diff options
| author | Serge Semin <fancer.lancer@gmail.com> | 2025-04-17 01:20:45 +0300 |
|---|---|---|
| committer | Serge Semin <fancer.lancer@gmail.com> | 2026-08-13 20:35:10 +0300 |
| commit | d456306f0decc3143ce273af33af5bed0d8cc033 (patch) | |
| tree | a0a0d5882c9a15406b52ccda94e491d243aff5d3 | |
| parent | 2c6ad51635c5ca38a674bf33659db1ffb266dfa9 (diff) | |
| download | linux-d456306f0decc3143ce273af33af5bed0d8cc033.tar.gz linux-d456306f0decc3143ce273af33af5bed0d8cc033.zip | |
net: stmmac: vlan: Use hash and perfect VLAN filters complementarily
Current hash-based VLAN-filters and extended VLAN-filters implementations
are orthogonal. That is they duplicate each other filtering the same VLAN
tags. It's not that optimal since the controller supports them to work
complementarily. It means to use one filter resources if only the
resources of another one have been fully used up. Particularly the
Extended VLAN-Filters as being the perfect filters would be utilised
first. Only if no free perfect VLAN-filter slots left, the hash-based
VLAN-filter will be configured.
Let's implement the denoted functionality then. It's not that complicated
since the preceding commits have smoothly prepared the code for that. So
just invert the filters configuration order and regard the error-values of
the extended filter configuration as a hint to fallback to the hash-based
filter utilization.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 25 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c | 32 |
2 files changed, 24 insertions, 33 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 58a4ce67fe19..b8bdaeab32b7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -7161,6 +7161,9 @@ static int stmmac_update_hw_vlan_rx_hash(struct stmmac_priv *priv, bool add, u16 vid_cpu; int ret; + if (!priv->dma_cap.vlhash) + return -ENOSPC; + if (proto == htons(ETH_P_8021Q)) { active_vlans = priv->active_cvlans; add_ctags = add ? 1 : -1; @@ -7216,15 +7219,13 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid if (ret < 0) return ret; - ret = stmmac_update_hw_vlan_rx_hash(priv, true, proto, vid); - if (ret) - goto err_pm_put; - ret = stmmac_add_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid); - if (ret && ret != -EINVAL) - stmmac_update_hw_vlan_rx_hash(priv, false, proto, vid); + if (!ret) + goto ok_pm_put; -err_pm_put: + ret = stmmac_update_hw_vlan_rx_hash(priv, true, proto, vid); + +ok_pm_put: pm_runtime_put(priv->device); return ret; @@ -7243,14 +7244,12 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi return ret; ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid); - if (ret && ret != -EINVAL) - goto del_vlan_error; + if (!ret) + goto ok_pm_put; ret = stmmac_update_hw_vlan_rx_hash(priv, false, proto, vid); - if (ret) - stmmac_add_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid); -del_vlan_error: +ok_pm_put: pm_runtime_put(priv->device); return ret; @@ -8797,7 +8796,7 @@ static int __stmmac_dvr_probe(struct device *device, ndev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX; ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX; - if (priv->dma_cap.vlhash) { + if (priv->dma_cap.vlhash || priv->dma_cap.nrvf_num) { ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER; ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c index 2cd79672c739..4cf1096a119a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c @@ -82,10 +82,8 @@ static int vlan_add_hw_rx_fltr(struct net_device *dev, /* Single Rx VLAN Filter */ if (hw->num_vlan == 1) { /* For single VLAN filter, VID 0 means VLAN promiscuous */ - if (vid == 0) { - netdev_warn(dev, "Adding VLAN ID 0 is not supported\n"); - return -EPERM; - } + if (vid == 0) + return -EINVAL; val = vid; if (is_stag) @@ -94,10 +92,8 @@ static int vlan_add_hw_rx_fltr(struct net_device *dev, if (hw->vlan_filter[0] == val) return 0; - if (hw->vlan_filter[0] & VLAN_TAG_VID) { - netdev_err(dev, "Only single VLAN ID supported\n"); - return -EPERM; - } + if (hw->vlan_filter[0] & VLAN_TAG_VID) + return -ENOSPC; vlan_update_hash(hw, hw->vlan_hash, !is_stag, is_stag); @@ -120,11 +116,8 @@ static int vlan_add_hw_rx_fltr(struct net_device *dev, index = i; } - if (index == -1) { - netdev_err(dev, "MAC_VLAN_Tag_Filter full (size: %0u)\n", - hw->num_vlan); - return -EPERM; - } + if (index == -1) + return -ENOSPC; ret = vlan_write_filter(dev, hw, index, val); if (ret && ret != -EAGAIN) @@ -139,18 +132,18 @@ static int vlan_del_hw_rx_fltr(struct net_device *dev, struct mac_device_info *hw, __be16 proto, u16 vid) { - int i, ret = 0; bool is_stag; + int i, ret; is_stag = proto == htons(ETH_P_8021AD); /* Single Rx VLAN Filter */ if (hw->num_vlan == 1) { if ((hw->vlan_filter[0] & VLAN_TAG_VID) != vid) - return 0; + return -ENOENT; if (is_stag != !!(hw->vlan_filter[0] & VLAN_TAG_ERSVLM)) - return 0; + return -ENOENT; vlan_update_hash(hw, hw->vlan_hash, -!is_stag, -is_stag); @@ -177,9 +170,11 @@ static int vlan_del_hw_rx_fltr(struct net_device *dev, return ret; hw->vlan_filter[i] = 0; + + return 0; } - return 0; + return -ENOENT; } static void vlan_update_hash(struct mac_device_info *hw, u32 hash, @@ -210,9 +205,6 @@ static void vlan_update_hash(struct mac_device_info *hw, u32 hash, value &= ~VLAN_ERSVLM; } - if (!hw->vlan_filter[0]) - value |= VLAN_VID; - writel(value, ioaddr + VLAN_TAG); } |
