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