162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
262306a36Sopenharmony_ci/* Copyright 2017-2019 NXP */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <asm/unaligned.h>
562306a36Sopenharmony_ci#include <linux/mdio.h>
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include <linux/fsl/enetc_mdio.h>
862306a36Sopenharmony_ci#include <linux/of_platform.h>
962306a36Sopenharmony_ci#include <linux/of_mdio.h>
1062306a36Sopenharmony_ci#include <linux/of_net.h>
1162306a36Sopenharmony_ci#include <linux/pcs-lynx.h>
1262306a36Sopenharmony_ci#include "enetc_ierb.h"
1362306a36Sopenharmony_ci#include "enetc_pf.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define ENETC_DRV_NAME_STR "ENETC PF driver"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic void enetc_pf_get_primary_mac_addr(struct enetc_hw *hw, int si, u8 *addr)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	u32 upper = __raw_readl(hw->port + ENETC_PSIPMAR0(si));
2062306a36Sopenharmony_ci	u16 lower = __raw_readw(hw->port + ENETC_PSIPMAR1(si));
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	put_unaligned_le32(upper, addr);
2362306a36Sopenharmony_ci	put_unaligned_le16(lower, addr + 4);
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic void enetc_pf_set_primary_mac_addr(struct enetc_hw *hw, int si,
2762306a36Sopenharmony_ci					  const u8 *addr)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	u32 upper = get_unaligned_le32(addr);
3062306a36Sopenharmony_ci	u16 lower = get_unaligned_le16(addr + 4);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	__raw_writel(upper, hw->port + ENETC_PSIPMAR0(si));
3362306a36Sopenharmony_ci	__raw_writew(lower, hw->port + ENETC_PSIPMAR1(si));
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
3962306a36Sopenharmony_ci	struct sockaddr *saddr = addr;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (!is_valid_ether_addr(saddr->sa_data))
4262306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	eth_hw_addr_set(ndev, saddr->sa_data);
4562306a36Sopenharmony_ci	enetc_pf_set_primary_mac_addr(&priv->si->hw, 0, saddr->sa_data);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	return 0;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic void enetc_set_vlan_promisc(struct enetc_hw *hw, char si_map)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	u32 val = enetc_port_rd(hw, ENETC_PSIPVMR);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	val &= ~ENETC_PSIPVMR_SET_VP(ENETC_VLAN_PROMISC_MAP_ALL);
5562306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIPVMR, ENETC_PSIPVMR_SET_VP(si_map) | val);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic void enetc_enable_si_vlan_promisc(struct enetc_pf *pf, int si_idx)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	pf->vlan_promisc_simap |= BIT(si_idx);
6162306a36Sopenharmony_ci	enetc_set_vlan_promisc(&pf->si->hw, pf->vlan_promisc_simap);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void enetc_disable_si_vlan_promisc(struct enetc_pf *pf, int si_idx)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	pf->vlan_promisc_simap &= ~BIT(si_idx);
6762306a36Sopenharmony_ci	enetc_set_vlan_promisc(&pf->si->hw, pf->vlan_promisc_simap);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void enetc_set_isol_vlan(struct enetc_hw *hw, int si, u16 vlan, u8 qos)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	u32 val = 0;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (vlan)
7562306a36Sopenharmony_ci		val = ENETC_PSIVLAN_EN | ENETC_PSIVLAN_SET_QOS(qos) | vlan;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIVLANR(si), val);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int enetc_mac_addr_hash_idx(const u8 *addr)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	u64 fold = __swab64(ether_addr_to_u64(addr)) >> 16;
8362306a36Sopenharmony_ci	u64 mask = 0;
8462306a36Sopenharmony_ci	int res = 0;
8562306a36Sopenharmony_ci	int i;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
8862306a36Sopenharmony_ci		mask |= BIT_ULL(i * 6);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
9162306a36Sopenharmony_ci		res |= (hweight64(fold & (mask << i)) & 0x1) << i;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return res;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void enetc_reset_mac_addr_filter(struct enetc_mac_filter *filter)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	filter->mac_addr_cnt = 0;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	bitmap_zero(filter->mac_hash_table,
10162306a36Sopenharmony_ci		    ENETC_MADDR_HASH_TBL_SZ);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter,
10562306a36Sopenharmony_ci					 const unsigned char *addr)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	/* add exact match addr */
10862306a36Sopenharmony_ci	ether_addr_copy(filter->mac_addr, addr);
10962306a36Sopenharmony_ci	filter->mac_addr_cnt++;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic void enetc_add_mac_addr_ht_filter(struct enetc_mac_filter *filter,
11362306a36Sopenharmony_ci					 const unsigned char *addr)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	int idx = enetc_mac_addr_hash_idx(addr);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* add hash table entry */
11862306a36Sopenharmony_ci	__set_bit(idx, filter->mac_hash_table);
11962306a36Sopenharmony_ci	filter->mac_addr_cnt++;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic void enetc_clear_mac_ht_flt(struct enetc_si *si, int si_idx, int type)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	bool err = si->errata & ENETC_ERR_UCMCSWP;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (type == UC) {
12762306a36Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err), 0);
12862306a36Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx), 0);
12962306a36Sopenharmony_ci	} else { /* MC */
13062306a36Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err), 0);
13162306a36Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx), 0);
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type,
13662306a36Sopenharmony_ci				 unsigned long hash)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	bool err = si->errata & ENETC_ERR_UCMCSWP;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	if (type == UC) {
14162306a36Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err),
14262306a36Sopenharmony_ci			      lower_32_bits(hash));
14362306a36Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx),
14462306a36Sopenharmony_ci			      upper_32_bits(hash));
14562306a36Sopenharmony_ci	} else { /* MC */
14662306a36Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err),
14762306a36Sopenharmony_ci			      lower_32_bits(hash));
14862306a36Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx),
14962306a36Sopenharmony_ci			      upper_32_bits(hash));
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic void enetc_sync_mac_filters(struct enetc_pf *pf)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct enetc_mac_filter *f = pf->mac_filter;
15662306a36Sopenharmony_ci	struct enetc_si *si = pf->si;
15762306a36Sopenharmony_ci	int i, pos;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	pos = EMETC_MAC_ADDR_FILT_RES;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	for (i = 0; i < MADDR_TYPE; i++, f++) {
16262306a36Sopenharmony_ci		bool em = (f->mac_addr_cnt == 1) && (i == UC);
16362306a36Sopenharmony_ci		bool clear = !f->mac_addr_cnt;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		if (clear) {
16662306a36Sopenharmony_ci			if (i == UC)
16762306a36Sopenharmony_ci				enetc_clear_mac_flt_entry(si, pos);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci			enetc_clear_mac_ht_flt(si, 0, i);
17062306a36Sopenharmony_ci			continue;
17162306a36Sopenharmony_ci		}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		/* exact match filter */
17462306a36Sopenharmony_ci		if (em) {
17562306a36Sopenharmony_ci			int err;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci			enetc_clear_mac_ht_flt(si, 0, UC);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci			err = enetc_set_mac_flt_entry(si, pos, f->mac_addr,
18062306a36Sopenharmony_ci						      BIT(0));
18162306a36Sopenharmony_ci			if (!err)
18262306a36Sopenharmony_ci				continue;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci			/* fallback to HT filtering */
18562306a36Sopenharmony_ci			dev_warn(&si->pdev->dev, "fallback to HT filt (%d)\n",
18662306a36Sopenharmony_ci				 err);
18762306a36Sopenharmony_ci		}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		/* hash table filter, clear EM filter for UC entries */
19062306a36Sopenharmony_ci		if (i == UC)
19162306a36Sopenharmony_ci			enetc_clear_mac_flt_entry(si, pos);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		enetc_set_mac_ht_flt(si, 0, i, *f->mac_hash_table);
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic void enetc_pf_set_rx_mode(struct net_device *ndev)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
20062306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
20162306a36Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
20262306a36Sopenharmony_ci	bool uprom = false, mprom = false;
20362306a36Sopenharmony_ci	struct enetc_mac_filter *filter;
20462306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
20562306a36Sopenharmony_ci	u32 psipmr = 0;
20662306a36Sopenharmony_ci	bool em;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	if (ndev->flags & IFF_PROMISC) {
20962306a36Sopenharmony_ci		/* enable promisc mode for SI0 (PF) */
21062306a36Sopenharmony_ci		psipmr = ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0);
21162306a36Sopenharmony_ci		uprom = true;
21262306a36Sopenharmony_ci		mprom = true;
21362306a36Sopenharmony_ci	} else if (ndev->flags & IFF_ALLMULTI) {
21462306a36Sopenharmony_ci		/* enable multi cast promisc mode for SI0 (PF) */
21562306a36Sopenharmony_ci		psipmr = ENETC_PSIPMR_SET_MP(0);
21662306a36Sopenharmony_ci		mprom = true;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* first 2 filter entries belong to PF */
22062306a36Sopenharmony_ci	if (!uprom) {
22162306a36Sopenharmony_ci		/* Update unicast filters */
22262306a36Sopenharmony_ci		filter = &pf->mac_filter[UC];
22362306a36Sopenharmony_ci		enetc_reset_mac_addr_filter(filter);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		em = (netdev_uc_count(ndev) == 1);
22662306a36Sopenharmony_ci		netdev_for_each_uc_addr(ha, ndev) {
22762306a36Sopenharmony_ci			if (em) {
22862306a36Sopenharmony_ci				enetc_add_mac_addr_em_filter(filter, ha->addr);
22962306a36Sopenharmony_ci				break;
23062306a36Sopenharmony_ci			}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci			enetc_add_mac_addr_ht_filter(filter, ha->addr);
23362306a36Sopenharmony_ci		}
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (!mprom) {
23762306a36Sopenharmony_ci		/* Update multicast filters */
23862306a36Sopenharmony_ci		filter = &pf->mac_filter[MC];
23962306a36Sopenharmony_ci		enetc_reset_mac_addr_filter(filter);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci		netdev_for_each_mc_addr(ha, ndev) {
24262306a36Sopenharmony_ci			if (!is_multicast_ether_addr(ha->addr))
24362306a36Sopenharmony_ci				continue;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci			enetc_add_mac_addr_ht_filter(filter, ha->addr);
24662306a36Sopenharmony_ci		}
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (!uprom || !mprom)
25062306a36Sopenharmony_ci		/* update PF entries */
25162306a36Sopenharmony_ci		enetc_sync_mac_filters(pf);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	psipmr |= enetc_port_rd(hw, ENETC_PSIPMR) &
25462306a36Sopenharmony_ci		  ~(ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0));
25562306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIPMR, psipmr);
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic void enetc_set_vlan_ht_filter(struct enetc_hw *hw, int si_idx,
25962306a36Sopenharmony_ci				     unsigned long hash)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIVHFR0(si_idx), lower_32_bits(hash));
26262306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIVHFR1(si_idx), upper_32_bits(hash));
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic int enetc_vid_hash_idx(unsigned int vid)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	int res = 0;
26862306a36Sopenharmony_ci	int i;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
27162306a36Sopenharmony_ci		res |= (hweight8(vid & (BIT(i) | BIT(i + 6))) & 0x1) << i;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return res;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic void enetc_sync_vlan_ht_filter(struct enetc_pf *pf, bool rehash)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	int i;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (rehash) {
28162306a36Sopenharmony_ci		bitmap_zero(pf->vlan_ht_filter, ENETC_VLAN_HT_SIZE);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		for_each_set_bit(i, pf->active_vlans, VLAN_N_VID) {
28462306a36Sopenharmony_ci			int hidx = enetc_vid_hash_idx(i);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci			__set_bit(hidx, pf->vlan_ht_filter);
28762306a36Sopenharmony_ci		}
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	enetc_set_vlan_ht_filter(&pf->si->hw, 0, *pf->vlan_ht_filter);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
29662306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
29762306a36Sopenharmony_ci	int idx;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	__set_bit(vid, pf->active_vlans);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	idx = enetc_vid_hash_idx(vid);
30262306a36Sopenharmony_ci	if (!__test_and_set_bit(idx, pf->vlan_ht_filter))
30362306a36Sopenharmony_ci		enetc_sync_vlan_ht_filter(pf, false);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	return 0;
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
31162306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	__clear_bit(vid, pf->active_vlans);
31462306a36Sopenharmony_ci	enetc_sync_vlan_ht_filter(pf, true);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return 0;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic void enetc_set_loopback(struct net_device *ndev, bool en)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
32262306a36Sopenharmony_ci	struct enetc_si *si = priv->si;
32362306a36Sopenharmony_ci	u32 reg;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	reg = enetc_port_mac_rd(si, ENETC_PM0_IF_MODE);
32662306a36Sopenharmony_ci	if (reg & ENETC_PM0_IFM_RG) {
32762306a36Sopenharmony_ci		/* RGMII mode */
32862306a36Sopenharmony_ci		reg = (reg & ~ENETC_PM0_IFM_RLP) |
32962306a36Sopenharmony_ci		      (en ? ENETC_PM0_IFM_RLP : 0);
33062306a36Sopenharmony_ci		enetc_port_mac_wr(si, ENETC_PM0_IF_MODE, reg);
33162306a36Sopenharmony_ci	} else {
33262306a36Sopenharmony_ci		/* assume SGMII mode */
33362306a36Sopenharmony_ci		reg = enetc_port_mac_rd(si, ENETC_PM0_CMD_CFG);
33462306a36Sopenharmony_ci		reg = (reg & ~ENETC_PM0_CMD_XGLP) |
33562306a36Sopenharmony_ci		      (en ? ENETC_PM0_CMD_XGLP : 0);
33662306a36Sopenharmony_ci		reg = (reg & ~ENETC_PM0_CMD_PHY_TX_EN) |
33762306a36Sopenharmony_ci		      (en ? ENETC_PM0_CMD_PHY_TX_EN : 0);
33862306a36Sopenharmony_ci		enetc_port_mac_wr(si, ENETC_PM0_CMD_CFG, reg);
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
34562306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
34662306a36Sopenharmony_ci	struct enetc_vf_state *vf_state;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (vf >= pf->total_vfs)
34962306a36Sopenharmony_ci		return -EINVAL;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (!is_valid_ether_addr(mac))
35262306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	vf_state = &pf->vf_state[vf];
35562306a36Sopenharmony_ci	vf_state->flags |= ENETC_VF_FLAG_PF_SET_MAC;
35662306a36Sopenharmony_ci	enetc_pf_set_primary_mac_addr(&priv->si->hw, vf + 1, mac);
35762306a36Sopenharmony_ci	return 0;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic int enetc_pf_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,
36162306a36Sopenharmony_ci				u8 qos, __be16 proto)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
36462306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (priv->si->errata & ENETC_ERR_VLAN_ISOL)
36762306a36Sopenharmony_ci		return -EOPNOTSUPP;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (vf >= pf->total_vfs)
37062306a36Sopenharmony_ci		return -EINVAL;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (proto != htons(ETH_P_8021Q))
37362306a36Sopenharmony_ci		/* only C-tags supported for now */
37462306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	enetc_set_isol_vlan(&priv->si->hw, vf + 1, vlan, qos);
37762306a36Sopenharmony_ci	return 0;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
38362306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
38462306a36Sopenharmony_ci	u32 cfgr;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (vf >= pf->total_vfs)
38762306a36Sopenharmony_ci		return -EINVAL;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	cfgr = enetc_port_rd(&priv->si->hw, ENETC_PSICFGR0(vf + 1));
39062306a36Sopenharmony_ci	cfgr = (cfgr & ~ENETC_PSICFGR0_ASE) | (en ? ENETC_PSICFGR0_ASE : 0);
39162306a36Sopenharmony_ci	enetc_port_wr(&priv->si->hw, ENETC_PSICFGR0(vf + 1), cfgr);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return 0;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf,
39762306a36Sopenharmony_ci				   int si)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct device *dev = &pf->si->pdev->dev;
40062306a36Sopenharmony_ci	struct enetc_hw *hw = &pf->si->hw;
40162306a36Sopenharmony_ci	u8 mac_addr[ETH_ALEN] = { 0 };
40262306a36Sopenharmony_ci	int err;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	/* (1) try to get the MAC address from the device tree */
40562306a36Sopenharmony_ci	if (np) {
40662306a36Sopenharmony_ci		err = of_get_mac_address(np, mac_addr);
40762306a36Sopenharmony_ci		if (err == -EPROBE_DEFER)
40862306a36Sopenharmony_ci			return err;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* (2) bootloader supplied MAC address */
41262306a36Sopenharmony_ci	if (is_zero_ether_addr(mac_addr))
41362306a36Sopenharmony_ci		enetc_pf_get_primary_mac_addr(hw, si, mac_addr);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* (3) choose a random one */
41662306a36Sopenharmony_ci	if (is_zero_ether_addr(mac_addr)) {
41762306a36Sopenharmony_ci		eth_random_addr(mac_addr);
41862306a36Sopenharmony_ci		dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
41962306a36Sopenharmony_ci			 si, mac_addr);
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	enetc_pf_set_primary_mac_addr(hw, si, mac_addr);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return 0;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic int enetc_setup_mac_addresses(struct device_node *np,
42862306a36Sopenharmony_ci				     struct enetc_pf *pf)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	int err, i;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	/* The PF might take its MAC from the device tree */
43362306a36Sopenharmony_ci	err = enetc_setup_mac_address(np, pf, 0);
43462306a36Sopenharmony_ci	if (err)
43562306a36Sopenharmony_ci		return err;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	for (i = 0; i < pf->total_vfs; i++) {
43862306a36Sopenharmony_ci		err = enetc_setup_mac_address(NULL, pf, i + 1);
43962306a36Sopenharmony_ci		if (err)
44062306a36Sopenharmony_ci			return err;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	return 0;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic void enetc_port_assign_rfs_entries(struct enetc_si *si)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(si);
44962306a36Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
45062306a36Sopenharmony_ci	int num_entries, vf_entries, i;
45162306a36Sopenharmony_ci	u32 val;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	/* split RFS entries between functions */
45462306a36Sopenharmony_ci	val = enetc_port_rd(hw, ENETC_PRFSCAPR);
45562306a36Sopenharmony_ci	num_entries = ENETC_PRFSCAPR_GET_NUM_RFS(val);
45662306a36Sopenharmony_ci	vf_entries = num_entries / (pf->total_vfs + 1);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	for (i = 0; i < pf->total_vfs; i++)
45962306a36Sopenharmony_ci		enetc_port_wr(hw, ENETC_PSIRFSCFGR(i + 1), vf_entries);
46062306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIRFSCFGR(0),
46162306a36Sopenharmony_ci		      num_entries - vf_entries * pf->total_vfs);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/* enable RFS on port */
46462306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PRFSMR, ENETC_PRFSMR_RFSE);
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic void enetc_port_si_configure(struct enetc_si *si)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(si);
47062306a36Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
47162306a36Sopenharmony_ci	int num_rings, i;
47262306a36Sopenharmony_ci	u32 val;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	val = enetc_port_rd(hw, ENETC_PCAPR0);
47562306a36Sopenharmony_ci	num_rings = min(ENETC_PCAPR0_RXBDR(val), ENETC_PCAPR0_TXBDR(val));
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	val = ENETC_PSICFGR0_SET_TXBDR(ENETC_PF_NUM_RINGS);
47862306a36Sopenharmony_ci	val |= ENETC_PSICFGR0_SET_RXBDR(ENETC_PF_NUM_RINGS);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (unlikely(num_rings < ENETC_PF_NUM_RINGS)) {
48162306a36Sopenharmony_ci		val = ENETC_PSICFGR0_SET_TXBDR(num_rings);
48262306a36Sopenharmony_ci		val |= ENETC_PSICFGR0_SET_RXBDR(num_rings);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		dev_warn(&si->pdev->dev, "Found %d rings, expected %d!\n",
48562306a36Sopenharmony_ci			 num_rings, ENETC_PF_NUM_RINGS);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		num_rings = 0;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* Add default one-time settings for SI0 (PF) */
49162306a36Sopenharmony_ci	val |= ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSICFGR0(0), val);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	if (num_rings)
49662306a36Sopenharmony_ci		num_rings -= ENETC_PF_NUM_RINGS;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/* Configure the SIs for each available VF */
49962306a36Sopenharmony_ci	val = ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
50062306a36Sopenharmony_ci	val |= ENETC_PSICFGR0_VTE | ENETC_PSICFGR0_SIVIE;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (num_rings) {
50362306a36Sopenharmony_ci		num_rings /= pf->total_vfs;
50462306a36Sopenharmony_ci		val |= ENETC_PSICFGR0_SET_TXBDR(num_rings);
50562306a36Sopenharmony_ci		val |= ENETC_PSICFGR0_SET_RXBDR(num_rings);
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	for (i = 0; i < pf->total_vfs; i++)
50962306a36Sopenharmony_ci		enetc_port_wr(hw, ENETC_PSICFGR0(i + 1), val);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* Port level VLAN settings */
51262306a36Sopenharmony_ci	val = ENETC_PVCLCTR_OVTPIDL(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
51362306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PVCLCTR, val);
51462306a36Sopenharmony_ci	/* use outer tag for VLAN filtering */
51562306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIVLANFMR, ENETC_PSIVLANFMR_VS);
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_civoid enetc_set_ptcmsdur(struct enetc_hw *hw, u32 *max_sdu)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	int tc;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	for (tc = 0; tc < 8; tc++) {
52362306a36Sopenharmony_ci		u32 val = ENETC_MAC_MAXFRM_SIZE;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		if (max_sdu[tc])
52662306a36Sopenharmony_ci			val = max_sdu[tc] + VLAN_ETH_HLEN;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci		enetc_port_wr(hw, ENETC_PTCMSDUR(tc), val);
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_civoid enetc_reset_ptcmsdur(struct enetc_hw *hw)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	int tc;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	for (tc = 0; tc < 8; tc++)
53762306a36Sopenharmony_ci		enetc_port_wr(hw, ENETC_PTCMSDUR(tc), ENETC_MAC_MAXFRM_SIZE);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic void enetc_configure_port_mac(struct enetc_si *si)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	enetc_port_mac_wr(si, ENETC_PM0_MAXFRM,
54562306a36Sopenharmony_ci			  ENETC_SET_MAXFRM(ENETC_RX_MAXFRM_SIZE));
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	enetc_reset_ptcmsdur(hw);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	enetc_port_mac_wr(si, ENETC_PM0_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN |
55062306a36Sopenharmony_ci			  ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/* On LS1028A, the MAC RX FIFO defaults to 2, which is too high
55362306a36Sopenharmony_ci	 * and may lead to RX lock-up under traffic. Set it to 1 instead,
55462306a36Sopenharmony_ci	 * as recommended by the hardware team.
55562306a36Sopenharmony_ci	 */
55662306a36Sopenharmony_ci	enetc_port_mac_wr(si, ENETC_PM0_RX_FIFO, ENETC_PM0_RX_FIFO_VAL);
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic void enetc_mac_config(struct enetc_si *si, phy_interface_t phy_mode)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	u32 val;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (phy_interface_mode_is_rgmii(phy_mode)) {
56462306a36Sopenharmony_ci		val = enetc_port_mac_rd(si, ENETC_PM0_IF_MODE);
56562306a36Sopenharmony_ci		val &= ~(ENETC_PM0_IFM_EN_AUTO | ENETC_PM0_IFM_IFMODE_MASK);
56662306a36Sopenharmony_ci		val |= ENETC_PM0_IFM_IFMODE_GMII | ENETC_PM0_IFM_RG;
56762306a36Sopenharmony_ci		enetc_port_mac_wr(si, ENETC_PM0_IF_MODE, val);
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if (phy_mode == PHY_INTERFACE_MODE_USXGMII) {
57162306a36Sopenharmony_ci		val = ENETC_PM0_IFM_FULL_DPX | ENETC_PM0_IFM_IFMODE_XGMII;
57262306a36Sopenharmony_ci		enetc_port_mac_wr(si, ENETC_PM0_IF_MODE, val);
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic void enetc_mac_enable(struct enetc_si *si, bool en)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	u32 val = enetc_port_mac_rd(si, ENETC_PM0_CMD_CFG);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	val &= ~(ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
58162306a36Sopenharmony_ci	val |= en ? (ENETC_PM0_TX_EN | ENETC_PM0_RX_EN) : 0;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	enetc_port_mac_wr(si, ENETC_PM0_CMD_CFG, val);
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic void enetc_configure_port(struct enetc_pf *pf)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	u8 hash_key[ENETC_RSSHASH_KEY_SIZE];
58962306a36Sopenharmony_ci	struct enetc_hw *hw = &pf->si->hw;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	enetc_configure_port_mac(pf->si);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	enetc_port_si_configure(pf->si);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/* set up hash key */
59662306a36Sopenharmony_ci	get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE);
59762306a36Sopenharmony_ci	enetc_set_rss_key(hw, hash_key);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* split up RFS entries */
60062306a36Sopenharmony_ci	enetc_port_assign_rfs_entries(pf->si);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/* enforce VLAN promisc mode for all SIs */
60362306a36Sopenharmony_ci	pf->vlan_promisc_simap = ENETC_VLAN_PROMISC_MAP_ALL;
60462306a36Sopenharmony_ci	enetc_set_vlan_promisc(hw, pf->vlan_promisc_simap);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIPMR, 0);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* enable port */
60962306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PMR, ENETC_PMR_EN);
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci/* Messaging */
61362306a36Sopenharmony_cistatic u16 enetc_msg_pf_set_vf_primary_mac_addr(struct enetc_pf *pf,
61462306a36Sopenharmony_ci						int vf_id)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
61762306a36Sopenharmony_ci	struct enetc_msg_swbd *msg = &pf->rxmsg[vf_id];
61862306a36Sopenharmony_ci	struct enetc_msg_cmd_set_primary_mac *cmd;
61962306a36Sopenharmony_ci	struct device *dev = &pf->si->pdev->dev;
62062306a36Sopenharmony_ci	u16 cmd_id;
62162306a36Sopenharmony_ci	char *addr;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	cmd = (struct enetc_msg_cmd_set_primary_mac *)msg->vaddr;
62462306a36Sopenharmony_ci	cmd_id = cmd->header.id;
62562306a36Sopenharmony_ci	if (cmd_id != ENETC_MSG_CMD_MNG_ADD)
62662306a36Sopenharmony_ci		return ENETC_MSG_CMD_STATUS_FAIL;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	addr = cmd->mac.sa_data;
62962306a36Sopenharmony_ci	if (vf_state->flags & ENETC_VF_FLAG_PF_SET_MAC)
63062306a36Sopenharmony_ci		dev_warn(dev, "Attempt to override PF set mac addr for VF%d\n",
63162306a36Sopenharmony_ci			 vf_id);
63262306a36Sopenharmony_ci	else
63362306a36Sopenharmony_ci		enetc_pf_set_primary_mac_addr(&pf->si->hw, vf_id + 1, addr);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	return ENETC_MSG_CMD_STATUS_OK;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_civoid enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id, u16 *status)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct enetc_msg_swbd *msg = &pf->rxmsg[vf_id];
64162306a36Sopenharmony_ci	struct device *dev = &pf->si->pdev->dev;
64262306a36Sopenharmony_ci	struct enetc_msg_cmd_header *cmd_hdr;
64362306a36Sopenharmony_ci	u16 cmd_type;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	*status = ENETC_MSG_CMD_STATUS_OK;
64662306a36Sopenharmony_ci	cmd_hdr = (struct enetc_msg_cmd_header *)msg->vaddr;
64762306a36Sopenharmony_ci	cmd_type = cmd_hdr->type;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	switch (cmd_type) {
65062306a36Sopenharmony_ci	case ENETC_MSG_CMD_MNG_MAC:
65162306a36Sopenharmony_ci		*status = enetc_msg_pf_set_vf_primary_mac_addr(pf, vf_id);
65262306a36Sopenharmony_ci		break;
65362306a36Sopenharmony_ci	default:
65462306a36Sopenharmony_ci		dev_err(dev, "command not supported (cmd_type: 0x%x)\n",
65562306a36Sopenharmony_ci			cmd_type);
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
66062306a36Sopenharmony_cistatic int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	struct enetc_si *si = pci_get_drvdata(pdev);
66362306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(si);
66462306a36Sopenharmony_ci	int err;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (!num_vfs) {
66762306a36Sopenharmony_ci		enetc_msg_psi_free(pf);
66862306a36Sopenharmony_ci		kfree(pf->vf_state);
66962306a36Sopenharmony_ci		pf->num_vfs = 0;
67062306a36Sopenharmony_ci		pci_disable_sriov(pdev);
67162306a36Sopenharmony_ci	} else {
67262306a36Sopenharmony_ci		pf->num_vfs = num_vfs;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state),
67562306a36Sopenharmony_ci				       GFP_KERNEL);
67662306a36Sopenharmony_ci		if (!pf->vf_state) {
67762306a36Sopenharmony_ci			pf->num_vfs = 0;
67862306a36Sopenharmony_ci			return -ENOMEM;
67962306a36Sopenharmony_ci		}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci		err = enetc_msg_psi_init(pf);
68262306a36Sopenharmony_ci		if (err) {
68362306a36Sopenharmony_ci			dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err);
68462306a36Sopenharmony_ci			goto err_msg_psi;
68562306a36Sopenharmony_ci		}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci		err = pci_enable_sriov(pdev, num_vfs);
68862306a36Sopenharmony_ci		if (err) {
68962306a36Sopenharmony_ci			dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err);
69062306a36Sopenharmony_ci			goto err_en_sriov;
69162306a36Sopenharmony_ci		}
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	return num_vfs;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cierr_en_sriov:
69762306a36Sopenharmony_ci	enetc_msg_psi_free(pf);
69862306a36Sopenharmony_cierr_msg_psi:
69962306a36Sopenharmony_ci	kfree(pf->vf_state);
70062306a36Sopenharmony_ci	pf->num_vfs = 0;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	return err;
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_ci#else
70562306a36Sopenharmony_ci#define enetc_sriov_configure(pdev, num_vfs)	(void)0
70662306a36Sopenharmony_ci#endif
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic int enetc_pf_set_features(struct net_device *ndev,
70962306a36Sopenharmony_ci				 netdev_features_t features)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	netdev_features_t changed = ndev->features ^ features;
71262306a36Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
71362306a36Sopenharmony_ci	int err;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (changed & NETIF_F_HW_TC) {
71662306a36Sopenharmony_ci		err = enetc_set_psfp(ndev, !!(features & NETIF_F_HW_TC));
71762306a36Sopenharmony_ci		if (err)
71862306a36Sopenharmony_ci			return err;
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
72262306a36Sopenharmony_ci		struct enetc_pf *pf = enetc_si_priv(priv->si);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci		if (!!(features & NETIF_F_HW_VLAN_CTAG_FILTER))
72562306a36Sopenharmony_ci			enetc_disable_si_vlan_promisc(pf, 0);
72662306a36Sopenharmony_ci		else
72762306a36Sopenharmony_ci			enetc_enable_si_vlan_promisc(pf, 0);
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (changed & NETIF_F_LOOPBACK)
73162306a36Sopenharmony_ci		enetc_set_loopback(ndev, !!(features & NETIF_F_LOOPBACK));
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	enetc_set_features(ndev, features);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	return 0;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic int enetc_pf_setup_tc(struct net_device *ndev, enum tc_setup_type type,
73962306a36Sopenharmony_ci			     void *type_data)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	switch (type) {
74262306a36Sopenharmony_ci	case TC_QUERY_CAPS:
74362306a36Sopenharmony_ci		return enetc_qos_query_caps(ndev, type_data);
74462306a36Sopenharmony_ci	case TC_SETUP_QDISC_MQPRIO:
74562306a36Sopenharmony_ci		return enetc_setup_tc_mqprio(ndev, type_data);
74662306a36Sopenharmony_ci	case TC_SETUP_QDISC_TAPRIO:
74762306a36Sopenharmony_ci		return enetc_setup_tc_taprio(ndev, type_data);
74862306a36Sopenharmony_ci	case TC_SETUP_QDISC_CBS:
74962306a36Sopenharmony_ci		return enetc_setup_tc_cbs(ndev, type_data);
75062306a36Sopenharmony_ci	case TC_SETUP_QDISC_ETF:
75162306a36Sopenharmony_ci		return enetc_setup_tc_txtime(ndev, type_data);
75262306a36Sopenharmony_ci	case TC_SETUP_BLOCK:
75362306a36Sopenharmony_ci		return enetc_setup_tc_psfp(ndev, type_data);
75462306a36Sopenharmony_ci	default:
75562306a36Sopenharmony_ci		return -EOPNOTSUPP;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_cistatic const struct net_device_ops enetc_ndev_ops = {
76062306a36Sopenharmony_ci	.ndo_open		= enetc_open,
76162306a36Sopenharmony_ci	.ndo_stop		= enetc_close,
76262306a36Sopenharmony_ci	.ndo_start_xmit		= enetc_xmit,
76362306a36Sopenharmony_ci	.ndo_get_stats		= enetc_get_stats,
76462306a36Sopenharmony_ci	.ndo_set_mac_address	= enetc_pf_set_mac_addr,
76562306a36Sopenharmony_ci	.ndo_set_rx_mode	= enetc_pf_set_rx_mode,
76662306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid	= enetc_vlan_rx_add_vid,
76762306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= enetc_vlan_rx_del_vid,
76862306a36Sopenharmony_ci	.ndo_set_vf_mac		= enetc_pf_set_vf_mac,
76962306a36Sopenharmony_ci	.ndo_set_vf_vlan	= enetc_pf_set_vf_vlan,
77062306a36Sopenharmony_ci	.ndo_set_vf_spoofchk	= enetc_pf_set_vf_spoofchk,
77162306a36Sopenharmony_ci	.ndo_set_features	= enetc_pf_set_features,
77262306a36Sopenharmony_ci	.ndo_eth_ioctl		= enetc_ioctl,
77362306a36Sopenharmony_ci	.ndo_setup_tc		= enetc_pf_setup_tc,
77462306a36Sopenharmony_ci	.ndo_bpf		= enetc_setup_bpf,
77562306a36Sopenharmony_ci	.ndo_xdp_xmit		= enetc_xdp_xmit,
77662306a36Sopenharmony_ci};
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
77962306a36Sopenharmony_ci				  const struct net_device_ops *ndev_ops)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	SET_NETDEV_DEV(ndev, &si->pdev->dev);
78462306a36Sopenharmony_ci	priv->ndev = ndev;
78562306a36Sopenharmony_ci	priv->si = si;
78662306a36Sopenharmony_ci	priv->dev = &si->pdev->dev;
78762306a36Sopenharmony_ci	si->ndev = ndev;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
79062306a36Sopenharmony_ci	ndev->netdev_ops = ndev_ops;
79162306a36Sopenharmony_ci	enetc_set_ethtool_ops(ndev);
79262306a36Sopenharmony_ci	ndev->watchdog_timeo = 5 * HZ;
79362306a36Sopenharmony_ci	ndev->max_mtu = ENETC_MAX_MTU;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
79662306a36Sopenharmony_ci			    NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
79762306a36Sopenharmony_ci			    NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK |
79862306a36Sopenharmony_ci			    NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
79962306a36Sopenharmony_ci	ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM |
80062306a36Sopenharmony_ci			 NETIF_F_HW_VLAN_CTAG_TX |
80162306a36Sopenharmony_ci			 NETIF_F_HW_VLAN_CTAG_RX |
80262306a36Sopenharmony_ci			 NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
80362306a36Sopenharmony_ci	ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |
80462306a36Sopenharmony_ci			      NETIF_F_TSO | NETIF_F_TSO6;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (si->num_rss)
80762306a36Sopenharmony_ci		ndev->hw_features |= NETIF_F_RXHASH;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	ndev->priv_flags |= IFF_UNICAST_FLT;
81062306a36Sopenharmony_ci	ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
81162306a36Sopenharmony_ci			     NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG |
81262306a36Sopenharmony_ci			     NETDEV_XDP_ACT_NDO_XMIT_SG;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) {
81562306a36Sopenharmony_ci		priv->active_offloads |= ENETC_F_QCI;
81662306a36Sopenharmony_ci		ndev->features |= NETIF_F_HW_TC;
81762306a36Sopenharmony_ci		ndev->hw_features |= NETIF_F_HW_TC;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* pick up primary MAC address from SI */
82162306a36Sopenharmony_ci	enetc_load_primary_mac_addr(&si->hw, ndev);
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_cistatic int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	struct device *dev = &pf->si->pdev->dev;
82762306a36Sopenharmony_ci	struct enetc_mdio_priv *mdio_priv;
82862306a36Sopenharmony_ci	struct mii_bus *bus;
82962306a36Sopenharmony_ci	int err;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
83262306a36Sopenharmony_ci	if (!bus)
83362306a36Sopenharmony_ci		return -ENOMEM;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	bus->name = "Freescale ENETC MDIO Bus";
83662306a36Sopenharmony_ci	bus->read = enetc_mdio_read_c22;
83762306a36Sopenharmony_ci	bus->write = enetc_mdio_write_c22;
83862306a36Sopenharmony_ci	bus->read_c45 = enetc_mdio_read_c45;
83962306a36Sopenharmony_ci	bus->write_c45 = enetc_mdio_write_c45;
84062306a36Sopenharmony_ci	bus->parent = dev;
84162306a36Sopenharmony_ci	mdio_priv = bus->priv;
84262306a36Sopenharmony_ci	mdio_priv->hw = &pf->si->hw;
84362306a36Sopenharmony_ci	mdio_priv->mdio_base = ENETC_EMDIO_BASE;
84462306a36Sopenharmony_ci	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	err = of_mdiobus_register(bus, np);
84762306a36Sopenharmony_ci	if (err)
84862306a36Sopenharmony_ci		return dev_err_probe(dev, err, "cannot register MDIO bus\n");
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	pf->mdio = bus;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	return 0;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic void enetc_mdio_remove(struct enetc_pf *pf)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	if (pf->mdio)
85862306a36Sopenharmony_ci		mdiobus_unregister(pf->mdio);
85962306a36Sopenharmony_ci}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_cistatic int enetc_imdio_create(struct enetc_pf *pf)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	struct device *dev = &pf->si->pdev->dev;
86462306a36Sopenharmony_ci	struct enetc_mdio_priv *mdio_priv;
86562306a36Sopenharmony_ci	struct phylink_pcs *phylink_pcs;
86662306a36Sopenharmony_ci	struct mii_bus *bus;
86762306a36Sopenharmony_ci	int err;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
87062306a36Sopenharmony_ci	if (!bus)
87162306a36Sopenharmony_ci		return -ENOMEM;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	bus->name = "Freescale ENETC internal MDIO Bus";
87462306a36Sopenharmony_ci	bus->read = enetc_mdio_read_c22;
87562306a36Sopenharmony_ci	bus->write = enetc_mdio_write_c22;
87662306a36Sopenharmony_ci	bus->read_c45 = enetc_mdio_read_c45;
87762306a36Sopenharmony_ci	bus->write_c45 = enetc_mdio_write_c45;
87862306a36Sopenharmony_ci	bus->parent = dev;
87962306a36Sopenharmony_ci	bus->phy_mask = ~0;
88062306a36Sopenharmony_ci	mdio_priv = bus->priv;
88162306a36Sopenharmony_ci	mdio_priv->hw = &pf->si->hw;
88262306a36Sopenharmony_ci	mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
88362306a36Sopenharmony_ci	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	err = mdiobus_register(bus);
88662306a36Sopenharmony_ci	if (err) {
88762306a36Sopenharmony_ci		dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
88862306a36Sopenharmony_ci		goto free_mdio_bus;
88962306a36Sopenharmony_ci	}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	phylink_pcs = lynx_pcs_create_mdiodev(bus, 0);
89262306a36Sopenharmony_ci	if (IS_ERR(phylink_pcs)) {
89362306a36Sopenharmony_ci		err = PTR_ERR(phylink_pcs);
89462306a36Sopenharmony_ci		dev_err(dev, "cannot create lynx pcs (%d)\n", err);
89562306a36Sopenharmony_ci		goto unregister_mdiobus;
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	pf->imdio = bus;
89962306a36Sopenharmony_ci	pf->pcs = phylink_pcs;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	return 0;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ciunregister_mdiobus:
90462306a36Sopenharmony_ci	mdiobus_unregister(bus);
90562306a36Sopenharmony_cifree_mdio_bus:
90662306a36Sopenharmony_ci	mdiobus_free(bus);
90762306a36Sopenharmony_ci	return err;
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic void enetc_imdio_remove(struct enetc_pf *pf)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	if (pf->pcs)
91362306a36Sopenharmony_ci		lynx_pcs_destroy(pf->pcs);
91462306a36Sopenharmony_ci	if (pf->imdio) {
91562306a36Sopenharmony_ci		mdiobus_unregister(pf->imdio);
91662306a36Sopenharmony_ci		mdiobus_free(pf->imdio);
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_cistatic bool enetc_port_has_pcs(struct enetc_pf *pf)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
92362306a36Sopenharmony_ci		pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
92462306a36Sopenharmony_ci		pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
92562306a36Sopenharmony_ci}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_cistatic int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	struct device_node *mdio_np;
93062306a36Sopenharmony_ci	int err;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	mdio_np = of_get_child_by_name(node, "mdio");
93362306a36Sopenharmony_ci	if (mdio_np) {
93462306a36Sopenharmony_ci		err = enetc_mdio_probe(pf, mdio_np);
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci		of_node_put(mdio_np);
93762306a36Sopenharmony_ci		if (err)
93862306a36Sopenharmony_ci			return err;
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (enetc_port_has_pcs(pf)) {
94262306a36Sopenharmony_ci		err = enetc_imdio_create(pf);
94362306a36Sopenharmony_ci		if (err) {
94462306a36Sopenharmony_ci			enetc_mdio_remove(pf);
94562306a36Sopenharmony_ci			return err;
94662306a36Sopenharmony_ci		}
94762306a36Sopenharmony_ci	}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	return 0;
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_cistatic void enetc_mdiobus_destroy(struct enetc_pf *pf)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	enetc_mdio_remove(pf);
95562306a36Sopenharmony_ci	enetc_imdio_remove(pf);
95662306a36Sopenharmony_ci}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_cistatic struct phylink_pcs *
95962306a36Sopenharmony_cienetc_pl_mac_select_pcs(struct phylink_config *config, phy_interface_t iface)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	struct enetc_pf *pf = phylink_to_enetc_pf(config);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	return pf->pcs;
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic void enetc_pl_mac_config(struct phylink_config *config,
96762306a36Sopenharmony_ci				unsigned int mode,
96862306a36Sopenharmony_ci				const struct phylink_link_state *state)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	struct enetc_pf *pf = phylink_to_enetc_pf(config);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	enetc_mac_config(pf->si, state->interface);
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic void enetc_force_rgmii_mac(struct enetc_si *si, int speed, int duplex)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	u32 old_val, val;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	old_val = val = enetc_port_mac_rd(si, ENETC_PM0_IF_MODE);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	if (speed == SPEED_1000) {
98262306a36Sopenharmony_ci		val &= ~ENETC_PM0_IFM_SSP_MASK;
98362306a36Sopenharmony_ci		val |= ENETC_PM0_IFM_SSP_1000;
98462306a36Sopenharmony_ci	} else if (speed == SPEED_100) {
98562306a36Sopenharmony_ci		val &= ~ENETC_PM0_IFM_SSP_MASK;
98662306a36Sopenharmony_ci		val |= ENETC_PM0_IFM_SSP_100;
98762306a36Sopenharmony_ci	} else if (speed == SPEED_10) {
98862306a36Sopenharmony_ci		val &= ~ENETC_PM0_IFM_SSP_MASK;
98962306a36Sopenharmony_ci		val |= ENETC_PM0_IFM_SSP_10;
99062306a36Sopenharmony_ci	}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	if (duplex == DUPLEX_FULL)
99362306a36Sopenharmony_ci		val |= ENETC_PM0_IFM_FULL_DPX;
99462306a36Sopenharmony_ci	else
99562306a36Sopenharmony_ci		val &= ~ENETC_PM0_IFM_FULL_DPX;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	if (val == old_val)
99862306a36Sopenharmony_ci		return;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	enetc_port_mac_wr(si, ENETC_PM0_IF_MODE, val);
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic void enetc_pl_mac_link_up(struct phylink_config *config,
100462306a36Sopenharmony_ci				 struct phy_device *phy, unsigned int mode,
100562306a36Sopenharmony_ci				 phy_interface_t interface, int speed,
100662306a36Sopenharmony_ci				 int duplex, bool tx_pause, bool rx_pause)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	struct enetc_pf *pf = phylink_to_enetc_pf(config);
100962306a36Sopenharmony_ci	u32 pause_off_thresh = 0, pause_on_thresh = 0;
101062306a36Sopenharmony_ci	u32 init_quanta = 0, refresh_quanta = 0;
101162306a36Sopenharmony_ci	struct enetc_hw *hw = &pf->si->hw;
101262306a36Sopenharmony_ci	struct enetc_si *si = pf->si;
101362306a36Sopenharmony_ci	struct enetc_ndev_priv *priv;
101462306a36Sopenharmony_ci	u32 rbmr, cmd_cfg;
101562306a36Sopenharmony_ci	int idx;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	priv = netdev_priv(pf->si->ndev);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	if (pf->si->hw_features & ENETC_SI_F_QBV)
102062306a36Sopenharmony_ci		enetc_sched_speed_set(priv, speed);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	if (!phylink_autoneg_inband(mode) &&
102362306a36Sopenharmony_ci	    phy_interface_mode_is_rgmii(interface))
102462306a36Sopenharmony_ci		enetc_force_rgmii_mac(si, speed, duplex);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	/* Flow control */
102762306a36Sopenharmony_ci	for (idx = 0; idx < priv->num_rx_rings; idx++) {
102862306a36Sopenharmony_ci		rbmr = enetc_rxbdr_rd(hw, idx, ENETC_RBMR);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci		if (tx_pause)
103162306a36Sopenharmony_ci			rbmr |= ENETC_RBMR_CM;
103262306a36Sopenharmony_ci		else
103362306a36Sopenharmony_ci			rbmr &= ~ENETC_RBMR_CM;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci		enetc_rxbdr_wr(hw, idx, ENETC_RBMR, rbmr);
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	if (tx_pause) {
103962306a36Sopenharmony_ci		/* When the port first enters congestion, send a PAUSE request
104062306a36Sopenharmony_ci		 * with the maximum number of quanta. When the port exits
104162306a36Sopenharmony_ci		 * congestion, it will automatically send a PAUSE frame with
104262306a36Sopenharmony_ci		 * zero quanta.
104362306a36Sopenharmony_ci		 */
104462306a36Sopenharmony_ci		init_quanta = 0xffff;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci		/* Also, set up the refresh timer to send follow-up PAUSE
104762306a36Sopenharmony_ci		 * frames at half the quanta value, in case the congestion
104862306a36Sopenharmony_ci		 * condition persists.
104962306a36Sopenharmony_ci		 */
105062306a36Sopenharmony_ci		refresh_quanta = 0xffff / 2;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci		/* Start emitting PAUSE frames when 3 large frames (or more
105362306a36Sopenharmony_ci		 * smaller frames) have accumulated in the FIFO waiting to be
105462306a36Sopenharmony_ci		 * DMAed to the RX ring.
105562306a36Sopenharmony_ci		 */
105662306a36Sopenharmony_ci		pause_on_thresh = 3 * ENETC_MAC_MAXFRM_SIZE;
105762306a36Sopenharmony_ci		pause_off_thresh = 1 * ENETC_MAC_MAXFRM_SIZE;
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	enetc_port_mac_wr(si, ENETC_PM0_PAUSE_QUANTA, init_quanta);
106162306a36Sopenharmony_ci	enetc_port_mac_wr(si, ENETC_PM0_PAUSE_THRESH, refresh_quanta);
106262306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PPAUONTR, pause_on_thresh);
106362306a36Sopenharmony_ci	enetc_port_wr(hw, ENETC_PPAUOFFTR, pause_off_thresh);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	cmd_cfg = enetc_port_mac_rd(si, ENETC_PM0_CMD_CFG);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	if (rx_pause)
106862306a36Sopenharmony_ci		cmd_cfg &= ~ENETC_PM0_PAUSE_IGN;
106962306a36Sopenharmony_ci	else
107062306a36Sopenharmony_ci		cmd_cfg |= ENETC_PM0_PAUSE_IGN;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	enetc_port_mac_wr(si, ENETC_PM0_CMD_CFG, cmd_cfg);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	enetc_mac_enable(si, true);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	if (si->hw_features & ENETC_SI_F_QBU)
107762306a36Sopenharmony_ci		enetc_mm_link_state_update(priv, true);
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic void enetc_pl_mac_link_down(struct phylink_config *config,
108162306a36Sopenharmony_ci				   unsigned int mode,
108262306a36Sopenharmony_ci				   phy_interface_t interface)
108362306a36Sopenharmony_ci{
108462306a36Sopenharmony_ci	struct enetc_pf *pf = phylink_to_enetc_pf(config);
108562306a36Sopenharmony_ci	struct enetc_si *si = pf->si;
108662306a36Sopenharmony_ci	struct enetc_ndev_priv *priv;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	priv = netdev_priv(si->ndev);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (si->hw_features & ENETC_SI_F_QBU)
109162306a36Sopenharmony_ci		enetc_mm_link_state_update(priv, false);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	enetc_mac_enable(si, false);
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cistatic const struct phylink_mac_ops enetc_mac_phylink_ops = {
109762306a36Sopenharmony_ci	.mac_select_pcs = enetc_pl_mac_select_pcs,
109862306a36Sopenharmony_ci	.mac_config = enetc_pl_mac_config,
109962306a36Sopenharmony_ci	.mac_link_up = enetc_pl_mac_link_up,
110062306a36Sopenharmony_ci	.mac_link_down = enetc_pl_mac_link_down,
110162306a36Sopenharmony_ci};
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic int enetc_phylink_create(struct enetc_ndev_priv *priv,
110462306a36Sopenharmony_ci				struct device_node *node)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
110762306a36Sopenharmony_ci	struct phylink *phylink;
110862306a36Sopenharmony_ci	int err;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	pf->phylink_config.dev = &priv->ndev->dev;
111162306a36Sopenharmony_ci	pf->phylink_config.type = PHYLINK_NETDEV;
111262306a36Sopenharmony_ci	pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
111362306a36Sopenharmony_ci		MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	__set_bit(PHY_INTERFACE_MODE_INTERNAL,
111662306a36Sopenharmony_ci		  pf->phylink_config.supported_interfaces);
111762306a36Sopenharmony_ci	__set_bit(PHY_INTERFACE_MODE_SGMII,
111862306a36Sopenharmony_ci		  pf->phylink_config.supported_interfaces);
111962306a36Sopenharmony_ci	__set_bit(PHY_INTERFACE_MODE_2500BASEX,
112062306a36Sopenharmony_ci		  pf->phylink_config.supported_interfaces);
112162306a36Sopenharmony_ci	__set_bit(PHY_INTERFACE_MODE_USXGMII,
112262306a36Sopenharmony_ci		  pf->phylink_config.supported_interfaces);
112362306a36Sopenharmony_ci	phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
112662306a36Sopenharmony_ci				 pf->if_mode, &enetc_mac_phylink_ops);
112762306a36Sopenharmony_ci	if (IS_ERR(phylink)) {
112862306a36Sopenharmony_ci		err = PTR_ERR(phylink);
112962306a36Sopenharmony_ci		return err;
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	priv->phylink = phylink;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	return 0;
113562306a36Sopenharmony_ci}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_cistatic void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	phylink_destroy(priv->phylink);
114062306a36Sopenharmony_ci}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci/* Initialize the entire shared memory for the flow steering entries
114362306a36Sopenharmony_ci * of this port (PF + VFs)
114462306a36Sopenharmony_ci */
114562306a36Sopenharmony_cistatic int enetc_init_port_rfs_memory(struct enetc_si *si)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	struct enetc_cmd_rfse rfse = {0};
114862306a36Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
114962306a36Sopenharmony_ci	int num_rfs, i, err = 0;
115062306a36Sopenharmony_ci	u32 val;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	val = enetc_port_rd(hw, ENETC_PRFSCAPR);
115362306a36Sopenharmony_ci	num_rfs = ENETC_PRFSCAPR_GET_NUM_RFS(val);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	for (i = 0; i < num_rfs; i++) {
115662306a36Sopenharmony_ci		err = enetc_set_fs_entry(si, &rfse, i);
115762306a36Sopenharmony_ci		if (err)
115862306a36Sopenharmony_ci			break;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	return err;
116262306a36Sopenharmony_ci}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_cistatic int enetc_init_port_rss_memory(struct enetc_si *si)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
116762306a36Sopenharmony_ci	int num_rss, err;
116862306a36Sopenharmony_ci	int *rss_table;
116962306a36Sopenharmony_ci	u32 val;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	val = enetc_port_rd(hw, ENETC_PRSSCAPR);
117262306a36Sopenharmony_ci	num_rss = ENETC_PRSSCAPR_GET_NUM_RSS(val);
117362306a36Sopenharmony_ci	if (!num_rss)
117462306a36Sopenharmony_ci		return 0;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	rss_table = kcalloc(num_rss, sizeof(*rss_table), GFP_KERNEL);
117762306a36Sopenharmony_ci	if (!rss_table)
117862306a36Sopenharmony_ci		return -ENOMEM;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	err = enetc_set_rss_table(si, rss_table, num_rss);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	kfree(rss_table);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	return err;
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_cistatic int enetc_pf_register_with_ierb(struct pci_dev *pdev)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	struct platform_device *ierb_pdev;
119062306a36Sopenharmony_ci	struct device_node *ierb_node;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	ierb_node = of_find_compatible_node(NULL, NULL,
119362306a36Sopenharmony_ci					    "fsl,ls1028a-enetc-ierb");
119462306a36Sopenharmony_ci	if (!ierb_node || !of_device_is_available(ierb_node))
119562306a36Sopenharmony_ci		return -ENODEV;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	ierb_pdev = of_find_device_by_node(ierb_node);
119862306a36Sopenharmony_ci	of_node_put(ierb_node);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	if (!ierb_pdev)
120162306a36Sopenharmony_ci		return -EPROBE_DEFER;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	return enetc_ierb_register_pf(ierb_pdev, pdev);
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistatic struct enetc_si *enetc_psi_create(struct pci_dev *pdev)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	struct enetc_si *si;
120962306a36Sopenharmony_ci	int err;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(struct enetc_pf));
121262306a36Sopenharmony_ci	if (err) {
121362306a36Sopenharmony_ci		dev_err_probe(&pdev->dev, err, "PCI probing failed\n");
121462306a36Sopenharmony_ci		goto out;
121562306a36Sopenharmony_ci	}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	si = pci_get_drvdata(pdev);
121862306a36Sopenharmony_ci	if (!si->hw.port || !si->hw.global) {
121962306a36Sopenharmony_ci		err = -ENODEV;
122062306a36Sopenharmony_ci		dev_err(&pdev->dev, "could not map PF space, probing a VF?\n");
122162306a36Sopenharmony_ci		goto out_pci_remove;
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	err = enetc_setup_cbdr(&pdev->dev, &si->hw, ENETC_CBDR_DEFAULT_SIZE,
122562306a36Sopenharmony_ci			       &si->cbd_ring);
122662306a36Sopenharmony_ci	if (err)
122762306a36Sopenharmony_ci		goto out_pci_remove;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	err = enetc_init_port_rfs_memory(si);
123062306a36Sopenharmony_ci	if (err) {
123162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to initialize RFS memory\n");
123262306a36Sopenharmony_ci		goto out_teardown_cbdr;
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	err = enetc_init_port_rss_memory(si);
123662306a36Sopenharmony_ci	if (err) {
123762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to initialize RSS memory\n");
123862306a36Sopenharmony_ci		goto out_teardown_cbdr;
123962306a36Sopenharmony_ci	}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	return si;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ciout_teardown_cbdr:
124462306a36Sopenharmony_ci	enetc_teardown_cbdr(&si->cbd_ring);
124562306a36Sopenharmony_ciout_pci_remove:
124662306a36Sopenharmony_ci	enetc_pci_remove(pdev);
124762306a36Sopenharmony_ciout:
124862306a36Sopenharmony_ci	return ERR_PTR(err);
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic void enetc_psi_destroy(struct pci_dev *pdev)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	struct enetc_si *si = pci_get_drvdata(pdev);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	enetc_teardown_cbdr(&si->cbd_ring);
125662306a36Sopenharmony_ci	enetc_pci_remove(pdev);
125762306a36Sopenharmony_ci}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_cistatic int enetc_pf_probe(struct pci_dev *pdev,
126062306a36Sopenharmony_ci			  const struct pci_device_id *ent)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
126362306a36Sopenharmony_ci	struct enetc_ndev_priv *priv;
126462306a36Sopenharmony_ci	struct net_device *ndev;
126562306a36Sopenharmony_ci	struct enetc_si *si;
126662306a36Sopenharmony_ci	struct enetc_pf *pf;
126762306a36Sopenharmony_ci	int err;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	err = enetc_pf_register_with_ierb(pdev);
127062306a36Sopenharmony_ci	if (err == -EPROBE_DEFER)
127162306a36Sopenharmony_ci		return err;
127262306a36Sopenharmony_ci	if (err)
127362306a36Sopenharmony_ci		dev_warn(&pdev->dev,
127462306a36Sopenharmony_ci			 "Could not register with IERB driver: %pe, please update the device tree\n",
127562306a36Sopenharmony_ci			 ERR_PTR(err));
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	si = enetc_psi_create(pdev);
127862306a36Sopenharmony_ci	if (IS_ERR(si)) {
127962306a36Sopenharmony_ci		err = PTR_ERR(si);
128062306a36Sopenharmony_ci		goto err_psi_create;
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	pf = enetc_si_priv(si);
128462306a36Sopenharmony_ci	pf->si = si;
128562306a36Sopenharmony_ci	pf->total_vfs = pci_sriov_get_totalvfs(pdev);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	err = enetc_setup_mac_addresses(node, pf);
128862306a36Sopenharmony_ci	if (err)
128962306a36Sopenharmony_ci		goto err_setup_mac_addresses;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	enetc_configure_port(pf);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	enetc_get_si_caps(si);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	ndev = alloc_etherdev_mq(sizeof(*priv), ENETC_MAX_NUM_TXQS);
129662306a36Sopenharmony_ci	if (!ndev) {
129762306a36Sopenharmony_ci		err = -ENOMEM;
129862306a36Sopenharmony_ci		dev_err(&pdev->dev, "netdev creation failed\n");
129962306a36Sopenharmony_ci		goto err_alloc_netdev;
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	enetc_pf_netdev_setup(si, ndev, &enetc_ndev_ops);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	priv = netdev_priv(ndev);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	mutex_init(&priv->mm_lock);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	enetc_init_si_rings_params(priv);
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	err = enetc_alloc_si_resources(priv);
131162306a36Sopenharmony_ci	if (err) {
131262306a36Sopenharmony_ci		dev_err(&pdev->dev, "SI resource alloc failed\n");
131362306a36Sopenharmony_ci		goto err_alloc_si_res;
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	err = enetc_configure_si(priv);
131762306a36Sopenharmony_ci	if (err) {
131862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to configure SI\n");
131962306a36Sopenharmony_ci		goto err_config_si;
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	err = enetc_alloc_msix(priv);
132362306a36Sopenharmony_ci	if (err) {
132462306a36Sopenharmony_ci		dev_err(&pdev->dev, "MSIX alloc failed\n");
132562306a36Sopenharmony_ci		goto err_alloc_msix;
132662306a36Sopenharmony_ci	}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	err = of_get_phy_mode(node, &pf->if_mode);
132962306a36Sopenharmony_ci	if (err) {
133062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to read PHY mode\n");
133162306a36Sopenharmony_ci		goto err_phy_mode;
133262306a36Sopenharmony_ci	}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	err = enetc_mdiobus_create(pf, node);
133562306a36Sopenharmony_ci	if (err)
133662306a36Sopenharmony_ci		goto err_mdiobus_create;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	err = enetc_phylink_create(priv, node);
133962306a36Sopenharmony_ci	if (err)
134062306a36Sopenharmony_ci		goto err_phylink_create;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	err = register_netdev(ndev);
134362306a36Sopenharmony_ci	if (err)
134462306a36Sopenharmony_ci		goto err_reg_netdev;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	return 0;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_cierr_reg_netdev:
134962306a36Sopenharmony_ci	enetc_phylink_destroy(priv);
135062306a36Sopenharmony_cierr_phylink_create:
135162306a36Sopenharmony_ci	enetc_mdiobus_destroy(pf);
135262306a36Sopenharmony_cierr_mdiobus_create:
135362306a36Sopenharmony_cierr_phy_mode:
135462306a36Sopenharmony_ci	enetc_free_msix(priv);
135562306a36Sopenharmony_cierr_config_si:
135662306a36Sopenharmony_cierr_alloc_msix:
135762306a36Sopenharmony_ci	enetc_free_si_resources(priv);
135862306a36Sopenharmony_cierr_alloc_si_res:
135962306a36Sopenharmony_ci	si->ndev = NULL;
136062306a36Sopenharmony_ci	free_netdev(ndev);
136162306a36Sopenharmony_cierr_alloc_netdev:
136262306a36Sopenharmony_cierr_setup_mac_addresses:
136362306a36Sopenharmony_ci	enetc_psi_destroy(pdev);
136462306a36Sopenharmony_cierr_psi_create:
136562306a36Sopenharmony_ci	return err;
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic void enetc_pf_remove(struct pci_dev *pdev)
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	struct enetc_si *si = pci_get_drvdata(pdev);
137162306a36Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(si);
137262306a36Sopenharmony_ci	struct enetc_ndev_priv *priv;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	priv = netdev_priv(si->ndev);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	if (pf->num_vfs)
137762306a36Sopenharmony_ci		enetc_sriov_configure(pdev, 0);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	unregister_netdev(si->ndev);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	enetc_phylink_destroy(priv);
138262306a36Sopenharmony_ci	enetc_mdiobus_destroy(pf);
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	enetc_free_msix(priv);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	enetc_free_si_resources(priv);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	free_netdev(si->ndev);
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	enetc_psi_destroy(pdev);
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_cistatic void enetc_fixup_clear_rss_rfs(struct pci_dev *pdev)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
139662306a36Sopenharmony_ci	struct enetc_si *si;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	/* Only apply quirk for disabled functions. For the ones
139962306a36Sopenharmony_ci	 * that are enabled, enetc_pf_probe() will apply it.
140062306a36Sopenharmony_ci	 */
140162306a36Sopenharmony_ci	if (node && of_device_is_available(node))
140262306a36Sopenharmony_ci		return;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	si = enetc_psi_create(pdev);
140562306a36Sopenharmony_ci	if (!IS_ERR(si))
140662306a36Sopenharmony_ci		enetc_psi_destroy(pdev);
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ciDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF,
140962306a36Sopenharmony_ci			enetc_fixup_clear_rss_rfs);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_cistatic const struct pci_device_id enetc_pf_id_table[] = {
141262306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF) },
141362306a36Sopenharmony_ci	{ 0, } /* End of table. */
141462306a36Sopenharmony_ci};
141562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, enetc_pf_id_table);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_cistatic struct pci_driver enetc_pf_driver = {
141862306a36Sopenharmony_ci	.name = KBUILD_MODNAME,
141962306a36Sopenharmony_ci	.id_table = enetc_pf_id_table,
142062306a36Sopenharmony_ci	.probe = enetc_pf_probe,
142162306a36Sopenharmony_ci	.remove = enetc_pf_remove,
142262306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
142362306a36Sopenharmony_ci	.sriov_configure = enetc_sriov_configure,
142462306a36Sopenharmony_ci#endif
142562306a36Sopenharmony_ci};
142662306a36Sopenharmony_cimodule_pci_driver(enetc_pf_driver);
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ciMODULE_DESCRIPTION(ENETC_DRV_NAME_STR);
142962306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
1430