diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c index 1b1591dce73d..4a769d9e5679 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c +++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c @@ -31,9 +31,11 @@ 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 maft_entry_data maft; + struct ntmp_user *user; struct enetc_pf *pf; - int i, err, num_si; - u32 val; + u32 val, entry_id; + int i, num_si; + int err = 0; pf = enetc_si_priv(si); num_si = pf->caps.num_vsi + 1; @@ -50,22 +52,30 @@ 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 = &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); diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c index a02b01753ff2..b966637572a7 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c @@ -32,9 +32,6 @@ static void enetc4_get_port_caps(struct enetc_pf *pf) 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) @@ -92,31 +89,45 @@ 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 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); + 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); 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(&pf->si->ntmp_user, pf->num_mfe, - &maft); - if (unlikely(err)) + err = ntmp_maft_add_entry(user, entry_id, &maft); + if (unlikely(err)) { + ntmp_clear_eid_bitmap(user->maft_eid_bitmap, entry_id); goto clear_maft_entries; - - pf->num_mfe++; + } } return 0; @@ -146,10 +157,10 @@ static void enetc4_pf_set_uc_hash_filter(struct enetc_pf *pf, static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf, struct netdev_hw_addr_list *uc) { - int mac_cnt = netdev_hw_addr_list_count(uc); struct enetc_si *si = pf->si; + int err; - if (!mac_cnt) { + if (netdev_hw_addr_list_empty(uc)) { /* clear both MAC hash and exact filters */ enetc_set_si_uc_hash_filter(si, 0, 0); enetc4_pf_clear_maft_entries(pf); @@ -157,21 +168,19 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf, return 0; } - if (mac_cnt > pf->caps.mac_filter_num) - return -ENOSPC; - - /* 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_uc_hash_filter(pf, uc); enetc4_pf_clear_maft_entries(pf); - if (!enetc4_pf_add_maft_entries(pf, uc)) { + 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 0; + return err; } static void enetc4_pf_set_mc_hash_filter(struct enetc_pf *pf, @@ -393,18 +402,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); } @@ -422,7 +473,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; } diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h index 285b7e5c48fd..6f15f9ea1664 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h @@ -22,7 +22,6 @@ struct enetc_port_caps { int num_msix; int num_rx_bdr; int num_tx_bdr; - int mac_filter_num; }; struct enetc_pf; @@ -60,8 +59,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/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 {