summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2025-04-17 01:20:45 +0300
committerSerge Semin <fancer.lancer@gmail.com>2026-08-13 20:35:10 +0300
commitd456306f0decc3143ce273af33af5bed0d8cc033 (patch)
treea0a0d5882c9a15406b52ccda94e491d243aff5d3
parent2c6ad51635c5ca38a674bf33659db1ffb266dfa9 (diff)
downloadlinux-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.c25
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c32
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);
}