diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index 04a5dd5ea6c7..8839cfb49bcf 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* Copyright 2017-2019 NXP */ +/* Copyright 2017-2019, 2025-2026 NXP */ #include #include @@ -324,8 +324,6 @@ struct enetc_si { const struct enetc_drvdata *drvdata; const struct enetc_si_ops *ops; - struct workqueue_struct *workqueue; - struct work_struct rx_mode_task; struct dentry *debugfs_root; struct enetc_msg_swbd msg; /* Only valid for VSI */ }; diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c index 1b1591dce73d..5029038bf99f 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c +++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c @@ -28,15 +28,14 @@ static void enetc_show_si_mac_hash_filter(struct seq_file *s, int i) static int enetc_mac_filter_show(struct seq_file *s, void *data) { - struct enetc_si *si = s->private; - struct enetc_hw *hw = &si->hw; + struct enetc_pf *pf = enetc_si_priv(s->private); + struct enetc_hw *hw = &pf->si->hw; + int num_si = pf->total_vfs + 1; struct maft_entry_data maft; - struct enetc_pf *pf; - int i, err, num_si; - u32 val; - - pf = enetc_si_priv(si); - num_si = pf->caps.num_vsi + 1; + struct ntmp_user *user; + u32 val, entry_id; + int err = 0; + int i; val = enetc_port_rd(hw, ENETC4_PSIPMMR); for (i = 0; i < num_si; i++) { @@ -50,31 +49,38 @@ static int enetc_mac_filter_show(struct seq_file *s, void *data) for (i = 0; i < num_si; i++) enetc_show_si_mac_hash_filter(s, i); - if (!pf->num_mfe) - return 0; + user = &pf->si->ntmp_user; + rtnl_lock(); + + if (bitmap_empty(user->maft_eid_bitmap, user->maft_num_entries)) + goto unlock_rtnl; /* MAC address filter table */ seq_puts(s, "MAC address filter table\n"); - for (i = 0; i < pf->num_mfe; i++) { + for_each_set_bit(entry_id, user->maft_eid_bitmap, + user->maft_num_entries) { memset(&maft, 0, sizeof(maft)); - err = ntmp_maft_query_entry(&si->ntmp_user, i, &maft); + err = ntmp_maft_query_entry(user, entry_id, &maft); if (err) - return err; + goto unlock_rtnl; - seq_printf(s, "Entry %d, MAC: %pM, SI bitmap: 0x%04x\n", i, - maft.keye.mac_addr, le16_to_cpu(maft.cfge.si_bitmap)); + seq_printf(s, "Entry %d, MAC: %pM, SI bitmap: 0x%04x\n", + entry_id, maft.keye.mac_addr, + le16_to_cpu(maft.cfge.si_bitmap)); } - return 0; +unlock_rtnl: + rtnl_unlock(); + + return err; } DEFINE_SHOW_ATTRIBUTE(enetc_mac_filter); void enetc_create_debugfs(struct enetc_si *si) { - struct net_device *ndev = si->ndev; struct dentry *root; - root = debugfs_create_dir(netdev_name(ndev), NULL); + root = debugfs_create_dir(pci_name(si->pdev), NULL); if (IS_ERR(root)) return; diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h index f18437556a0e..09025e7a2a3a 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h +++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h @@ -69,8 +69,6 @@ /* Port Station interface promiscuous MAC mode register */ #define ENETC4_PSIPMMR 0x200 -#define PSIPMMR_SI_MAC_UP(a) BIT(a) /* a = SI index */ -#define PSIPMMR_SI_MAC_MP(a) BIT((a) + 16) /* Port Station interface promiscuous VLAN mode register */ #define ENETC4_PSIPVMR 0x204 @@ -137,7 +135,6 @@ #define ENETC4_PSIVHFR1(a) ((a) * 0x80 + 0x2064) #define ENETC4_PMCAPR 0x4004 -#define PMCAPR_HD BIT(8) #define PMCAPR_FP GENMASK(10, 9) /* Port capability register */ @@ -150,7 +147,7 @@ #define PCR_L2DOSE BIT(4) #define PCR_TIMER_CS BIT(8) #define PCR_PSPEED GENMASK(29, 16) -#define PCR_PSPEED_VAL(speed) (((speed) / 10 - 1) << 16) +#define PCR_PSPEED_VAL(s) FIELD_PREP(PCR_PSPEED, ((s) / 10 - 1)) /* Port MAC address register 0/1 */ #define ENETC4_PMAR0 0x4020 @@ -200,7 +197,6 @@ #define PM_CMD_CFG_CNT_FRM_EN BIT(13) #define PM_CMD_CFG_TXP BIT(15) #define PM_CMD_CFG_SEND_IDLE BIT(16) -#define PM_CMD_CFG_HD_FCEN BIT(18) #define PM_CMD_CFG_SFD BIT(21) #define PM_CMD_CFG_TX_FLUSH BIT(22) #define PM_CMD_CFG_TX_LOWP_EN BIT(23) diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c index 437a15bbb47b..fcfbabb29d22 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c @@ -23,18 +23,11 @@ static void enetc4_get_port_caps(struct enetc_pf *pf) u32 val; val = enetc_port_rd(hw, ENETC4_ECAPR1); - pf->caps.num_vsi = (val & ECAPR1_NUM_VSI) >> 24; pf->caps.num_msix = ((val & ECAPR1_NUM_MSIX) >> 12) + 1; val = enetc_port_rd(hw, ENETC4_ECAPR2); pf->caps.num_rx_bdr = (val & ECAPR2_NUM_RX_BDR) >> 16; pf->caps.num_tx_bdr = val & ECAPR2_NUM_TX_BDR; - - val = enetc_port_rd(hw, ENETC4_PMCAPR); - pf->caps.half_duplex = (val & PMCAPR_HD) ? 1 : 0; - - val = enetc_port_rd(hw, ENETC4_PSIMAFCAPR); - pf->caps.mac_filter_num = val & PSIMAFCAPR_NUM_MAC_AFTE; } static void enetc4_get_psi_hw_features(struct enetc_si *si) @@ -75,38 +68,6 @@ static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si, put_unaligned_le16(lower, addr + 4); } -static void enetc4_pf_set_si_mac_promisc(struct enetc_hw *hw, int si, - bool uc_promisc, bool mc_promisc) -{ - u32 val = enetc_port_rd(hw, ENETC4_PSIPMMR); - - if (uc_promisc) - val |= PSIPMMR_SI_MAC_UP(si); - else - val &= ~PSIPMMR_SI_MAC_UP(si); - - if (mc_promisc) - val |= PSIPMMR_SI_MAC_MP(si); - else - val &= ~PSIPMMR_SI_MAC_MP(si); - - enetc_port_wr(hw, ENETC4_PSIPMMR, val); -} - -static void enetc4_pf_set_si_uc_hash_filter(struct enetc_hw *hw, int si, - u64 hash) -{ - enetc_port_wr(hw, ENETC4_PSIUMHFR0(si), lower_32_bits(hash)); - enetc_port_wr(hw, ENETC4_PSIUMHFR1(si), upper_32_bits(hash)); -} - -static void enetc4_pf_set_si_mc_hash_filter(struct enetc_hw *hw, int si, - u64 hash) -{ - enetc_port_wr(hw, ENETC4_PSIMMHFR0(si), lower_32_bits(hash)); - enetc_port_wr(hw, ENETC4_PSIMMHFR1(si), upper_32_bits(hash)); -} - static void enetc4_pf_set_loopback(struct net_device *ndev, bool en) { struct enetc_ndev_priv *priv = netdev_priv(ndev); @@ -124,34 +85,47 @@ static void enetc4_pf_set_loopback(struct net_device *ndev, bool en) static void enetc4_pf_clear_maft_entries(struct enetc_pf *pf) { - int i; + struct ntmp_user *user = &pf->si->ntmp_user; + u32 entry_id; - for (i = 0; i < pf->num_mfe; i++) - ntmp_maft_delete_entry(&pf->si->ntmp_user, i); - - pf->num_mfe = 0; + for_each_set_bit(entry_id, user->maft_eid_bitmap, + user->maft_num_entries) { + if (!ntmp_maft_delete_entry(user, entry_id)) + ntmp_clear_eid_bitmap(user->maft_eid_bitmap, entry_id); + } } static int enetc4_pf_add_maft_entries(struct enetc_pf *pf, - struct enetc_mac_addr *mac, - int mac_cnt) + struct netdev_hw_addr_list *uc) { + struct ntmp_user *user = &pf->si->ntmp_user; + int mac_cnt = netdev_hw_addr_list_count(uc); struct maft_entry_data maft = {}; + struct netdev_hw_addr *ha; + u32 available_entries; u16 si_bit = BIT(0); - int i, err; + u32 entry_id; + int err; + + available_entries = user->maft_num_entries - + bitmap_weight(user->maft_eid_bitmap, + user->maft_num_entries); + + if (mac_cnt > available_entries) + return -ENOSPC; maft.cfge.si_bitmap = cpu_to_le16(si_bit); - for (i = 0; i < mac_cnt; i++) { - ether_addr_copy(maft.keye.mac_addr, mac[i].addr); - err = ntmp_maft_add_entry(&pf->si->ntmp_user, i, &maft); + netdev_hw_addr_list_for_each(ha, uc) { + entry_id = ntmp_lookup_free_eid(user->maft_eid_bitmap, + user->maft_num_entries); + ether_addr_copy(maft.keye.mac_addr, ha->addr); + err = ntmp_maft_add_entry(user, entry_id, &maft); if (unlikely(err)) { - pf->num_mfe = i; + ntmp_clear_eid_bitmap(user->maft_eid_bitmap, entry_id); goto clear_maft_entries; } } - pf->num_mfe = mac_cnt; - return 0; clear_maft_entries: @@ -160,97 +134,70 @@ static int enetc4_pf_add_maft_entries(struct enetc_pf *pf, return err; } -static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf) +static void enetc4_pf_set_uc_hash_filter(struct enetc_pf *pf, + struct netdev_hw_addr_list *uc) { - int max_num_mfe = pf->caps.mac_filter_num; - struct enetc_mac_filter mac_filter = {}; - struct net_device *ndev = pf->si->ndev; - struct enetc_hw *hw = &pf->si->hw; - struct enetc_mac_addr *mac_tbl; + struct enetc_mac_filter *mac_filter = &pf->mac_filter[UC]; struct netdev_hw_addr *ha; - int i = 0, err; - int mac_cnt; + u64 hash; - netif_addr_lock_bh(ndev); + enetc_reset_mac_addr_filter(mac_filter); + netdev_hw_addr_list_for_each(ha, uc) + enetc_add_mac_addr_ht_filter(mac_filter, ha->addr); - mac_cnt = netdev_uc_count(ndev); - if (!mac_cnt) { - netif_addr_unlock_bh(ndev); + bitmap_to_arr64(&hash, mac_filter->mac_hash_table, + ENETC_MADDR_HASH_TBL_SZ); + enetc_set_si_uc_hash_filter(pf->si, 0, hash); +} + +static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf, + struct netdev_hw_addr_list *uc) +{ + struct enetc_si *si = pf->si; + int err; + + if (netdev_hw_addr_list_empty(uc)) { /* clear both MAC hash and exact filters */ - enetc4_pf_set_si_uc_hash_filter(hw, 0, 0); + enetc_set_si_uc_hash_filter(si, 0, 0); enetc4_pf_clear_maft_entries(pf); return 0; } - if (mac_cnt > max_num_mfe) { - err = -ENOSPC; - goto unlock_netif_addr; - } - - mac_tbl = kzalloc_objs(*mac_tbl, mac_cnt, GFP_ATOMIC); - if (!mac_tbl) { - err = -ENOMEM; - goto unlock_netif_addr; - } - - netdev_for_each_uc_addr(ha, ndev) { - enetc_add_mac_addr_ht_filter(&mac_filter, ha->addr); - ether_addr_copy(mac_tbl[i++].addr, ha->addr); - } - - netif_addr_unlock_bh(ndev); - - /* Set temporary unicast hash filters in case of Rx loss when + /* Set temporary unicast hash filter in case of Rx loss when * updating MAC address filter table */ - enetc4_pf_set_si_uc_hash_filter(hw, 0, *mac_filter.mac_hash_table); + enetc4_pf_set_uc_hash_filter(pf, uc); enetc4_pf_clear_maft_entries(pf); - if (!enetc4_pf_add_maft_entries(pf, mac_tbl, i)) - enetc4_pf_set_si_uc_hash_filter(hw, 0, 0); - - kfree(mac_tbl); - - return 0; - -unlock_netif_addr: - netif_addr_unlock_bh(ndev); + err = enetc4_pf_add_maft_entries(pf, uc); + if (!err) { + enetc_reset_mac_addr_filter(&pf->mac_filter[UC]); + enetc_set_si_uc_hash_filter(si, 0, 0); + } return err; } -static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type) +static void enetc4_pf_set_mc_hash_filter(struct enetc_pf *pf, + struct netdev_hw_addr_list *mc) { - struct net_device *ndev = pf->si->ndev; - struct enetc_mac_filter *mac_filter; - struct enetc_hw *hw = &pf->si->hw; + struct enetc_mac_filter *mac_filter = &pf->mac_filter[MC]; struct netdev_hw_addr *ha; + u64 hash; - netif_addr_lock_bh(ndev); - if (type & ENETC_MAC_FILTER_TYPE_UC) { - mac_filter = &pf->mac_filter[UC]; - enetc_reset_mac_addr_filter(mac_filter); - netdev_for_each_uc_addr(ha, ndev) - enetc_add_mac_addr_ht_filter(mac_filter, ha->addr); + enetc_reset_mac_addr_filter(mac_filter); + netdev_hw_addr_list_for_each(ha, mc) + enetc_add_mac_addr_ht_filter(mac_filter, ha->addr); - enetc4_pf_set_si_uc_hash_filter(hw, 0, - *mac_filter->mac_hash_table); - } - - if (type & ENETC_MAC_FILTER_TYPE_MC) { - mac_filter = &pf->mac_filter[MC]; - enetc_reset_mac_addr_filter(mac_filter); - netdev_for_each_mc_addr(ha, ndev) - enetc_add_mac_addr_ht_filter(mac_filter, ha->addr); - - enetc4_pf_set_si_mc_hash_filter(hw, 0, - *mac_filter->mac_hash_table); - } - netif_addr_unlock_bh(ndev); + bitmap_to_arr64(&hash, mac_filter->mac_hash_table, + ENETC_MADDR_HASH_TBL_SZ); + enetc_set_si_mc_hash_filter(pf->si, 0, hash); } -static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type) +static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type, + struct netdev_hw_addr_list *uc, + struct netdev_hw_addr_list *mc) { /* Currently, the MAC address filter table (MAFT) only has 4 entries, * and multiple multicast addresses for filtering will be configured @@ -258,15 +205,16 @@ static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type) * unicast filtering. If the number of unicast addresses exceeds the * table capacity, the MAC hash filter will be used. */ - if (type & ENETC_MAC_FILTER_TYPE_UC && enetc4_pf_set_uc_exact_filter(pf)) { + if (type & ENETC_MAC_FILTER_TYPE_UC && + enetc4_pf_set_uc_exact_filter(pf, uc)) { /* Fall back to the MAC hash filter */ - enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_UC); + enetc4_pf_set_uc_hash_filter(pf, uc); /* Clear the old MAC exact filter */ enetc4_pf_clear_maft_entries(pf); } if (type & ENETC_MAC_FILTER_TYPE_MC) - enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_MC); + enetc4_pf_set_mc_hash_filter(pf, mc); } static const struct enetc_pf_ops enetc4_pf_ops = { @@ -306,34 +254,35 @@ static void enetc4_default_rings_allocation(struct enetc_pf *pf) { struct enetc_hw *hw = &pf->si->hw; u32 num_rx_bdr, num_tx_bdr, val; + int num_vfs = pf->total_vfs; u32 vf_tx_bdr, vf_rx_bdr; int i, rx_rem, tx_rem; - if (pf->caps.num_rx_bdr < ENETC_SI_MAX_RING_NUM + pf->caps.num_vsi) - num_rx_bdr = pf->caps.num_rx_bdr - pf->caps.num_vsi; + if (pf->caps.num_rx_bdr < ENETC_SI_MAX_RING_NUM + num_vfs) + num_rx_bdr = pf->caps.num_rx_bdr - num_vfs; else num_rx_bdr = ENETC_SI_MAX_RING_NUM; - if (pf->caps.num_tx_bdr < ENETC_SI_MAX_RING_NUM + pf->caps.num_vsi) - num_tx_bdr = pf->caps.num_tx_bdr - pf->caps.num_vsi; + if (pf->caps.num_tx_bdr < ENETC_SI_MAX_RING_NUM + num_vfs) + num_tx_bdr = pf->caps.num_tx_bdr - num_vfs; else num_tx_bdr = ENETC_SI_MAX_RING_NUM; val = enetc4_psicfgr0_val_construct(false, num_tx_bdr, num_rx_bdr); enetc_port_wr(hw, ENETC4_PSICFGR0(0), val); - if (!pf->caps.num_vsi) + if (!num_vfs) return; num_rx_bdr = pf->caps.num_rx_bdr - num_rx_bdr; - rx_rem = num_rx_bdr % pf->caps.num_vsi; - num_rx_bdr = num_rx_bdr / pf->caps.num_vsi; + rx_rem = num_rx_bdr % num_vfs; + num_rx_bdr = num_rx_bdr / num_vfs; num_tx_bdr = pf->caps.num_tx_bdr - num_tx_bdr; - tx_rem = num_tx_bdr % pf->caps.num_vsi; - num_tx_bdr = num_tx_bdr / pf->caps.num_vsi; + tx_rem = num_tx_bdr % num_vfs; + num_tx_bdr = num_tx_bdr / num_vfs; - for (i = 0; i < pf->caps.num_vsi; i++) { + for (i = 0; i < num_vfs; i++) { vf_tx_bdr = (i < tx_rem) ? num_tx_bdr + 1 : num_tx_bdr; vf_rx_bdr = (i < rx_rem) ? num_rx_bdr + 1 : num_rx_bdr; val = enetc4_psicfgr0_val_construct(true, vf_tx_bdr, vf_rx_bdr); @@ -346,53 +295,70 @@ static void enetc4_allocate_si_rings(struct enetc_pf *pf) enetc4_default_rings_allocation(pf); } -static void enetc4_pf_set_si_vlan_promisc(struct enetc_hw *hw, int si, bool en) -{ - u32 val = enetc_port_rd(hw, ENETC4_PSIPVMR); - - if (en) - val |= BIT(si); - else - val &= ~BIT(si); - - enetc_port_wr(hw, ENETC4_PSIPVMR, val); -} - -static void enetc4_set_default_si_vlan_promisc(struct enetc_pf *pf) -{ - struct enetc_hw *hw = &pf->si->hw; - int num_si = pf->caps.num_vsi + 1; - int i; - - /* enforce VLAN promiscuous mode for all SIs */ - for (i = 0; i < num_si; i++) - enetc4_pf_set_si_vlan_promisc(hw, i, true); -} - /* Allocate the number of MSI-X vectors for per SI. */ static void enetc4_set_si_msix_num(struct enetc_pf *pf) { + int valid_num_si = pf->total_vfs + 1; struct enetc_hw *hw = &pf->si->hw; - int i, num_msix, total_si; + int i, num_msix, num_vsi; u32 val; - total_si = pf->caps.num_vsi + 1; + val = enetc_port_rd(hw, ENETC4_ECAPR1); + num_vsi = FIELD_GET(ECAPR1_NUM_VSI, val); - num_msix = pf->caps.num_msix / total_si + - pf->caps.num_msix % total_si - 1; - val = num_msix & PSICFGR2_NUM_MSIX; - enetc_port_wr(hw, ENETC4_PSICFGR2(0), val); + /* The PSIaCFGR2[NUM_MSIX] indicates the number of MSI-X allocated to + * the SI is NUM_MSIX + 1, so the minimum number of MSI-X allocated to + * each SI is 1. The total number of MSI-X allocated to PSI and VSIs + * cannot exceed the total number of MSI-X owned by this ENETC, which + * is ECAPR1[NUM_MSIX]. Otherwise, when multiple ENETC instances exist, + * it will affect other ENETCs whose MSI-X interrupts cannot be + * generated. This is similar to out-of-bounds array access: the array + * itself is not affected, but adjacent arrays will be corrupted. + * + * pf->total_vfs is 0 if CONFIG_PCI_IOV is disabled. If the hardware + * itself supports SR-IOV, then when allocating the number of MSIXs to + * the SI, it must be taken into account that the VSI has at least 1 + * MSIX, and the total number of MSIXs of all SIs cannot exceed + * ECAPR1[NUM_MSIX]. + */ + if (!pf->total_vfs && num_vsi) { + /* Because each SI has at least one MSIX, and from the hardware + * perspective, pf->caps.num_msix will always be greater than + * num_vsi. So num_msix is always greater than or equal to 0. + */ + num_msix = pf->caps.num_msix - num_vsi - 1; + if (num_msix > PSICFGR2_NUM_MSIX) + num_msix = PSICFGR2_NUM_MSIX; + enetc_port_wr(hw, ENETC4_PSICFGR2(0), num_msix); - num_msix = pf->caps.num_msix / total_si - 1; - val = num_msix & PSICFGR2_NUM_MSIX; - for (i = 0; i < pf->caps.num_vsi; i++) - enetc_port_wr(hw, ENETC4_PSICFGR2(i + 1), val); + for (i = 0; i < num_vsi; i++) + enetc_port_wr(hw, ENETC4_PSICFGR2(i + 1), 0); + + return; + } + + /* Likewise, from the hardware perspective pf->caps.num_msix is always + * greater than valid_num_si. So num_msix is always greater than or + * equal to 0. + */ + num_msix = pf->caps.num_msix / valid_num_si + + pf->caps.num_msix % valid_num_si - 1; + if (num_msix > PSICFGR2_NUM_MSIX) + num_msix = PSICFGR2_NUM_MSIX; + enetc_port_wr(hw, ENETC4_PSICFGR2(0), num_msix); + + num_msix = pf->caps.num_msix / valid_num_si - 1; + if (num_msix > PSICFGR2_NUM_MSIX) + num_msix = PSICFGR2_NUM_MSIX; + + for (i = 0; i < pf->total_vfs; i++) + enetc_port_wr(hw, ENETC4_PSICFGR2(i + 1), num_msix); } static void enetc4_enable_all_si(struct enetc_pf *pf) { struct enetc_hw *hw = &pf->si->hw; - int num_si = pf->caps.num_vsi + 1; + int num_si = pf->total_vfs + 1; u32 si_bitmap = 0; int i; @@ -412,7 +378,9 @@ static void enetc4_configure_port_si(struct enetc_pf *pf) /* Outer VLAN tag will be used for VLAN filtering */ enetc_port_wr(hw, ENETC4_PSIVLANFMR, PSIVLANFMR_VS); - enetc4_set_default_si_vlan_promisc(pf); + /* Enforce VLAN promiscuous mode for all SIs */ + for (int i = 0; i < pf->total_vfs + 1; i++) + enetc_set_si_vlan_promisc(pf->si, i, true); /* Disable SI MAC multicast & unicast promiscuous */ enetc_port_wr(hw, ENETC4_PSIPMMR, 0); @@ -450,18 +418,60 @@ static void enetc4_configure_port(struct enetc_pf *pf) enetc_set_default_rss_key(pf); } +static void enetc4_get_ntmp_caps(struct enetc_si *si) +{ + struct ntmp_user *user = &si->ntmp_user; + struct enetc_hw *hw = &si->hw; + u32 val; + + val = enetc_port_rd(hw, ENETC4_PSIMAFCAPR); + user->maft_num_entries = FIELD_GET(PSIMAFCAPR_NUM_MAC_AFTE, val); +} + +static int enetc4_ntmp_bitmap_init(struct ntmp_user *user) +{ + user->maft_eid_bitmap = bitmap_zalloc(user->maft_num_entries, + GFP_KERNEL); + if (!user->maft_eid_bitmap) + return -ENOMEM; + + return 0; +} + +static void enetc4_ntmp_bitmap_free(struct ntmp_user *user) +{ + bitmap_free(user->maft_eid_bitmap); + user->maft_eid_bitmap = NULL; +} + static int enetc4_init_ntmp_user(struct enetc_si *si) { struct ntmp_user *user = &si->ntmp_user; + int err; /* For ENETC 4.1, all table versions are 0 */ memset(&user->tbl, 0, sizeof(user->tbl)); - return enetc4_setup_cbdr(si); + err = enetc4_setup_cbdr(si); + if (err) + return err; + + enetc4_get_ntmp_caps(si); + err = enetc4_ntmp_bitmap_init(user); + if (err) + goto teardown_cbdr; + + return 0; + +teardown_cbdr: + enetc4_teardown_cbdr(si); + + return err; } static void enetc4_free_ntmp_user(struct enetc_si *si) { + enetc4_ntmp_bitmap_free(&si->ntmp_user); enetc4_teardown_cbdr(si); } @@ -479,7 +489,7 @@ static int enetc4_pf_init(struct enetc_pf *pf) err = enetc4_init_ntmp_user(pf->si); if (err) { - dev_err(dev, "Failed to init CBDR\n"); + dev_err(dev, "Failed to init NTMP user\n"); return err; } @@ -493,18 +503,17 @@ static void enetc4_pf_free(struct enetc_pf *pf) enetc4_free_ntmp_user(pf->si); } -static void enetc4_psi_do_set_rx_mode(struct work_struct *work) +static int enetc4_pf_set_rx_mode(struct net_device *ndev, + struct netdev_hw_addr_list *uc, + struct netdev_hw_addr_list *mc) { - struct enetc_si *si = container_of(work, struct enetc_si, rx_mode_task); - struct enetc_pf *pf = enetc_si_priv(si); - struct net_device *ndev = si->ndev; - struct enetc_hw *hw = &si->hw; + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct enetc_pf *pf = enetc_si_priv(priv->si); + struct enetc_si *si = priv->si; bool uc_promisc = false; bool mc_promisc = false; int type = 0; - rtnl_lock(); - if (ndev->flags & IFF_PROMISC) { uc_promisc = true; mc_promisc = true; @@ -515,28 +524,21 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work) type = ENETC_MAC_FILTER_TYPE_ALL; } - enetc4_pf_set_si_mac_promisc(hw, 0, uc_promisc, mc_promisc); + enetc_set_si_uc_promisc(si, 0, uc_promisc); + enetc_set_si_mc_promisc(si, 0, mc_promisc); if (uc_promisc) { - enetc4_pf_set_si_uc_hash_filter(hw, 0, 0); + enetc_set_si_uc_hash_filter(si, 0, 0); enetc4_pf_clear_maft_entries(pf); } if (mc_promisc) - enetc4_pf_set_si_mc_hash_filter(hw, 0, 0); + enetc_set_si_mc_hash_filter(si, 0, 0); /* Set new MAC filter */ - enetc4_pf_set_mac_filter(pf, type); + enetc4_pf_set_mac_filter(pf, type, uc, mc); - rtnl_unlock(); -} - -static void enetc4_pf_set_rx_mode(struct net_device *ndev) -{ - struct enetc_ndev_priv *priv = netdev_priv(ndev); - struct enetc_si *si = priv->si; - - queue_work(si->workqueue, &si->rx_mode_task); + return 0; } static int enetc4_pf_set_features(struct net_device *ndev, @@ -544,12 +546,11 @@ static int enetc4_pf_set_features(struct net_device *ndev, { netdev_features_t changed = ndev->features ^ features; struct enetc_ndev_priv *priv = netdev_priv(ndev); - struct enetc_hw *hw = &priv->si->hw; if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) { bool promisc_en = !(features & NETIF_F_HW_VLAN_CTAG_FILTER); - enetc4_pf_set_si_vlan_promisc(hw, 0, promisc_en); + enetc_set_si_vlan_promisc(priv->si, 0, promisc_en); } if (changed & NETIF_F_LOOPBACK) @@ -566,7 +567,7 @@ static const struct net_device_ops enetc4_ndev_ops = { .ndo_start_xmit = enetc_xmit, .ndo_get_stats = enetc_get_stats, .ndo_set_mac_address = enetc_pf_set_mac_addr, - .ndo_set_rx_mode = enetc4_pf_set_rx_mode, + .ndo_set_rx_mode_async = enetc4_pf_set_rx_mode, .ndo_set_features = enetc4_pf_set_features, .ndo_vlan_rx_add_vid = enetc_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = enetc_vlan_rx_del_vid, @@ -602,11 +603,6 @@ static void enetc4_mac_config(struct enetc_pf *pf, unsigned int mode, case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: val |= IFMODE_RGMII; - /* We need to enable auto-negotiation for the MAC - * if its RGMII interface support In-Band status. - */ - if (phylink_autoneg_inband(mode)) - val |= PM_IF_MODE_ENA; break; case PHY_INTERFACE_MODE_RMII: val |= IFMODE_RMII; @@ -616,7 +612,6 @@ static void enetc4_mac_config(struct enetc_pf *pf, unsigned int mode, val |= IFMODE_SGMII; break; case PHY_INTERFACE_MODE_10GBASER: - case PHY_INTERFACE_MODE_XGMII: case PHY_INTERFACE_MODE_USXGMII: val |= IFMODE_XGMII; break; @@ -642,26 +637,19 @@ static void enetc4_set_port_speed(struct enetc_ndev_priv *priv, int speed) u32 old_speed = priv->speed; u32 val; + /* If the speed is unknown, use the minimum value */ + if (speed == SPEED_UNKNOWN) { + speed = SPEED_10; + dev_warn(priv->dev, "Speed unknown, default is 10Mbps\n"); + } + if (speed == old_speed) return; - val = enetc_port_rd(&priv->si->hw, ENETC4_PCR); - val &= ~PCR_PSPEED; - - switch (speed) { - case SPEED_100: - case SPEED_1000: - case SPEED_2500: - case SPEED_10000: - val |= (PCR_PSPEED & PCR_PSPEED_VAL(speed)); - break; - case SPEED_10: - default: - val |= (PCR_PSPEED & PCR_PSPEED_VAL(SPEED_10)); - } - - priv->speed = speed; + val = enetc_port_rd(&priv->si->hw, ENETC4_PCR) & (~PCR_PSPEED); + val |= PCR_PSPEED_VAL(speed); enetc_port_wr(&priv->si->hw, ENETC4_PCR, val); + priv->speed = speed; } static void enetc4_set_rgmii_mac(struct enetc_pf *pf, int speed, int duplex) @@ -717,22 +705,6 @@ static void enetc4_set_rmii_mac(struct enetc_pf *pf, int speed, int duplex) enetc_port_mac_wr(si, ENETC4_PM_IF_MODE(0), val); } -static void enetc4_set_hd_flow_control(struct enetc_pf *pf, bool enable) -{ - struct enetc_si *si = pf->si; - u32 old_val, val; - - if (!pf->caps.half_duplex) - return; - - old_val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0)); - val = u32_replace_bits(old_val, enable ? 1 : 0, PM_CMD_CFG_HD_FCEN); - if (val == old_val) - return; - - enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val); -} - static void enetc4_set_rx_pause(struct enetc_pf *pf, bool rx_pause) { struct enetc_si *si = pf->si; @@ -908,13 +880,11 @@ static void enetc4_pl_mac_link_up(struct phylink_config *config, struct enetc_pf *pf = phylink_to_enetc_pf(config); struct enetc_si *si = pf->si; struct enetc_ndev_priv *priv; - bool hd_fc = false; priv = netdev_priv(si->ndev); enetc4_set_port_speed(priv, speed); - if (!phylink_autoneg_inband(mode) && - phy_interface_mode_is_rgmii(interface)) + if (phy_interface_mode_is_rgmii(interface)) enetc4_set_rgmii_mac(pf, speed, duplex); if (interface == PHY_INTERFACE_MODE_RMII) @@ -926,18 +896,8 @@ static void enetc4_pl_mac_link_up(struct phylink_config *config, */ if (priv->active_offloads & ENETC_F_QBU) tx_pause = false; - } else { /* DUPLEX_HALF */ - if (tx_pause || rx_pause) - hd_fc = true; - - /* As per 802.3 annex 31B, PAUSE frames are only supported - * when the link is configured for full duplex operation. - */ - tx_pause = false; - rx_pause = false; } - enetc4_set_hd_flow_control(pf, hd_fc); enetc4_set_tx_pause(pf, priv->num_rx_rings, tx_pause); enetc4_set_rx_pause(pf, rx_pause); enetc4_mac_tx_enable(pf); @@ -1009,19 +969,6 @@ static void enetc4_link_deinit(struct enetc_ndev_priv *priv) enetc_mdiobus_destroy(pf); } -static int enetc4_psi_wq_task_init(struct enetc_si *si) -{ - char wq_name[24]; - - INIT_WORK(&si->rx_mode_task, enetc4_psi_do_set_rx_mode); - snprintf(wq_name, sizeof(wq_name), "enetc-%s", pci_name(si->pdev)); - si->workqueue = create_singlethread_workqueue(wq_name); - if (!si->workqueue) - return -ENOMEM; - - return 0; -} - static int enetc4_pf_netdev_create(struct enetc_si *si) { struct device *dev = &si->pdev->dev; @@ -1062,12 +1009,6 @@ static int enetc4_pf_netdev_create(struct enetc_si *si) if (err) goto err_link_init; - err = enetc4_psi_wq_task_init(si); - if (err) { - dev_err(dev, "Failed to init workqueue\n"); - goto err_wq_init; - } - err = register_netdev(ndev); if (err) { dev_err(dev, "Failed to register netdev\n"); @@ -1077,8 +1018,6 @@ static int enetc4_pf_netdev_create(struct enetc_si *si) return 0; err_reg_netdev: - destroy_workqueue(si->workqueue); -err_wq_init: enetc4_link_deinit(priv); err_link_init: enetc_free_msix(priv); @@ -1096,8 +1035,6 @@ static void enetc4_pf_netdev_destroy(struct enetc_si *si) struct net_device *ndev = si->ndev; unregister_netdev(ndev); - cancel_work(&si->rx_mode_task); - destroy_workqueue(si->workqueue); enetc4_link_deinit(priv); enetc_free_msix(priv); free_netdev(ndev); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c index 71f376ef1be1..07b7832f2427 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c @@ -29,7 +29,7 @@ static const u32 enetc_rxbdr_regs[] = { }; static const u32 enetc_port_regs[] = { - ENETC_PMR, ENETC_PSR, ENETC_PSIPMR, ENETC_PSIPMAR0(0), + ENETC_PMR, ENETC_PSR, ENETC_PSIPMMR, ENETC_PSIPMAR0(0), ENETC_PSIPMAR1(0), ENETC_PTXMBAR, ENETC_PCAPR0, ENETC_PCAPR1, ENETC_PSICFGR0(0), ENETC_PRFSCAPR, ENETC_PTCMSDUR(0), ENETC_PM0_CMD_CFG, ENETC_PM0_MAXFRM, ENETC_PM0_IF_MODE diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h index bf99b65d7598..16da732dc5de 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h @@ -180,13 +180,13 @@ enum enetc_bdr_type {TX, RX}; #define ENETC_PMR_PSPEED_1000M BIT(9) #define ENETC_PMR_PSPEED_2500M BIT(10) #define ENETC_PSR 0x0004 /* RO */ -#define ENETC_PSIPMR 0x0018 -#define ENETC_PSIPMR_SET_UP(n) BIT(n) /* n = SI index */ -#define ENETC_PSIPMR_SET_MP(n) BIT((n) + 16) +#define ENETC_PSIPMMR 0x0018 +#define PSIPMMR_SI_MAC_UP(n) BIT(n) /* n = SI index */ +#define PSIPMMR_SI_MAC_MP(n) BIT((n) + 16) + #define ENETC_PSIPVMR 0x001c -#define ENETC_VLAN_PROMISC_MAP_ALL 0x7 -#define ENETC_PSIPVMR_SET_VP(simap) ((simap) & 0x7) -#define ENETC_PSIPVMR_SET_VUTA(simap) (((simap) & 0x7) << 16) +#define PSIPVMR_SI_VLAN_P(n) BIT(n) /* n = SI index */ + #define ENETC_PSIPMAR0(n) (0x0100 + (n) * 0x8) /* n = SI index */ #define ENETC_PSIPMAR1(n) (0x0104 + (n) * 0x8) #define ENETC_PVCLCTR 0x0208 diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index 2d687bb8c3a0..a509929f89f2 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -42,26 +42,6 @@ static void enetc_pf_destroy_pcs(struct phylink_pcs *pcs) lynx_pcs_destroy(pcs); } -static void enetc_set_vlan_promisc(struct enetc_hw *hw, char si_map) -{ - u32 val = enetc_port_rd(hw, ENETC_PSIPVMR); - - val &= ~ENETC_PSIPVMR_SET_VP(ENETC_VLAN_PROMISC_MAP_ALL); - enetc_port_wr(hw, ENETC_PSIPVMR, ENETC_PSIPVMR_SET_VP(si_map) | val); -} - -static void enetc_enable_si_vlan_promisc(struct enetc_pf *pf, int si_idx) -{ - pf->vlan_promisc_simap |= BIT(si_idx); - enetc_set_vlan_promisc(&pf->si->hw, pf->vlan_promisc_simap); -} - -static void enetc_disable_si_vlan_promisc(struct enetc_pf *pf, int si_idx) -{ - pf->vlan_promisc_simap &= ~BIT(si_idx); - enetc_set_vlan_promisc(&pf->si->hw, pf->vlan_promisc_simap); -} - static void enetc_set_isol_vlan(struct enetc_hw *hw, int si, u16 vlan, u8 qos) { u32 val = 0; @@ -80,37 +60,6 @@ static void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter, filter->mac_addr_cnt++; } -static void enetc_clear_mac_ht_flt(struct enetc_si *si, int si_idx, int type) -{ - bool err = si->errata & ENETC_ERR_UCMCSWP; - - if (type == UC) { - enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err), 0); - enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx), 0); - } else { /* MC */ - enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err), 0); - enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx), 0); - } -} - -static void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type, - unsigned long hash) -{ - bool err = si->errata & ENETC_ERR_UCMCSWP; - - if (type == UC) { - enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err), - lower_32_bits(hash)); - enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx), - upper_32_bits(hash)); - } else { /* MC */ - enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err), - lower_32_bits(hash)); - enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx), - upper_32_bits(hash)); - } -} - static void enetc_sync_mac_filters(struct enetc_pf *pf) { struct enetc_mac_filter *f = pf->mac_filter; @@ -122,12 +71,16 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf) for (i = 0; i < MADDR_TYPE; i++, f++) { bool em = (f->mac_addr_cnt == 1) && (i == UC); bool clear = !f->mac_addr_cnt; + u64 hash; if (clear) { - if (i == UC) + if (i == UC) { enetc_clear_mac_flt_entry(si, pos); + enetc_set_si_uc_hash_filter(si, 0, 0); + } else { + enetc_set_si_mc_hash_filter(si, 0, 0); + } - enetc_clear_mac_ht_flt(si, 0, i); continue; } @@ -135,7 +88,7 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf) if (em) { int err; - enetc_clear_mac_ht_flt(si, 0, UC); + enetc_set_si_uc_hash_filter(si, 0, 0); err = enetc_set_mac_flt_entry(si, pos, f->mac_addr, BIT(0)); @@ -147,11 +100,15 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf) err); } + bitmap_to_arr64(&hash, f->mac_hash_table, + ENETC_MADDR_HASH_TBL_SZ); /* hash table filter, clear EM filter for UC entries */ - if (i == UC) + if (i == UC) { enetc_clear_mac_flt_entry(si, pos); - - enetc_set_mac_ht_flt(si, 0, i, *f->mac_hash_table); + enetc_set_si_uc_hash_filter(si, 0, hash); + } else { + enetc_set_si_mc_hash_filter(si, 0, hash); + } } } @@ -159,21 +116,17 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev) { struct enetc_ndev_priv *priv = netdev_priv(ndev); struct enetc_pf *pf = enetc_si_priv(priv->si); - struct enetc_hw *hw = &priv->si->hw; bool uprom = false, mprom = false; struct enetc_mac_filter *filter; struct netdev_hw_addr *ha; - u32 psipmr = 0; bool em; if (ndev->flags & IFF_PROMISC) { /* enable promisc mode for SI0 (PF) */ - psipmr = ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0); uprom = true; mprom = true; } else if (ndev->flags & IFF_ALLMULTI) { /* enable multi cast promisc mode for SI0 (PF) */ - psipmr = ENETC_PSIPMR_SET_MP(0); mprom = true; } @@ -211,9 +164,8 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev) /* update PF entries */ enetc_sync_mac_filters(pf); - psipmr |= enetc_port_rd(hw, ENETC_PSIPMR) & - ~(ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0)); - enetc_port_wr(hw, ENETC_PSIPMR, psipmr); + enetc_set_si_uc_promisc(priv->si, 0, uprom); + enetc_set_si_mc_promisc(priv->si, 0, mprom); } static void enetc_set_loopback(struct net_device *ndev, bool en) @@ -469,12 +421,11 @@ static void enetc_configure_port(struct enetc_pf *pf) /* split up RFS entries */ enetc_port_assign_rfs_entries(pf->si); - /* enforce VLAN promisc mode for all SIs */ - pf->vlan_promisc_simap = ENETC_VLAN_PROMISC_MAP_ALL; - enetc_set_vlan_promisc(hw, pf->vlan_promisc_simap); + for (int i = 0; i < pf->total_vfs + 1; i++) + enetc_set_si_vlan_promisc(pf->si, i, true); - enetc_port_wr(hw, ENETC_PSIPMR, 0); + enetc_port_wr(hw, ENETC_PSIPMMR, 0); /* enable port */ enetc_port_wr(hw, ENETC_PMR, ENETC_PMR_EN); @@ -494,12 +445,9 @@ static int enetc_pf_set_features(struct net_device *ndev, } if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) { - struct enetc_pf *pf = enetc_si_priv(priv->si); + bool promisc = !(features & NETIF_F_HW_VLAN_CTAG_FILTER); - if (!!(features & NETIF_F_HW_VLAN_CTAG_FILTER)) - enetc_disable_si_vlan_promisc(pf, 0); - else - enetc_enable_si_vlan_promisc(pf, 0); + enetc_set_si_vlan_promisc(priv->si, 0, promisc); } if (changed & NETIF_F_LOOPBACK) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h index 285b7e5c48fd..56d23a8a11a0 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h @@ -17,12 +17,9 @@ struct enetc_vf_state { }; struct enetc_port_caps { - u32 half_duplex:1; - int num_vsi; int num_msix; int num_rx_bdr; int num_tx_bdr; - int mac_filter_num; }; struct enetc_pf; @@ -47,7 +44,6 @@ struct enetc_pf { struct work_struct msg_task; char msg_int_name[ENETC_INT_NAME_MAX]; - char vlan_promisc_simap; /* bitmap of SIs in VLAN promisc mode */ DECLARE_BITMAP(vlan_ht_filter, ENETC_VLAN_HT_SIZE); DECLARE_BITMAP(active_vlans, VLAN_N_VID); @@ -60,8 +56,6 @@ struct enetc_pf { struct enetc_port_caps caps; const struct enetc_pf_ops *ops; - - int num_mfe; /* number of mac address filter table entries */ }; #define phylink_to_enetc_pf(config) \ diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c index 6e5d2f869915..d32a195a04c9 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) -/* Copyright 2024 NXP */ +/* Copyright 2024-2026 NXP */ #include #include @@ -87,6 +87,112 @@ int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf) } EXPORT_SYMBOL_GPL(enetc_setup_mac_addresses); +void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc) +{ + struct enetc_hw *hw = &si->hw; + int psipmmr_off; + u32 val; + + if (is_enetc_rev1(si)) + psipmmr_off = ENETC_PSIPMMR; + else + psipmmr_off = ENETC4_PSIPMMR; + + val = enetc_port_rd(hw, psipmmr_off); + + if (promisc) + val |= PSIPMMR_SI_MAC_UP(si_id); + else + val &= ~PSIPMMR_SI_MAC_UP(si_id); + + enetc_port_wr(hw, psipmmr_off, val); +} +EXPORT_SYMBOL_GPL(enetc_set_si_uc_promisc); + +void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc) +{ + struct enetc_hw *hw = &si->hw; + int psipmmr_off; + u32 val; + + if (is_enetc_rev1(si)) + psipmmr_off = ENETC_PSIPMMR; + else + psipmmr_off = ENETC4_PSIPMMR; + + val = enetc_port_rd(hw, psipmmr_off); + + if (promisc) + val |= PSIPMMR_SI_MAC_MP(si_id); + else + val &= ~PSIPMMR_SI_MAC_MP(si_id); + + enetc_port_wr(hw, psipmmr_off, val); +} +EXPORT_SYMBOL_GPL(enetc_set_si_mc_promisc); + +void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash) +{ + int psiumhfr0_off, psiumhfr1_off; + struct enetc_hw *hw = &si->hw; + + if (is_enetc_rev1(si)) { + bool err = si->errata & ENETC_ERR_UCMCSWP; + + psiumhfr0_off = ENETC_PSIUMHFR0(si_id, err); + psiumhfr1_off = ENETC_PSIUMHFR1(si_id); + } else { + psiumhfr0_off = ENETC4_PSIUMHFR0(si_id); + psiumhfr1_off = ENETC4_PSIUMHFR1(si_id); + } + + enetc_port_wr(hw, psiumhfr0_off, lower_32_bits(hash)); + enetc_port_wr(hw, psiumhfr1_off, upper_32_bits(hash)); +} +EXPORT_SYMBOL_GPL(enetc_set_si_uc_hash_filter); + +void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash) +{ + int psimmhfr0_off, psimmhfr1_off; + struct enetc_hw *hw = &si->hw; + + if (is_enetc_rev1(si)) { + bool err = si->errata & ENETC_ERR_UCMCSWP; + + psimmhfr0_off = ENETC_PSIMMHFR0(si_id, err); + psimmhfr1_off = ENETC_PSIMMHFR1(si_id); + } else { + psimmhfr0_off = ENETC4_PSIMMHFR0(si_id); + psimmhfr1_off = ENETC4_PSIMMHFR1(si_id); + } + + enetc_port_wr(hw, psimmhfr0_off, lower_32_bits(hash)); + enetc_port_wr(hw, psimmhfr1_off, upper_32_bits(hash)); +} +EXPORT_SYMBOL_GPL(enetc_set_si_mc_hash_filter); + +void enetc_set_si_vlan_promisc(struct enetc_si *si, int si_id, bool promisc) +{ + struct enetc_hw *hw = &si->hw; + int psipvmr_off; + u32 val; + + if (is_enetc_rev1(si)) + psipvmr_off = ENETC_PSIPVMR; + else + psipvmr_off = ENETC4_PSIPVMR; + + val = enetc_port_rd(hw, psipvmr_off); + + if (promisc) + val |= PSIPVMR_SI_VLAN_P(si_id); + else + val &= ~PSIPVMR_SI_VLAN_P(si_id); + + enetc_port_wr(hw, psipvmr_off, val); +} +EXPORT_SYMBOL_GPL(enetc_set_si_vlan_promisc); + void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, const struct net_device_ops *ndev_ops) { @@ -275,7 +381,8 @@ static bool enetc_port_has_pcs(struct enetc_pf *pf) return (pf->if_mode == PHY_INTERFACE_MODE_SGMII || pf->if_mode == PHY_INTERFACE_MODE_1000BASEX || pf->if_mode == PHY_INTERFACE_MODE_2500BASEX || - pf->if_mode == PHY_INTERFACE_MODE_USXGMII); + pf->if_mode == PHY_INTERFACE_MODE_USXGMII || + pf->if_mode == PHY_INTERFACE_MODE_10GBASER); } int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node) @@ -316,25 +423,42 @@ int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node, { struct enetc_pf *pf = enetc_si_priv(priv->si); struct phylink *phylink; + unsigned long mac_caps; int err; pf->phylink_config.dev = &priv->ndev->dev; pf->phylink_config.type = PHYLINK_NETDEV; - pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | - MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD; __set_bit(PHY_INTERFACE_MODE_INTERNAL, pf->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_SGMII, - pf->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_1000BASEX, - pf->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_2500BASEX, - pf->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_USXGMII, - pf->phylink_config.supported_interfaces); - phy_interface_set_rgmii(pf->phylink_config.supported_interfaces); + mac_caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE; + if (!enetc_is_pseudo_mac(priv->si)) { + mac_caps |= MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD; + + __set_bit(PHY_INTERFACE_MODE_SGMII, + pf->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, + pf->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, + pf->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_USXGMII, + pf->phylink_config.supported_interfaces); + + if (!is_enetc_rev1(priv->si)) { + mac_caps |= MAC_5000FD | MAC_10000FD; + __set_bit(PHY_INTERFACE_MODE_10GBASER, + pf->phylink_config.supported_interfaces); + } + + phy_interface_set_rgmii(pf->phylink_config.supported_interfaces); + } else { + mac_caps |= MAC_10FD | MAC_100FD | MAC_1000FD | MAC_2500FD | + MAC_5000FD | MAC_10000FD | MAC_20000FD | + MAC_25000FD; + } + + pf->phylink_config.mac_capabilities = mac_caps; phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node), pf->if_mode, ops); if (IS_ERR(phylink)) { diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h index 57d2e0ebd2b0..8243ce0de57f 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h @@ -17,6 +17,11 @@ void enetc_set_default_rss_key(struct enetc_pf *pf); int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid); int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid); int enetc_init_sriov_resources(struct enetc_pf *pf); +void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc); +void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc); +void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash); +void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash); +void enetc_set_si_vlan_promisc(struct enetc_si *si, int si_id, bool promisc); static inline u16 enetc_get_ip_revision(struct enetc_hw *hw) { diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index 7b17bca24f26..2aa0fcaafcd2 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -1135,7 +1135,6 @@ static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv, struct flow_action_entry *entry; struct action_gate_entry *e; u8 sfi_overwrite = 0; - int entries_size; int i, err; if (f->common.chain_index >= priv->psfp_cap.max_streamid) { @@ -1242,8 +1241,7 @@ static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv, goto free_filter; } - entries_size = struct_size(sgi, entries, entryg->gate.num_entries); - sgi = kzalloc(entries_size, GFP_KERNEL); + sgi = kzalloc_flex(*sgi, entries, entryg->gate.num_entries); if (!sgi) { err = -ENOMEM; goto free_filter; diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c index 9cdb0a4d6baf..7dcb4a0246f5 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c @@ -317,7 +317,14 @@ static int enetc_vf_probe(struct pci_dev *pdev, enetc_get_si_caps(si); - ndev = alloc_etherdev_mq(sizeof(*priv), ENETC_MAX_NUM_TXQS); + /* Currently, the supported SoCs have a max of 6 CPUs and the VFs + * have less than 6 RX/TX rings. So no issues for these supported + * SoCs, but for future SoCs which have more CPUs or more TX/RX + * rings, all the related logic needs to be improved. + */ + ndev = alloc_etherdev_mqs(sizeof(*priv), + min(si->num_tx_rings, ENETC_MAX_NUM_TXQS), + min(si->num_rx_rings, ENETC_MAX_NUM_TXQS)); if (!ndev) { err = -ENOMEM; dev_err(&pdev->dev, "netdev creation failed\n"); diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h index d3b6c476b91a..764ef2892608 100644 --- a/include/linux/fsl/ntmp.h +++ b/include/linux/fsl/ntmp.h @@ -75,8 +75,10 @@ struct ntmp_user { /* NTMP table bitmaps for resource management */ u32 ett_bitmap_size; u32 ect_bitmap_size; + u16 maft_num_entries; unsigned long *ett_gid_bitmap; /* only valid for switch */ unsigned long *ect_gid_bitmap; /* only valid for switch */ + unsigned long *maft_eid_bitmap; /* only valid for ENETC */ }; struct maft_entry_data {