Merge branch 'net-enetc-cleanups-and-improvements'

Wei Fang says:

====================
net: enetc: cleanups and improvements

The first group of patches (1, 2, 5-7) eliminates code duplication
between the ENETC v1 and v4 drivers. Since both hardware generations
share identical register layouts for MAC promiscuous mode, MAC hash
filters, and VLAN promiscuous mode - differing only in register address
offsets - common helper functions are extracted into enetc_pf_common.c
and shared by both drivers.

Patch 3 converts ndo_set_rx_mode() to ndo_set_rx_mode_async(), removing
the dedicated workqueue that was previously needed to defer MAC address
list updates to a sleepable context.

Patch 4 replaces counter-based MAFT entry tracking with a bitmap, which
keeps hardware and software state in sync and avoids partial failures
during entry allocation.

Patches 8 and 9 fix phylink-related issues: removing invalid code from
enetc4_pl_mac_link_up() and properly differentiating phylink capabilities
between pseudo-MAC and standalone MAC.

The remaining patches (10-14) are minor cleanups: removing a redundant
VLAN promiscuous mode initialization in probe, using the PCI device name
for the debugfs directory, simplifying port speed configuration, removing
a redundant num_vsi field, using alloc_etherdev_mqs() for the VF driver,
and using kzalloc_flex() for a flexible array allocation.
====================

Link: https://patch.msgid.link/20260720014317.1059359-1-wei.fang@oss.nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-07-27 16:34:12 -07:00
commit 6a11e81062
13 changed files with 411 additions and 396 deletions

View File

@ -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 <linux/timer.h>
#include <linux/pci.h>
@ -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 */
};

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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) \

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2024 NXP */
/* Copyright 2024-2026 NXP */
#include <linux/fsl/enetc_mdio.h>
#include <linux/of_mdio.h>
@ -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)) {

View File

@ -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)
{

View File

@ -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;

View File

@ -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");

View File

@ -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 {