18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci/* Copyright 2017-2019 NXP */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/mdio.h>
58c2ecf20Sopenharmony_ci#include <linux/module.h>
68c2ecf20Sopenharmony_ci#include <linux/fsl/enetc_mdio.h>
78c2ecf20Sopenharmony_ci#include <linux/of_mdio.h>
88c2ecf20Sopenharmony_ci#include <linux/of_net.h>
98c2ecf20Sopenharmony_ci#include "enetc_pf.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define ENETC_DRV_NAME_STR "ENETC PF driver"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic void enetc_pf_get_primary_mac_addr(struct enetc_hw *hw, int si, u8 *addr)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	u32 upper = __raw_readl(hw->port + ENETC_PSIPMAR0(si));
168c2ecf20Sopenharmony_ci	u16 lower = __raw_readw(hw->port + ENETC_PSIPMAR1(si));
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	*(u32 *)addr = upper;
198c2ecf20Sopenharmony_ci	*(u16 *)(addr + 4) = lower;
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic void enetc_pf_set_primary_mac_addr(struct enetc_hw *hw, int si,
238c2ecf20Sopenharmony_ci					  const u8 *addr)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	u32 upper = *(const u32 *)addr;
268c2ecf20Sopenharmony_ci	u16 lower = *(const u16 *)(addr + 4);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	__raw_writel(upper, hw->port + ENETC_PSIPMAR0(si));
298c2ecf20Sopenharmony_ci	__raw_writew(lower, hw->port + ENETC_PSIPMAR1(si));
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
358c2ecf20Sopenharmony_ci	struct sockaddr *saddr = addr;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(saddr->sa_data))
388c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	memcpy(ndev->dev_addr, saddr->sa_data, ndev->addr_len);
418c2ecf20Sopenharmony_ci	enetc_pf_set_primary_mac_addr(&priv->si->hw, 0, saddr->sa_data);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	return 0;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic void enetc_set_vlan_promisc(struct enetc_hw *hw, char si_map)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	u32 val = enetc_port_rd(hw, ENETC_PSIPVMR);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	val &= ~ENETC_PSIPVMR_SET_VP(ENETC_VLAN_PROMISC_MAP_ALL);
518c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIPVMR, ENETC_PSIPVMR_SET_VP(si_map) | val);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic void enetc_enable_si_vlan_promisc(struct enetc_pf *pf, int si_idx)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	pf->vlan_promisc_simap |= BIT(si_idx);
578c2ecf20Sopenharmony_ci	enetc_set_vlan_promisc(&pf->si->hw, pf->vlan_promisc_simap);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic void enetc_disable_si_vlan_promisc(struct enetc_pf *pf, int si_idx)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	pf->vlan_promisc_simap &= ~BIT(si_idx);
638c2ecf20Sopenharmony_ci	enetc_set_vlan_promisc(&pf->si->hw, pf->vlan_promisc_simap);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic void enetc_set_isol_vlan(struct enetc_hw *hw, int si, u16 vlan, u8 qos)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	u32 val = 0;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if (vlan)
718c2ecf20Sopenharmony_ci		val = ENETC_PSIVLAN_EN | ENETC_PSIVLAN_SET_QOS(qos) | vlan;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIVLANR(si), val);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic int enetc_mac_addr_hash_idx(const u8 *addr)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	u64 fold = __swab64(ether_addr_to_u64(addr)) >> 16;
798c2ecf20Sopenharmony_ci	u64 mask = 0;
808c2ecf20Sopenharmony_ci	int res = 0;
818c2ecf20Sopenharmony_ci	int i;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++)
848c2ecf20Sopenharmony_ci		mask |= BIT_ULL(i * 6);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++)
878c2ecf20Sopenharmony_ci		res |= (hweight64(fold & (mask << i)) & 0x1) << i;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	return res;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic void enetc_reset_mac_addr_filter(struct enetc_mac_filter *filter)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	filter->mac_addr_cnt = 0;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	bitmap_zero(filter->mac_hash_table,
978c2ecf20Sopenharmony_ci		    ENETC_MADDR_HASH_TBL_SZ);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter,
1018c2ecf20Sopenharmony_ci					 const unsigned char *addr)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	/* add exact match addr */
1048c2ecf20Sopenharmony_ci	ether_addr_copy(filter->mac_addr, addr);
1058c2ecf20Sopenharmony_ci	filter->mac_addr_cnt++;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic void enetc_add_mac_addr_ht_filter(struct enetc_mac_filter *filter,
1098c2ecf20Sopenharmony_ci					 const unsigned char *addr)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	int idx = enetc_mac_addr_hash_idx(addr);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* add hash table entry */
1148c2ecf20Sopenharmony_ci	__set_bit(idx, filter->mac_hash_table);
1158c2ecf20Sopenharmony_ci	filter->mac_addr_cnt++;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic void enetc_clear_mac_ht_flt(struct enetc_si *si, int si_idx, int type)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	bool err = si->errata & ENETC_ERR_UCMCSWP;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	if (type == UC) {
1238c2ecf20Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err), 0);
1248c2ecf20Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx), 0);
1258c2ecf20Sopenharmony_ci	} else { /* MC */
1268c2ecf20Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err), 0);
1278c2ecf20Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx), 0);
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type,
1328c2ecf20Sopenharmony_ci				 u32 *hash)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	bool err = si->errata & ENETC_ERR_UCMCSWP;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (type == UC) {
1378c2ecf20Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err), *hash);
1388c2ecf20Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx), *(hash + 1));
1398c2ecf20Sopenharmony_ci	} else { /* MC */
1408c2ecf20Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err), *hash);
1418c2ecf20Sopenharmony_ci		enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx), *(hash + 1));
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic void enetc_sync_mac_filters(struct enetc_pf *pf)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct enetc_mac_filter *f = pf->mac_filter;
1488c2ecf20Sopenharmony_ci	struct enetc_si *si = pf->si;
1498c2ecf20Sopenharmony_ci	int i, pos;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	pos = EMETC_MAC_ADDR_FILT_RES;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	for (i = 0; i < MADDR_TYPE; i++, f++) {
1548c2ecf20Sopenharmony_ci		bool em = (f->mac_addr_cnt == 1) && (i == UC);
1558c2ecf20Sopenharmony_ci		bool clear = !f->mac_addr_cnt;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci		if (clear) {
1588c2ecf20Sopenharmony_ci			if (i == UC)
1598c2ecf20Sopenharmony_ci				enetc_clear_mac_flt_entry(si, pos);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci			enetc_clear_mac_ht_flt(si, 0, i);
1628c2ecf20Sopenharmony_ci			continue;
1638c2ecf20Sopenharmony_ci		}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		/* exact match filter */
1668c2ecf20Sopenharmony_ci		if (em) {
1678c2ecf20Sopenharmony_ci			int err;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci			enetc_clear_mac_ht_flt(si, 0, UC);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci			err = enetc_set_mac_flt_entry(si, pos, f->mac_addr,
1728c2ecf20Sopenharmony_ci						      BIT(0));
1738c2ecf20Sopenharmony_ci			if (!err)
1748c2ecf20Sopenharmony_ci				continue;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci			/* fallback to HT filtering */
1778c2ecf20Sopenharmony_ci			dev_warn(&si->pdev->dev, "fallback to HT filt (%d)\n",
1788c2ecf20Sopenharmony_ci				 err);
1798c2ecf20Sopenharmony_ci		}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci		/* hash table filter, clear EM filter for UC entries */
1828c2ecf20Sopenharmony_ci		if (i == UC)
1838c2ecf20Sopenharmony_ci			enetc_clear_mac_flt_entry(si, pos);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci		enetc_set_mac_ht_flt(si, 0, i, (u32 *)f->mac_hash_table);
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic void enetc_pf_set_rx_mode(struct net_device *ndev)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
1928c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
1938c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
1948c2ecf20Sopenharmony_ci	bool uprom = false, mprom = false;
1958c2ecf20Sopenharmony_ci	struct enetc_mac_filter *filter;
1968c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
1978c2ecf20Sopenharmony_ci	u32 psipmr = 0;
1988c2ecf20Sopenharmony_ci	bool em;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (ndev->flags & IFF_PROMISC) {
2018c2ecf20Sopenharmony_ci		/* enable promisc mode for SI0 (PF) */
2028c2ecf20Sopenharmony_ci		psipmr = ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0);
2038c2ecf20Sopenharmony_ci		uprom = true;
2048c2ecf20Sopenharmony_ci		mprom = true;
2058c2ecf20Sopenharmony_ci	} else if (ndev->flags & IFF_ALLMULTI) {
2068c2ecf20Sopenharmony_ci		/* enable multi cast promisc mode for SI0 (PF) */
2078c2ecf20Sopenharmony_ci		psipmr = ENETC_PSIPMR_SET_MP(0);
2088c2ecf20Sopenharmony_ci		mprom = true;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* first 2 filter entries belong to PF */
2128c2ecf20Sopenharmony_ci	if (!uprom) {
2138c2ecf20Sopenharmony_ci		/* Update unicast filters */
2148c2ecf20Sopenharmony_ci		filter = &pf->mac_filter[UC];
2158c2ecf20Sopenharmony_ci		enetc_reset_mac_addr_filter(filter);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		em = (netdev_uc_count(ndev) == 1);
2188c2ecf20Sopenharmony_ci		netdev_for_each_uc_addr(ha, ndev) {
2198c2ecf20Sopenharmony_ci			if (em) {
2208c2ecf20Sopenharmony_ci				enetc_add_mac_addr_em_filter(filter, ha->addr);
2218c2ecf20Sopenharmony_ci				break;
2228c2ecf20Sopenharmony_ci			}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci			enetc_add_mac_addr_ht_filter(filter, ha->addr);
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (!mprom) {
2298c2ecf20Sopenharmony_ci		/* Update multicast filters */
2308c2ecf20Sopenharmony_ci		filter = &pf->mac_filter[MC];
2318c2ecf20Sopenharmony_ci		enetc_reset_mac_addr_filter(filter);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, ndev) {
2348c2ecf20Sopenharmony_ci			if (!is_multicast_ether_addr(ha->addr))
2358c2ecf20Sopenharmony_ci				continue;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci			enetc_add_mac_addr_ht_filter(filter, ha->addr);
2388c2ecf20Sopenharmony_ci		}
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (!uprom || !mprom)
2428c2ecf20Sopenharmony_ci		/* update PF entries */
2438c2ecf20Sopenharmony_ci		enetc_sync_mac_filters(pf);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	psipmr |= enetc_port_rd(hw, ENETC_PSIPMR) &
2468c2ecf20Sopenharmony_ci		  ~(ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0));
2478c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIPMR, psipmr);
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic void enetc_set_vlan_ht_filter(struct enetc_hw *hw, int si_idx,
2518c2ecf20Sopenharmony_ci				     u32 *hash)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIVHFR0(si_idx), *hash);
2548c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIVHFR1(si_idx), *(hash + 1));
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic int enetc_vid_hash_idx(unsigned int vid)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	int res = 0;
2608c2ecf20Sopenharmony_ci	int i;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++)
2638c2ecf20Sopenharmony_ci		res |= (hweight8(vid & (BIT(i) | BIT(i + 6))) & 0x1) << i;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return res;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic void enetc_sync_vlan_ht_filter(struct enetc_pf *pf, bool rehash)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	int i;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (rehash) {
2738c2ecf20Sopenharmony_ci		bitmap_zero(pf->vlan_ht_filter, ENETC_VLAN_HT_SIZE);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		for_each_set_bit(i, pf->active_vlans, VLAN_N_VID) {
2768c2ecf20Sopenharmony_ci			int hidx = enetc_vid_hash_idx(i);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci			__set_bit(hidx, pf->vlan_ht_filter);
2798c2ecf20Sopenharmony_ci		}
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	enetc_set_vlan_ht_filter(&pf->si->hw, 0, (u32 *)pf->vlan_ht_filter);
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
2888c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
2898c2ecf20Sopenharmony_ci	int idx;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	__set_bit(vid, pf->active_vlans);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	idx = enetc_vid_hash_idx(vid);
2948c2ecf20Sopenharmony_ci	if (!__test_and_set_bit(idx, pf->vlan_ht_filter))
2958c2ecf20Sopenharmony_ci		enetc_sync_vlan_ht_filter(pf, false);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return 0;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
3038c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	__clear_bit(vid, pf->active_vlans);
3068c2ecf20Sopenharmony_ci	enetc_sync_vlan_ht_filter(pf, true);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	return 0;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic void enetc_set_loopback(struct net_device *ndev, bool en)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
3148c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
3158c2ecf20Sopenharmony_ci	u32 reg;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	reg = enetc_port_rd(hw, ENETC_PM0_IF_MODE);
3188c2ecf20Sopenharmony_ci	if (reg & ENETC_PM0_IFM_RG) {
3198c2ecf20Sopenharmony_ci		/* RGMII mode */
3208c2ecf20Sopenharmony_ci		reg = (reg & ~ENETC_PM0_IFM_RLP) |
3218c2ecf20Sopenharmony_ci		      (en ? ENETC_PM0_IFM_RLP : 0);
3228c2ecf20Sopenharmony_ci		enetc_port_wr(hw, ENETC_PM0_IF_MODE, reg);
3238c2ecf20Sopenharmony_ci	} else {
3248c2ecf20Sopenharmony_ci		/* assume SGMII mode */
3258c2ecf20Sopenharmony_ci		reg = enetc_port_rd(hw, ENETC_PM0_CMD_CFG);
3268c2ecf20Sopenharmony_ci		reg = (reg & ~ENETC_PM0_CMD_XGLP) |
3278c2ecf20Sopenharmony_ci		      (en ? ENETC_PM0_CMD_XGLP : 0);
3288c2ecf20Sopenharmony_ci		reg = (reg & ~ENETC_PM0_CMD_PHY_TX_EN) |
3298c2ecf20Sopenharmony_ci		      (en ? ENETC_PM0_CMD_PHY_TX_EN : 0);
3308c2ecf20Sopenharmony_ci		enetc_port_wr(hw, ENETC_PM0_CMD_CFG, reg);
3318c2ecf20Sopenharmony_ci		enetc_port_wr(hw, ENETC_PM1_CMD_CFG, reg);
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
3388c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
3398c2ecf20Sopenharmony_ci	struct enetc_vf_state *vf_state;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (vf >= pf->total_vfs)
3428c2ecf20Sopenharmony_ci		return -EINVAL;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(mac))
3458c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	vf_state = &pf->vf_state[vf];
3488c2ecf20Sopenharmony_ci	vf_state->flags |= ENETC_VF_FLAG_PF_SET_MAC;
3498c2ecf20Sopenharmony_ci	enetc_pf_set_primary_mac_addr(&priv->si->hw, vf + 1, mac);
3508c2ecf20Sopenharmony_ci	return 0;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic int enetc_pf_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,
3548c2ecf20Sopenharmony_ci				u8 qos, __be16 proto)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
3578c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (priv->si->errata & ENETC_ERR_VLAN_ISOL)
3608c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (vf >= pf->total_vfs)
3638c2ecf20Sopenharmony_ci		return -EINVAL;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (proto != htons(ETH_P_8021Q))
3668c2ecf20Sopenharmony_ci		/* only C-tags supported for now */
3678c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	enetc_set_isol_vlan(&priv->si->hw, vf + 1, vlan, qos);
3708c2ecf20Sopenharmony_ci	return 0;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
3768c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
3778c2ecf20Sopenharmony_ci	u32 cfgr;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	if (vf >= pf->total_vfs)
3808c2ecf20Sopenharmony_ci		return -EINVAL;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	cfgr = enetc_port_rd(&priv->si->hw, ENETC_PSICFGR0(vf + 1));
3838c2ecf20Sopenharmony_ci	cfgr = (cfgr & ~ENETC_PSICFGR0_ASE) | (en ? ENETC_PSICFGR0_ASE : 0);
3848c2ecf20Sopenharmony_ci	enetc_port_wr(&priv->si->hw, ENETC_PSICFGR0(vf + 1), cfgr);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	return 0;
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic void enetc_port_setup_primary_mac_address(struct enetc_si *si)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	unsigned char mac_addr[MAX_ADDR_LEN];
3928c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(si);
3938c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
3948c2ecf20Sopenharmony_ci	int i;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	/* check MAC addresses for PF and all VFs, if any is 0 set it ro rand */
3978c2ecf20Sopenharmony_ci	for (i = 0; i < pf->total_vfs + 1; i++) {
3988c2ecf20Sopenharmony_ci		enetc_pf_get_primary_mac_addr(hw, i, mac_addr);
3998c2ecf20Sopenharmony_ci		if (!is_zero_ether_addr(mac_addr))
4008c2ecf20Sopenharmony_ci			continue;
4018c2ecf20Sopenharmony_ci		eth_random_addr(mac_addr);
4028c2ecf20Sopenharmony_ci		dev_info(&si->pdev->dev, "no MAC address specified for SI%d, using %pM\n",
4038c2ecf20Sopenharmony_ci			 i, mac_addr);
4048c2ecf20Sopenharmony_ci		enetc_pf_set_primary_mac_addr(hw, i, mac_addr);
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic void enetc_port_assign_rfs_entries(struct enetc_si *si)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(si);
4118c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
4128c2ecf20Sopenharmony_ci	int num_entries, vf_entries, i;
4138c2ecf20Sopenharmony_ci	u32 val;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* split RFS entries between functions */
4168c2ecf20Sopenharmony_ci	val = enetc_port_rd(hw, ENETC_PRFSCAPR);
4178c2ecf20Sopenharmony_ci	num_entries = ENETC_PRFSCAPR_GET_NUM_RFS(val);
4188c2ecf20Sopenharmony_ci	vf_entries = num_entries / (pf->total_vfs + 1);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	for (i = 0; i < pf->total_vfs; i++)
4218c2ecf20Sopenharmony_ci		enetc_port_wr(hw, ENETC_PSIRFSCFGR(i + 1), vf_entries);
4228c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIRFSCFGR(0),
4238c2ecf20Sopenharmony_ci		      num_entries - vf_entries * pf->total_vfs);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	/* enable RFS on port */
4268c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PRFSMR, ENETC_PRFSMR_RFSE);
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic void enetc_port_si_configure(struct enetc_si *si)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(si);
4328c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
4338c2ecf20Sopenharmony_ci	int num_rings, i;
4348c2ecf20Sopenharmony_ci	u32 val;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	val = enetc_port_rd(hw, ENETC_PCAPR0);
4378c2ecf20Sopenharmony_ci	num_rings = min(ENETC_PCAPR0_RXBDR(val), ENETC_PCAPR0_TXBDR(val));
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	val = ENETC_PSICFGR0_SET_TXBDR(ENETC_PF_NUM_RINGS);
4408c2ecf20Sopenharmony_ci	val |= ENETC_PSICFGR0_SET_RXBDR(ENETC_PF_NUM_RINGS);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	if (unlikely(num_rings < ENETC_PF_NUM_RINGS)) {
4438c2ecf20Sopenharmony_ci		val = ENETC_PSICFGR0_SET_TXBDR(num_rings);
4448c2ecf20Sopenharmony_ci		val |= ENETC_PSICFGR0_SET_RXBDR(num_rings);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		dev_warn(&si->pdev->dev, "Found %d rings, expected %d!\n",
4478c2ecf20Sopenharmony_ci			 num_rings, ENETC_PF_NUM_RINGS);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci		num_rings = 0;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	/* Add default one-time settings for SI0 (PF) */
4538c2ecf20Sopenharmony_ci	val |= ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSICFGR0(0), val);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (num_rings)
4588c2ecf20Sopenharmony_ci		num_rings -= ENETC_PF_NUM_RINGS;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	/* Configure the SIs for each available VF */
4618c2ecf20Sopenharmony_ci	val = ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
4628c2ecf20Sopenharmony_ci	val |= ENETC_PSICFGR0_VTE | ENETC_PSICFGR0_SIVIE;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	if (num_rings) {
4658c2ecf20Sopenharmony_ci		num_rings /= pf->total_vfs;
4668c2ecf20Sopenharmony_ci		val |= ENETC_PSICFGR0_SET_TXBDR(num_rings);
4678c2ecf20Sopenharmony_ci		val |= ENETC_PSICFGR0_SET_RXBDR(num_rings);
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	for (i = 0; i < pf->total_vfs; i++)
4718c2ecf20Sopenharmony_ci		enetc_port_wr(hw, ENETC_PSICFGR0(i + 1), val);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/* Port level VLAN settings */
4748c2ecf20Sopenharmony_ci	val = ENETC_PVCLCTR_OVTPIDL(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
4758c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PVCLCTR, val);
4768c2ecf20Sopenharmony_ci	/* use outer tag for VLAN filtering */
4778c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIVLANFMR, ENETC_PSIVLANFMR_VS);
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic void enetc_configure_port_mac(struct enetc_hw *hw)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PM0_MAXFRM,
4838c2ecf20Sopenharmony_ci		      ENETC_SET_MAXFRM(ENETC_RX_MAXFRM_SIZE));
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PTCMSDUR(0), ENETC_MAC_MAXFRM_SIZE);
4868c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PTXMBAR, 2 * ENETC_MAC_MAXFRM_SIZE);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PM0_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN |
4898c2ecf20Sopenharmony_ci		      ENETC_PM0_CMD_TXP	| ENETC_PM0_PROMISC);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PM1_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN |
4928c2ecf20Sopenharmony_ci		      ENETC_PM0_CMD_TXP	| ENETC_PM0_PROMISC);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	/* On LS1028A, the MAC RX FIFO defaults to 2, which is too high
4958c2ecf20Sopenharmony_ci	 * and may lead to RX lock-up under traffic. Set it to 1 instead,
4968c2ecf20Sopenharmony_ci	 * as recommended by the hardware team.
4978c2ecf20Sopenharmony_ci	 */
4988c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PM0_RX_FIFO, ENETC_PM0_RX_FIFO_VAL);
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic void enetc_mac_config(struct enetc_hw *hw, phy_interface_t phy_mode)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	u32 val;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	if (phy_interface_mode_is_rgmii(phy_mode)) {
5068c2ecf20Sopenharmony_ci		val = enetc_port_rd(hw, ENETC_PM0_IF_MODE);
5078c2ecf20Sopenharmony_ci		val &= ~(ENETC_PM0_IFM_EN_AUTO | ENETC_PM0_IFM_IFMODE_MASK);
5088c2ecf20Sopenharmony_ci		val |= ENETC_PM0_IFM_IFMODE_GMII | ENETC_PM0_IFM_RG;
5098c2ecf20Sopenharmony_ci		enetc_port_wr(hw, ENETC_PM0_IF_MODE, val);
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if (phy_mode == PHY_INTERFACE_MODE_USXGMII) {
5138c2ecf20Sopenharmony_ci		val = ENETC_PM0_IFM_FULL_DPX | ENETC_PM0_IFM_IFMODE_XGMII;
5148c2ecf20Sopenharmony_ci		enetc_port_wr(hw, ENETC_PM0_IF_MODE, val);
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic void enetc_mac_enable(struct enetc_hw *hw, bool en)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	u32 val = enetc_port_rd(hw, ENETC_PM0_CMD_CFG);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	val &= ~(ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
5238c2ecf20Sopenharmony_ci	val |= en ? (ENETC_PM0_TX_EN | ENETC_PM0_RX_EN) : 0;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PM0_CMD_CFG, val);
5268c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PM1_CMD_CFG, val);
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic void enetc_configure_port_pmac(struct enetc_hw *hw)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	u32 temp;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	/* Set pMAC step lock */
5348c2ecf20Sopenharmony_ci	temp = enetc_port_rd(hw, ENETC_PFPMR);
5358c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PFPMR,
5368c2ecf20Sopenharmony_ci		      temp | ENETC_PFPMR_PMACE | ENETC_PFPMR_MWLM);
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	temp = enetc_port_rd(hw, ENETC_MMCSR);
5398c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_MMCSR, temp | ENETC_MMCSR_ME);
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic void enetc_configure_port(struct enetc_pf *pf)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	u8 hash_key[ENETC_RSSHASH_KEY_SIZE];
5458c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &pf->si->hw;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	enetc_configure_port_pmac(hw);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	enetc_configure_port_mac(hw);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	enetc_port_si_configure(pf->si);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	/* set up hash key */
5548c2ecf20Sopenharmony_ci	get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE);
5558c2ecf20Sopenharmony_ci	enetc_set_rss_key(hw, hash_key);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	/* split up RFS entries */
5588c2ecf20Sopenharmony_ci	enetc_port_assign_rfs_entries(pf->si);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	/* fix-up primary MAC addresses, if not set already */
5618c2ecf20Sopenharmony_ci	enetc_port_setup_primary_mac_address(pf->si);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	/* enforce VLAN promisc mode for all SIs */
5648c2ecf20Sopenharmony_ci	pf->vlan_promisc_simap = ENETC_VLAN_PROMISC_MAP_ALL;
5658c2ecf20Sopenharmony_ci	enetc_set_vlan_promisc(hw, pf->vlan_promisc_simap);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PSIPMR, 0);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* enable port */
5708c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PMR, ENETC_PMR_EN);
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci/* Messaging */
5748c2ecf20Sopenharmony_cistatic u16 enetc_msg_pf_set_vf_primary_mac_addr(struct enetc_pf *pf,
5758c2ecf20Sopenharmony_ci						int vf_id)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
5788c2ecf20Sopenharmony_ci	struct enetc_msg_swbd *msg = &pf->rxmsg[vf_id];
5798c2ecf20Sopenharmony_ci	struct enetc_msg_cmd_set_primary_mac *cmd;
5808c2ecf20Sopenharmony_ci	struct device *dev = &pf->si->pdev->dev;
5818c2ecf20Sopenharmony_ci	u16 cmd_id;
5828c2ecf20Sopenharmony_ci	char *addr;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	cmd = (struct enetc_msg_cmd_set_primary_mac *)msg->vaddr;
5858c2ecf20Sopenharmony_ci	cmd_id = cmd->header.id;
5868c2ecf20Sopenharmony_ci	if (cmd_id != ENETC_MSG_CMD_MNG_ADD)
5878c2ecf20Sopenharmony_ci		return ENETC_MSG_CMD_STATUS_FAIL;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	addr = cmd->mac.sa_data;
5908c2ecf20Sopenharmony_ci	if (vf_state->flags & ENETC_VF_FLAG_PF_SET_MAC)
5918c2ecf20Sopenharmony_ci		dev_warn(dev, "Attempt to override PF set mac addr for VF%d\n",
5928c2ecf20Sopenharmony_ci			 vf_id);
5938c2ecf20Sopenharmony_ci	else
5948c2ecf20Sopenharmony_ci		enetc_pf_set_primary_mac_addr(&pf->si->hw, vf_id + 1, addr);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	return ENETC_MSG_CMD_STATUS_OK;
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_civoid enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id, u16 *status)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	struct enetc_msg_swbd *msg = &pf->rxmsg[vf_id];
6028c2ecf20Sopenharmony_ci	struct device *dev = &pf->si->pdev->dev;
6038c2ecf20Sopenharmony_ci	struct enetc_msg_cmd_header *cmd_hdr;
6048c2ecf20Sopenharmony_ci	u16 cmd_type;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	*status = ENETC_MSG_CMD_STATUS_OK;
6078c2ecf20Sopenharmony_ci	cmd_hdr = (struct enetc_msg_cmd_header *)msg->vaddr;
6088c2ecf20Sopenharmony_ci	cmd_type = cmd_hdr->type;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	switch (cmd_type) {
6118c2ecf20Sopenharmony_ci	case ENETC_MSG_CMD_MNG_MAC:
6128c2ecf20Sopenharmony_ci		*status = enetc_msg_pf_set_vf_primary_mac_addr(pf, vf_id);
6138c2ecf20Sopenharmony_ci		break;
6148c2ecf20Sopenharmony_ci	default:
6158c2ecf20Sopenharmony_ci		dev_err(dev, "command not supported (cmd_type: 0x%x)\n",
6168c2ecf20Sopenharmony_ci			cmd_type);
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
6218c2ecf20Sopenharmony_cistatic int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct enetc_si *si = pci_get_drvdata(pdev);
6248c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(si);
6258c2ecf20Sopenharmony_ci	int err;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (!num_vfs) {
6288c2ecf20Sopenharmony_ci		enetc_msg_psi_free(pf);
6298c2ecf20Sopenharmony_ci		kfree(pf->vf_state);
6308c2ecf20Sopenharmony_ci		pf->num_vfs = 0;
6318c2ecf20Sopenharmony_ci		pci_disable_sriov(pdev);
6328c2ecf20Sopenharmony_ci	} else {
6338c2ecf20Sopenharmony_ci		pf->num_vfs = num_vfs;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state),
6368c2ecf20Sopenharmony_ci				       GFP_KERNEL);
6378c2ecf20Sopenharmony_ci		if (!pf->vf_state) {
6388c2ecf20Sopenharmony_ci			pf->num_vfs = 0;
6398c2ecf20Sopenharmony_ci			return -ENOMEM;
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		err = enetc_msg_psi_init(pf);
6438c2ecf20Sopenharmony_ci		if (err) {
6448c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err);
6458c2ecf20Sopenharmony_ci			goto err_msg_psi;
6468c2ecf20Sopenharmony_ci		}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci		err = pci_enable_sriov(pdev, num_vfs);
6498c2ecf20Sopenharmony_ci		if (err) {
6508c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err);
6518c2ecf20Sopenharmony_ci			goto err_en_sriov;
6528c2ecf20Sopenharmony_ci		}
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	return num_vfs;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cierr_en_sriov:
6588c2ecf20Sopenharmony_ci	enetc_msg_psi_free(pf);
6598c2ecf20Sopenharmony_cierr_msg_psi:
6608c2ecf20Sopenharmony_ci	kfree(pf->vf_state);
6618c2ecf20Sopenharmony_ci	pf->num_vfs = 0;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	return err;
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci#else
6668c2ecf20Sopenharmony_ci#define enetc_sriov_configure(pdev, num_vfs)	(void)0
6678c2ecf20Sopenharmony_ci#endif
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_cistatic int enetc_pf_set_features(struct net_device *ndev,
6708c2ecf20Sopenharmony_ci				 netdev_features_t features)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	netdev_features_t changed = ndev->features ^ features;
6738c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
6748c2ecf20Sopenharmony_ci	int err;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if (changed & NETIF_F_HW_TC) {
6778c2ecf20Sopenharmony_ci		err = enetc_set_psfp(ndev, !!(features & NETIF_F_HW_TC));
6788c2ecf20Sopenharmony_ci		if (err)
6798c2ecf20Sopenharmony_ci			return err;
6808c2ecf20Sopenharmony_ci	}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
6838c2ecf20Sopenharmony_ci		struct enetc_pf *pf = enetc_si_priv(priv->si);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		if (!!(features & NETIF_F_HW_VLAN_CTAG_FILTER))
6868c2ecf20Sopenharmony_ci			enetc_disable_si_vlan_promisc(pf, 0);
6878c2ecf20Sopenharmony_ci		else
6888c2ecf20Sopenharmony_ci			enetc_enable_si_vlan_promisc(pf, 0);
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (changed & NETIF_F_LOOPBACK)
6928c2ecf20Sopenharmony_ci		enetc_set_loopback(ndev, !!(features & NETIF_F_LOOPBACK));
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	enetc_set_features(ndev, features);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	return 0;
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_cistatic const struct net_device_ops enetc_ndev_ops = {
7008c2ecf20Sopenharmony_ci	.ndo_open		= enetc_open,
7018c2ecf20Sopenharmony_ci	.ndo_stop		= enetc_close,
7028c2ecf20Sopenharmony_ci	.ndo_start_xmit		= enetc_xmit,
7038c2ecf20Sopenharmony_ci	.ndo_get_stats		= enetc_get_stats,
7048c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= enetc_pf_set_mac_addr,
7058c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= enetc_pf_set_rx_mode,
7068c2ecf20Sopenharmony_ci	.ndo_vlan_rx_add_vid	= enetc_vlan_rx_add_vid,
7078c2ecf20Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= enetc_vlan_rx_del_vid,
7088c2ecf20Sopenharmony_ci	.ndo_set_vf_mac		= enetc_pf_set_vf_mac,
7098c2ecf20Sopenharmony_ci	.ndo_set_vf_vlan	= enetc_pf_set_vf_vlan,
7108c2ecf20Sopenharmony_ci	.ndo_set_vf_spoofchk	= enetc_pf_set_vf_spoofchk,
7118c2ecf20Sopenharmony_ci	.ndo_set_features	= enetc_pf_set_features,
7128c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= enetc_ioctl,
7138c2ecf20Sopenharmony_ci	.ndo_setup_tc		= enetc_setup_tc,
7148c2ecf20Sopenharmony_ci};
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cistatic void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
7178c2ecf20Sopenharmony_ci				  const struct net_device_ops *ndev_ops)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(ndev, &si->pdev->dev);
7228c2ecf20Sopenharmony_ci	priv->ndev = ndev;
7238c2ecf20Sopenharmony_ci	priv->si = si;
7248c2ecf20Sopenharmony_ci	priv->dev = &si->pdev->dev;
7258c2ecf20Sopenharmony_ci	si->ndev = ndev;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
7288c2ecf20Sopenharmony_ci	ndev->netdev_ops = ndev_ops;
7298c2ecf20Sopenharmony_ci	enetc_set_ethtool_ops(ndev);
7308c2ecf20Sopenharmony_ci	ndev->watchdog_timeo = 5 * HZ;
7318c2ecf20Sopenharmony_ci	ndev->max_mtu = ENETC_MAX_MTU;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
7348c2ecf20Sopenharmony_ci			    NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
7358c2ecf20Sopenharmony_ci			    NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK;
7368c2ecf20Sopenharmony_ci	ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG |
7378c2ecf20Sopenharmony_ci			 NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
7388c2ecf20Sopenharmony_ci			 NETIF_F_HW_VLAN_CTAG_TX |
7398c2ecf20Sopenharmony_ci			 NETIF_F_HW_VLAN_CTAG_RX;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	if (si->num_rss)
7428c2ecf20Sopenharmony_ci		ndev->hw_features |= NETIF_F_RXHASH;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	if (si->errata & ENETC_ERR_TXCSUM) {
7458c2ecf20Sopenharmony_ci		ndev->hw_features &= ~NETIF_F_HW_CSUM;
7468c2ecf20Sopenharmony_ci		ndev->features &= ~NETIF_F_HW_CSUM;
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	ndev->priv_flags |= IFF_UNICAST_FLT;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) {
7528c2ecf20Sopenharmony_ci		priv->active_offloads |= ENETC_F_QCI;
7538c2ecf20Sopenharmony_ci		ndev->features |= NETIF_F_HW_TC;
7548c2ecf20Sopenharmony_ci		ndev->hw_features |= NETIF_F_HW_TC;
7558c2ecf20Sopenharmony_ci	}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	/* pick up primary MAC address from SI */
7588c2ecf20Sopenharmony_ci	enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr);
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	struct device *dev = &pf->si->pdev->dev;
7648c2ecf20Sopenharmony_ci	struct enetc_mdio_priv *mdio_priv;
7658c2ecf20Sopenharmony_ci	struct mii_bus *bus;
7668c2ecf20Sopenharmony_ci	int err;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
7698c2ecf20Sopenharmony_ci	if (!bus)
7708c2ecf20Sopenharmony_ci		return -ENOMEM;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	bus->name = "Freescale ENETC MDIO Bus";
7738c2ecf20Sopenharmony_ci	bus->read = enetc_mdio_read;
7748c2ecf20Sopenharmony_ci	bus->write = enetc_mdio_write;
7758c2ecf20Sopenharmony_ci	bus->parent = dev;
7768c2ecf20Sopenharmony_ci	mdio_priv = bus->priv;
7778c2ecf20Sopenharmony_ci	mdio_priv->hw = &pf->si->hw;
7788c2ecf20Sopenharmony_ci	mdio_priv->mdio_base = ENETC_EMDIO_BASE;
7798c2ecf20Sopenharmony_ci	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	err = of_mdiobus_register(bus, np);
7828c2ecf20Sopenharmony_ci	if (err) {
7838c2ecf20Sopenharmony_ci		dev_err(dev, "cannot register MDIO bus\n");
7848c2ecf20Sopenharmony_ci		return err;
7858c2ecf20Sopenharmony_ci	}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	pf->mdio = bus;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	return 0;
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_cistatic void enetc_mdio_remove(struct enetc_pf *pf)
7938c2ecf20Sopenharmony_ci{
7948c2ecf20Sopenharmony_ci	if (pf->mdio)
7958c2ecf20Sopenharmony_ci		mdiobus_unregister(pf->mdio);
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_cistatic int enetc_imdio_create(struct enetc_pf *pf)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	struct device *dev = &pf->si->pdev->dev;
8018c2ecf20Sopenharmony_ci	struct enetc_mdio_priv *mdio_priv;
8028c2ecf20Sopenharmony_ci	struct lynx_pcs *pcs_lynx;
8038c2ecf20Sopenharmony_ci	struct mdio_device *pcs;
8048c2ecf20Sopenharmony_ci	struct mii_bus *bus;
8058c2ecf20Sopenharmony_ci	int err;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
8088c2ecf20Sopenharmony_ci	if (!bus)
8098c2ecf20Sopenharmony_ci		return -ENOMEM;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	bus->name = "Freescale ENETC internal MDIO Bus";
8128c2ecf20Sopenharmony_ci	bus->read = enetc_mdio_read;
8138c2ecf20Sopenharmony_ci	bus->write = enetc_mdio_write;
8148c2ecf20Sopenharmony_ci	bus->parent = dev;
8158c2ecf20Sopenharmony_ci	bus->phy_mask = ~0;
8168c2ecf20Sopenharmony_ci	mdio_priv = bus->priv;
8178c2ecf20Sopenharmony_ci	mdio_priv->hw = &pf->si->hw;
8188c2ecf20Sopenharmony_ci	mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
8198c2ecf20Sopenharmony_ci	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	err = mdiobus_register(bus);
8228c2ecf20Sopenharmony_ci	if (err) {
8238c2ecf20Sopenharmony_ci		dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
8248c2ecf20Sopenharmony_ci		goto free_mdio_bus;
8258c2ecf20Sopenharmony_ci	}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	pcs = mdio_device_create(bus, 0);
8288c2ecf20Sopenharmony_ci	if (IS_ERR(pcs)) {
8298c2ecf20Sopenharmony_ci		err = PTR_ERR(pcs);
8308c2ecf20Sopenharmony_ci		dev_err(dev, "cannot create pcs (%d)\n", err);
8318c2ecf20Sopenharmony_ci		goto unregister_mdiobus;
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	pcs_lynx = lynx_pcs_create(pcs);
8358c2ecf20Sopenharmony_ci	if (!pcs_lynx) {
8368c2ecf20Sopenharmony_ci		mdio_device_free(pcs);
8378c2ecf20Sopenharmony_ci		err = -ENOMEM;
8388c2ecf20Sopenharmony_ci		dev_err(dev, "cannot create lynx pcs (%d)\n", err);
8398c2ecf20Sopenharmony_ci		goto unregister_mdiobus;
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	pf->imdio = bus;
8438c2ecf20Sopenharmony_ci	pf->pcs = pcs_lynx;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	return 0;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ciunregister_mdiobus:
8488c2ecf20Sopenharmony_ci	mdiobus_unregister(bus);
8498c2ecf20Sopenharmony_cifree_mdio_bus:
8508c2ecf20Sopenharmony_ci	mdiobus_free(bus);
8518c2ecf20Sopenharmony_ci	return err;
8528c2ecf20Sopenharmony_ci}
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_cistatic void enetc_imdio_remove(struct enetc_pf *pf)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	if (pf->pcs) {
8578c2ecf20Sopenharmony_ci		mdio_device_free(pf->pcs->mdio);
8588c2ecf20Sopenharmony_ci		lynx_pcs_destroy(pf->pcs);
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci	if (pf->imdio) {
8618c2ecf20Sopenharmony_ci		mdiobus_unregister(pf->imdio);
8628c2ecf20Sopenharmony_ci		mdiobus_free(pf->imdio);
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_cistatic bool enetc_port_has_pcs(struct enetc_pf *pf)
8678c2ecf20Sopenharmony_ci{
8688c2ecf20Sopenharmony_ci	return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
8698c2ecf20Sopenharmony_ci		pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
8708c2ecf20Sopenharmony_ci		pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
8718c2ecf20Sopenharmony_ci}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_cistatic int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
8748c2ecf20Sopenharmony_ci{
8758c2ecf20Sopenharmony_ci	struct device_node *mdio_np;
8768c2ecf20Sopenharmony_ci	int err;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	mdio_np = of_get_child_by_name(node, "mdio");
8798c2ecf20Sopenharmony_ci	if (mdio_np) {
8808c2ecf20Sopenharmony_ci		err = enetc_mdio_probe(pf, mdio_np);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci		of_node_put(mdio_np);
8838c2ecf20Sopenharmony_ci		if (err)
8848c2ecf20Sopenharmony_ci			return err;
8858c2ecf20Sopenharmony_ci	}
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	if (enetc_port_has_pcs(pf)) {
8888c2ecf20Sopenharmony_ci		err = enetc_imdio_create(pf);
8898c2ecf20Sopenharmony_ci		if (err) {
8908c2ecf20Sopenharmony_ci			enetc_mdio_remove(pf);
8918c2ecf20Sopenharmony_ci			return err;
8928c2ecf20Sopenharmony_ci		}
8938c2ecf20Sopenharmony_ci	}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	return 0;
8968c2ecf20Sopenharmony_ci}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_cistatic void enetc_mdiobus_destroy(struct enetc_pf *pf)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	enetc_mdio_remove(pf);
9018c2ecf20Sopenharmony_ci	enetc_imdio_remove(pf);
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_cistatic void enetc_pl_mac_validate(struct phylink_config *config,
9058c2ecf20Sopenharmony_ci				  unsigned long *supported,
9068c2ecf20Sopenharmony_ci				  struct phylink_link_state *state)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	if (state->interface != PHY_INTERFACE_MODE_NA &&
9118c2ecf20Sopenharmony_ci	    state->interface != PHY_INTERFACE_MODE_INTERNAL &&
9128c2ecf20Sopenharmony_ci	    state->interface != PHY_INTERFACE_MODE_SGMII &&
9138c2ecf20Sopenharmony_ci	    state->interface != PHY_INTERFACE_MODE_2500BASEX &&
9148c2ecf20Sopenharmony_ci	    state->interface != PHY_INTERFACE_MODE_USXGMII &&
9158c2ecf20Sopenharmony_ci	    !phy_interface_mode_is_rgmii(state->interface)) {
9168c2ecf20Sopenharmony_ci		bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
9178c2ecf20Sopenharmony_ci		return;
9188c2ecf20Sopenharmony_ci	}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	phylink_set_port_modes(mask);
9218c2ecf20Sopenharmony_ci	phylink_set(mask, Autoneg);
9228c2ecf20Sopenharmony_ci	phylink_set(mask, Pause);
9238c2ecf20Sopenharmony_ci	phylink_set(mask, Asym_Pause);
9248c2ecf20Sopenharmony_ci	phylink_set(mask, 10baseT_Half);
9258c2ecf20Sopenharmony_ci	phylink_set(mask, 10baseT_Full);
9268c2ecf20Sopenharmony_ci	phylink_set(mask, 100baseT_Half);
9278c2ecf20Sopenharmony_ci	phylink_set(mask, 100baseT_Full);
9288c2ecf20Sopenharmony_ci	phylink_set(mask, 100baseT_Half);
9298c2ecf20Sopenharmony_ci	phylink_set(mask, 1000baseT_Half);
9308c2ecf20Sopenharmony_ci	phylink_set(mask, 1000baseT_Full);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	if (state->interface == PHY_INTERFACE_MODE_INTERNAL ||
9338c2ecf20Sopenharmony_ci	    state->interface == PHY_INTERFACE_MODE_2500BASEX ||
9348c2ecf20Sopenharmony_ci	    state->interface == PHY_INTERFACE_MODE_USXGMII) {
9358c2ecf20Sopenharmony_ci		phylink_set(mask, 2500baseT_Full);
9368c2ecf20Sopenharmony_ci		phylink_set(mask, 2500baseX_Full);
9378c2ecf20Sopenharmony_ci	}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	bitmap_and(supported, supported, mask,
9408c2ecf20Sopenharmony_ci		   __ETHTOOL_LINK_MODE_MASK_NBITS);
9418c2ecf20Sopenharmony_ci	bitmap_and(state->advertising, state->advertising, mask,
9428c2ecf20Sopenharmony_ci		   __ETHTOOL_LINK_MODE_MASK_NBITS);
9438c2ecf20Sopenharmony_ci}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_cistatic void enetc_pl_mac_config(struct phylink_config *config,
9468c2ecf20Sopenharmony_ci				unsigned int mode,
9478c2ecf20Sopenharmony_ci				const struct phylink_link_state *state)
9488c2ecf20Sopenharmony_ci{
9498c2ecf20Sopenharmony_ci	struct enetc_pf *pf = phylink_to_enetc_pf(config);
9508c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	enetc_mac_config(&pf->si->hw, state->interface);
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	priv = netdev_priv(pf->si->ndev);
9558c2ecf20Sopenharmony_ci	if (pf->pcs)
9568c2ecf20Sopenharmony_ci		phylink_set_pcs(priv->phylink, &pf->pcs->pcs);
9578c2ecf20Sopenharmony_ci}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_cistatic void enetc_force_rgmii_mac(struct enetc_hw *hw, int speed, int duplex)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	u32 old_val, val;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	old_val = val = enetc_port_rd(hw, ENETC_PM0_IF_MODE);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (speed == SPEED_1000) {
9668c2ecf20Sopenharmony_ci		val &= ~ENETC_PM0_IFM_SSP_MASK;
9678c2ecf20Sopenharmony_ci		val |= ENETC_PM0_IFM_SSP_1000;
9688c2ecf20Sopenharmony_ci	} else if (speed == SPEED_100) {
9698c2ecf20Sopenharmony_ci		val &= ~ENETC_PM0_IFM_SSP_MASK;
9708c2ecf20Sopenharmony_ci		val |= ENETC_PM0_IFM_SSP_100;
9718c2ecf20Sopenharmony_ci	} else if (speed == SPEED_10) {
9728c2ecf20Sopenharmony_ci		val &= ~ENETC_PM0_IFM_SSP_MASK;
9738c2ecf20Sopenharmony_ci		val |= ENETC_PM0_IFM_SSP_10;
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	if (duplex == DUPLEX_FULL)
9778c2ecf20Sopenharmony_ci		val |= ENETC_PM0_IFM_FULL_DPX;
9788c2ecf20Sopenharmony_ci	else
9798c2ecf20Sopenharmony_ci		val &= ~ENETC_PM0_IFM_FULL_DPX;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	if (val == old_val)
9828c2ecf20Sopenharmony_ci		return;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	enetc_port_wr(hw, ENETC_PM0_IF_MODE, val);
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cistatic void enetc_pl_mac_link_up(struct phylink_config *config,
9888c2ecf20Sopenharmony_ci				 struct phy_device *phy, unsigned int mode,
9898c2ecf20Sopenharmony_ci				 phy_interface_t interface, int speed,
9908c2ecf20Sopenharmony_ci				 int duplex, bool tx_pause, bool rx_pause)
9918c2ecf20Sopenharmony_ci{
9928c2ecf20Sopenharmony_ci	struct enetc_pf *pf = phylink_to_enetc_pf(config);
9938c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	priv = netdev_priv(pf->si->ndev);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	if (pf->si->hw_features & ENETC_SI_F_QBV)
9988c2ecf20Sopenharmony_ci		enetc_sched_speed_set(priv, speed);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	if (!phylink_autoneg_inband(mode) &&
10018c2ecf20Sopenharmony_ci	    phy_interface_mode_is_rgmii(interface))
10028c2ecf20Sopenharmony_ci		enetc_force_rgmii_mac(&pf->si->hw, speed, duplex);
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	enetc_mac_enable(&pf->si->hw, true);
10058c2ecf20Sopenharmony_ci}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_cistatic void enetc_pl_mac_link_down(struct phylink_config *config,
10088c2ecf20Sopenharmony_ci				   unsigned int mode,
10098c2ecf20Sopenharmony_ci				   phy_interface_t interface)
10108c2ecf20Sopenharmony_ci{
10118c2ecf20Sopenharmony_ci	struct enetc_pf *pf = phylink_to_enetc_pf(config);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	enetc_mac_enable(&pf->si->hw, false);
10148c2ecf20Sopenharmony_ci}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_cistatic const struct phylink_mac_ops enetc_mac_phylink_ops = {
10178c2ecf20Sopenharmony_ci	.validate = enetc_pl_mac_validate,
10188c2ecf20Sopenharmony_ci	.mac_config = enetc_pl_mac_config,
10198c2ecf20Sopenharmony_ci	.mac_link_up = enetc_pl_mac_link_up,
10208c2ecf20Sopenharmony_ci	.mac_link_down = enetc_pl_mac_link_down,
10218c2ecf20Sopenharmony_ci};
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_cistatic int enetc_phylink_create(struct enetc_ndev_priv *priv,
10248c2ecf20Sopenharmony_ci				struct device_node *node)
10258c2ecf20Sopenharmony_ci{
10268c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(priv->si);
10278c2ecf20Sopenharmony_ci	struct phylink *phylink;
10288c2ecf20Sopenharmony_ci	int err;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	pf->phylink_config.dev = &priv->ndev->dev;
10318c2ecf20Sopenharmony_ci	pf->phylink_config.type = PHYLINK_NETDEV;
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
10348c2ecf20Sopenharmony_ci				 pf->if_mode, &enetc_mac_phylink_ops);
10358c2ecf20Sopenharmony_ci	if (IS_ERR(phylink)) {
10368c2ecf20Sopenharmony_ci		err = PTR_ERR(phylink);
10378c2ecf20Sopenharmony_ci		return err;
10388c2ecf20Sopenharmony_ci	}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	priv->phylink = phylink;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	return 0;
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistatic void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
10468c2ecf20Sopenharmony_ci{
10478c2ecf20Sopenharmony_ci	if (priv->phylink)
10488c2ecf20Sopenharmony_ci		phylink_destroy(priv->phylink);
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci/* Initialize the entire shared memory for the flow steering entries
10528c2ecf20Sopenharmony_ci * of this port (PF + VFs)
10538c2ecf20Sopenharmony_ci */
10548c2ecf20Sopenharmony_cistatic int enetc_init_port_rfs_memory(struct enetc_si *si)
10558c2ecf20Sopenharmony_ci{
10568c2ecf20Sopenharmony_ci	struct enetc_cmd_rfse rfse = {0};
10578c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
10588c2ecf20Sopenharmony_ci	int num_rfs, i, err = 0;
10598c2ecf20Sopenharmony_ci	u32 val;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	val = enetc_port_rd(hw, ENETC_PRFSCAPR);
10628c2ecf20Sopenharmony_ci	num_rfs = ENETC_PRFSCAPR_GET_NUM_RFS(val);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	for (i = 0; i < num_rfs; i++) {
10658c2ecf20Sopenharmony_ci		err = enetc_set_fs_entry(si, &rfse, i);
10668c2ecf20Sopenharmony_ci		if (err)
10678c2ecf20Sopenharmony_ci			break;
10688c2ecf20Sopenharmony_ci	}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	return err;
10718c2ecf20Sopenharmony_ci}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_cistatic int enetc_init_port_rss_memory(struct enetc_si *si)
10748c2ecf20Sopenharmony_ci{
10758c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
10768c2ecf20Sopenharmony_ci	int num_rss, err;
10778c2ecf20Sopenharmony_ci	int *rss_table;
10788c2ecf20Sopenharmony_ci	u32 val;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	val = enetc_port_rd(hw, ENETC_PRSSCAPR);
10818c2ecf20Sopenharmony_ci	num_rss = ENETC_PRSSCAPR_GET_NUM_RSS(val);
10828c2ecf20Sopenharmony_ci	if (!num_rss)
10838c2ecf20Sopenharmony_ci		return 0;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	rss_table = kcalloc(num_rss, sizeof(*rss_table), GFP_KERNEL);
10868c2ecf20Sopenharmony_ci	if (!rss_table)
10878c2ecf20Sopenharmony_ci		return -ENOMEM;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	err = enetc_set_rss_table(si, rss_table, num_rss);
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	kfree(rss_table);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	return err;
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cistatic void enetc_init_unused_port(struct enetc_si *si)
10978c2ecf20Sopenharmony_ci{
10988c2ecf20Sopenharmony_ci	struct device *dev = &si->pdev->dev;
10998c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
11008c2ecf20Sopenharmony_ci	int err;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	si->cbd_ring.bd_count = ENETC_CBDR_DEFAULT_SIZE;
11038c2ecf20Sopenharmony_ci	err = enetc_alloc_cbdr(dev, &si->cbd_ring);
11048c2ecf20Sopenharmony_ci	if (err)
11058c2ecf20Sopenharmony_ci		return;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	enetc_setup_cbdr(hw, &si->cbd_ring);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	enetc_init_port_rfs_memory(si);
11108c2ecf20Sopenharmony_ci	enetc_init_port_rss_memory(si);
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	enetc_clear_cbdr(hw);
11138c2ecf20Sopenharmony_ci	enetc_free_cbdr(dev, &si->cbd_ring);
11148c2ecf20Sopenharmony_ci}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_cistatic int enetc_pf_probe(struct pci_dev *pdev,
11178c2ecf20Sopenharmony_ci			  const struct pci_device_id *ent)
11188c2ecf20Sopenharmony_ci{
11198c2ecf20Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
11208c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv;
11218c2ecf20Sopenharmony_ci	struct net_device *ndev;
11228c2ecf20Sopenharmony_ci	struct enetc_si *si;
11238c2ecf20Sopenharmony_ci	struct enetc_pf *pf;
11248c2ecf20Sopenharmony_ci	int err;
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf));
11278c2ecf20Sopenharmony_ci	if (err) {
11288c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "PCI probing failed\n");
11298c2ecf20Sopenharmony_ci		return err;
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	si = pci_get_drvdata(pdev);
11338c2ecf20Sopenharmony_ci	if (!si->hw.port || !si->hw.global) {
11348c2ecf20Sopenharmony_ci		err = -ENODEV;
11358c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "could not map PF space, probing a VF?\n");
11368c2ecf20Sopenharmony_ci		goto err_map_pf_space;
11378c2ecf20Sopenharmony_ci	}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	if (node && !of_device_is_available(node)) {
11408c2ecf20Sopenharmony_ci		enetc_init_unused_port(si);
11418c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "device is disabled, skipping\n");
11428c2ecf20Sopenharmony_ci		err = -ENODEV;
11438c2ecf20Sopenharmony_ci		goto err_device_disabled;
11448c2ecf20Sopenharmony_ci	}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	pf = enetc_si_priv(si);
11478c2ecf20Sopenharmony_ci	pf->si = si;
11488c2ecf20Sopenharmony_ci	pf->total_vfs = pci_sriov_get_totalvfs(pdev);
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	enetc_configure_port(pf);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	enetc_get_si_caps(si);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	ndev = alloc_etherdev_mq(sizeof(*priv), ENETC_MAX_NUM_TXQS);
11558c2ecf20Sopenharmony_ci	if (!ndev) {
11568c2ecf20Sopenharmony_ci		err = -ENOMEM;
11578c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "netdev creation failed\n");
11588c2ecf20Sopenharmony_ci		goto err_alloc_netdev;
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	enetc_pf_netdev_setup(si, ndev, &enetc_ndev_ops);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	priv = netdev_priv(ndev);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	enetc_init_si_rings_params(priv);
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	err = enetc_alloc_si_resources(priv);
11688c2ecf20Sopenharmony_ci	if (err) {
11698c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "SI resource alloc failed\n");
11708c2ecf20Sopenharmony_ci		goto err_alloc_si_res;
11718c2ecf20Sopenharmony_ci	}
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	err = enetc_init_port_rfs_memory(si);
11748c2ecf20Sopenharmony_ci	if (err) {
11758c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Failed to initialize RFS memory\n");
11768c2ecf20Sopenharmony_ci		goto err_init_port_rfs;
11778c2ecf20Sopenharmony_ci	}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	err = enetc_init_port_rss_memory(si);
11808c2ecf20Sopenharmony_ci	if (err) {
11818c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Failed to initialize RSS memory\n");
11828c2ecf20Sopenharmony_ci		goto err_init_port_rss;
11838c2ecf20Sopenharmony_ci	}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	err = enetc_configure_si(priv);
11868c2ecf20Sopenharmony_ci	if (err) {
11878c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Failed to configure SI\n");
11888c2ecf20Sopenharmony_ci		goto err_config_si;
11898c2ecf20Sopenharmony_ci	}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	err = enetc_alloc_msix(priv);
11928c2ecf20Sopenharmony_ci	if (err) {
11938c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "MSIX alloc failed\n");
11948c2ecf20Sopenharmony_ci		goto err_alloc_msix;
11958c2ecf20Sopenharmony_ci	}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	if (!of_get_phy_mode(node, &pf->if_mode)) {
11988c2ecf20Sopenharmony_ci		err = enetc_mdiobus_create(pf, node);
11998c2ecf20Sopenharmony_ci		if (err)
12008c2ecf20Sopenharmony_ci			goto err_mdiobus_create;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci		err = enetc_phylink_create(priv, node);
12038c2ecf20Sopenharmony_ci		if (err)
12048c2ecf20Sopenharmony_ci			goto err_phylink_create;
12058c2ecf20Sopenharmony_ci	}
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	err = register_netdev(ndev);
12088c2ecf20Sopenharmony_ci	if (err)
12098c2ecf20Sopenharmony_ci		goto err_reg_netdev;
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	return 0;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_cierr_reg_netdev:
12148c2ecf20Sopenharmony_ci	enetc_phylink_destroy(priv);
12158c2ecf20Sopenharmony_cierr_phylink_create:
12168c2ecf20Sopenharmony_ci	enetc_mdiobus_destroy(pf);
12178c2ecf20Sopenharmony_cierr_mdiobus_create:
12188c2ecf20Sopenharmony_ci	enetc_free_msix(priv);
12198c2ecf20Sopenharmony_cierr_config_si:
12208c2ecf20Sopenharmony_cierr_init_port_rss:
12218c2ecf20Sopenharmony_cierr_init_port_rfs:
12228c2ecf20Sopenharmony_cierr_alloc_msix:
12238c2ecf20Sopenharmony_ci	enetc_free_si_resources(priv);
12248c2ecf20Sopenharmony_cierr_alloc_si_res:
12258c2ecf20Sopenharmony_ci	si->ndev = NULL;
12268c2ecf20Sopenharmony_ci	free_netdev(ndev);
12278c2ecf20Sopenharmony_cierr_alloc_netdev:
12288c2ecf20Sopenharmony_cierr_device_disabled:
12298c2ecf20Sopenharmony_cierr_map_pf_space:
12308c2ecf20Sopenharmony_ci	enetc_pci_remove(pdev);
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	return err;
12338c2ecf20Sopenharmony_ci}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_cistatic void enetc_pf_remove(struct pci_dev *pdev)
12368c2ecf20Sopenharmony_ci{
12378c2ecf20Sopenharmony_ci	struct enetc_si *si = pci_get_drvdata(pdev);
12388c2ecf20Sopenharmony_ci	struct enetc_pf *pf = enetc_si_priv(si);
12398c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	priv = netdev_priv(si->ndev);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	if (pf->num_vfs)
12448c2ecf20Sopenharmony_ci		enetc_sriov_configure(pdev, 0);
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	unregister_netdev(si->ndev);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	enetc_phylink_destroy(priv);
12498c2ecf20Sopenharmony_ci	enetc_mdiobus_destroy(pf);
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	enetc_free_msix(priv);
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	enetc_free_si_resources(priv);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	free_netdev(si->ndev);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	enetc_pci_remove(pdev);
12588c2ecf20Sopenharmony_ci}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistatic const struct pci_device_id enetc_pf_id_table[] = {
12618c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF) },
12628c2ecf20Sopenharmony_ci	{ 0, } /* End of table. */
12638c2ecf20Sopenharmony_ci};
12648c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, enetc_pf_id_table);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cistatic struct pci_driver enetc_pf_driver = {
12678c2ecf20Sopenharmony_ci	.name = KBUILD_MODNAME,
12688c2ecf20Sopenharmony_ci	.id_table = enetc_pf_id_table,
12698c2ecf20Sopenharmony_ci	.probe = enetc_pf_probe,
12708c2ecf20Sopenharmony_ci	.remove = enetc_pf_remove,
12718c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
12728c2ecf20Sopenharmony_ci	.sriov_configure = enetc_sriov_configure,
12738c2ecf20Sopenharmony_ci#endif
12748c2ecf20Sopenharmony_ci};
12758c2ecf20Sopenharmony_cimodule_pci_driver(enetc_pf_driver);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(ENETC_DRV_NAME_STR);
12788c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
1279