diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/enetc/enetc_pf_common.c')
-rw-r--r-- | drivers/net/ethernet/freescale/enetc/enetc_pf_common.c | 93 |
1 files changed, 87 insertions, 6 deletions
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c index 3fd9b0727875..edf14a95cab7 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c @@ -128,14 +128,14 @@ void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, if (si->hw_features & ENETC_SI_F_LSO) priv->active_offloads |= ENETC_F_LSO; - /* TODO: currently, i.MX95 ENETC driver does not support advanced features */ - if (!is_enetc_rev1(si)) { - ndev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK); - goto end; + if (si->num_rss) { + ndev->hw_features |= NETIF_F_RXHASH; + ndev->features |= NETIF_F_RXHASH; } - if (si->num_rss) - ndev->hw_features |= NETIF_F_RXHASH; + /* TODO: currently, i.MX95 ENETC driver does not support advanced features */ + if (!is_enetc_rev1(si)) + goto end; ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG | @@ -341,5 +341,86 @@ void enetc_phylink_destroy(struct enetc_ndev_priv *priv) } EXPORT_SYMBOL_GPL(enetc_phylink_destroy); +void enetc_set_default_rss_key(struct enetc_pf *pf) +{ + u8 hash_key[ENETC_RSSHASH_KEY_SIZE] = {0}; + + /* set up hash key */ + get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE); + enetc_set_rss_key(pf->si, hash_key); +} +EXPORT_SYMBOL_GPL(enetc_set_default_rss_key); + +static int enetc_vid_hash_idx(unsigned int vid) +{ + int res = 0; + int i; + + for (i = 0; i < 6; i++) + res |= (hweight8(vid & (BIT(i) | BIT(i + 6))) & 0x1) << i; + + return res; +} + +static void enetc_refresh_vlan_ht_filter(struct enetc_pf *pf) +{ + int i; + + bitmap_zero(pf->vlan_ht_filter, ENETC_VLAN_HT_SIZE); + for_each_set_bit(i, pf->active_vlans, VLAN_N_VID) { + int hidx = enetc_vid_hash_idx(i); + + __set_bit(hidx, pf->vlan_ht_filter); + } +} + +static void enetc_set_si_vlan_ht_filter(struct enetc_si *si, + int si_id, u64 hash) +{ + struct enetc_hw *hw = &si->hw; + int high_reg_off, low_reg_off; + + if (is_enetc_rev1(si)) { + low_reg_off = ENETC_PSIVHFR0(si_id); + high_reg_off = ENETC_PSIVHFR1(si_id); + } else { + low_reg_off = ENETC4_PSIVHFR0(si_id); + high_reg_off = ENETC4_PSIVHFR1(si_id); + } + + enetc_port_wr(hw, low_reg_off, lower_32_bits(hash)); + enetc_port_wr(hw, high_reg_off, upper_32_bits(hash)); +} + +int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct enetc_pf *pf = enetc_si_priv(priv->si); + int idx; + + __set_bit(vid, pf->active_vlans); + + idx = enetc_vid_hash_idx(vid); + if (!__test_and_set_bit(idx, pf->vlan_ht_filter)) + enetc_set_si_vlan_ht_filter(pf->si, 0, *pf->vlan_ht_filter); + + return 0; +} +EXPORT_SYMBOL_GPL(enetc_vlan_rx_add_vid); + +int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct enetc_pf *pf = enetc_si_priv(priv->si); + + if (__test_and_clear_bit(vid, pf->active_vlans)) { + enetc_refresh_vlan_ht_filter(pf); + enetc_set_si_vlan_ht_filter(pf->si, 0, *pf->vlan_ht_filter); + } + + return 0; +} +EXPORT_SYMBOL_GPL(enetc_vlan_rx_del_vid); + MODULE_DESCRIPTION("NXP ENETC PF common functionality driver"); MODULE_LICENSE("Dual BSD/GPL"); |