Merge branch 'net-bcmasp-collection-of-fixes'

Florian Fainelli says:

====================
net: bcmasp: Collection of fixes

This patch series is a collection of bug fixes accumulated during a LLM
coding session. Thanks to Justin for the internal review and helping
with the last patch.
====================

Link: https://patch.msgid.link/20261013204439.3494046-1-florian.fainelli@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-10-20 13:01:16 -07:00
commit 38dda0ecd4
3 changed files with 95 additions and 62 deletions

View File

@ -511,6 +511,13 @@ static int bcmasp_netfilt_wr_to_hw(struct bcmasp_priv *priv,
return 0;
}
static bool bcmasp_netfilt_is_companion(struct bcmasp_priv *priv, int i)
{
return i > 0 && (i % 2) &&
priv->net_filters[i].wake_filter &&
priv->net_filters[i - 1].wake_filter;
}
void bcmasp_netfilt_suspend(struct bcmasp_intf *intf)
{
struct bcmasp_priv *priv = intf->parent;
@ -524,9 +531,7 @@ void bcmasp_netfilt_suspend(struct bcmasp_intf *intf)
priv->net_filters[i].port != intf->port)
continue;
if (i > 0 && (i % 2) &&
priv->net_filters[i].wake_filter &&
priv->net_filters[i - 1].wake_filter)
if (bcmasp_netfilt_is_companion(priv, i))
continue;
ret = bcmasp_netfilt_wr_to_hw(priv, &priv->net_filters[i]);
@ -556,9 +561,7 @@ int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs,
priv->net_filters[i].port != intf->port)
continue;
if (i > 0 && (i % 2) &&
priv->net_filters[i].wake_filter &&
priv->net_filters[i - 1].wake_filter)
if (bcmasp_netfilt_is_companion(priv, i))
continue;
if (j == *rule_cnt)
@ -583,9 +586,7 @@ int bcmasp_netfilt_get_active(struct bcmasp_intf *intf)
continue;
/* Skip over a wake filter pair */
if (i > 0 && (i % 2) &&
priv->net_filters[i].wake_filter &&
priv->net_filters[i - 1].wake_filter)
if (bcmasp_netfilt_is_companion(priv, i))
continue;
cnt++;
@ -607,6 +608,9 @@ bool bcmasp_netfilt_check_dup(struct bcmasp_intf *intf,
priv->net_filters[i].port != intf->port)
continue;
if (bcmasp_netfilt_is_companion(priv, i))
continue;
cur = &priv->net_filters[i].fs;
if (cur->flow_type != fs->flow_type ||
@ -659,7 +663,7 @@ bool bcmasp_netfilt_check_dup(struct bcmasp_intf *intf,
}
/* If no network filter found, return open filter.
* If no more open filters return NULL
* If no more open filters return error.
*/
struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf,
u32 loc, bool wake_filter,
@ -669,45 +673,55 @@ struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf,
struct bcmasp_priv *priv = intf->parent;
int i, open_index = -1;
/* Check whether we exceed the filter table capacity */
if (!init) {
if (loc == RX_CLS_LOC_ANY || loc >= priv->num_net_filters)
return ERR_PTR(-EINVAL);
if (priv->net_filters[loc].claimed &&
priv->net_filters[loc].port == intf->port &&
!bcmasp_netfilt_is_companion(priv, loc))
return &priv->net_filters[loc];
return ERR_PTR(-ENOENT);
}
if (loc != RX_CLS_LOC_ANY && loc >= priv->num_net_filters)
return ERR_PTR(-EINVAL);
/* If the filter location is busy (already claimed) and we are initializing
* the filter (insertion), return a busy error code.
*/
if (loc != RX_CLS_LOC_ANY && init && priv->net_filters[loc].claimed)
return ERR_PTR(-EBUSY);
if (loc != RX_CLS_LOC_ANY) {
if (priv->net_filters[loc].claimed)
return ERR_PTR(-EBUSY);
/* We need two filters for wake-up, so we cannot use an odd filter */
if (wake_filter && loc != RX_CLS_LOC_ANY && (loc % 2))
return ERR_PTR(-EINVAL);
/* Initialize the loop index based on the desired location or from 0 */
i = loc == RX_CLS_LOC_ANY ? 0 : loc;
for ( ; i < priv->num_net_filters; i++) {
/* Found matching network filter */
if (!init &&
priv->net_filters[i].claimed &&
priv->net_filters[i].hw_index == i &&
priv->net_filters[i].port == intf->port)
return &priv->net_filters[i];
/* If we don't need a new filter or new filter already found */
if (!init || open_index >= 0)
continue;
/* Wake filter conslidates two filters to cover more bytes
* Wake filter is open if...
* 1. It is an even filter
* 2. The current and next filter is not claimed
*/
if (wake_filter && !(i % 2) && !priv->net_filters[i].claimed &&
!priv->net_filters[i + 1].claimed)
open_index = i;
else if (!priv->net_filters[i].claimed)
open_index = i;
/* We need two filters for wake-up, so we cannot use an odd filter */
if (wake_filter) {
if ((loc % 2) || loc + 1 >= priv->num_net_filters)
return ERR_PTR(-EINVAL);
if (priv->net_filters[loc + 1].claimed)
return ERR_PTR(-EBUSY);
}
open_index = loc;
} else {
for (i = 0; i < priv->num_net_filters; i++) {
/* Wake filter consolidates two filters to cover more bytes.
* Wake filter is open if:
* 1. It is an even filter
* 2. The current and next filter is not claimed
*/
if (wake_filter) {
if (!(i % 2) && (i + 1 < priv->num_net_filters) &&
!priv->net_filters[i].claimed &&
!priv->net_filters[i + 1].claimed) {
open_index = i;
break;
}
} else if (!priv->net_filters[i].claimed) {
open_index = i;
break;
}
}
}
if (open_index >= 0) {
@ -716,16 +730,20 @@ struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf,
nfilter->port = intf->port;
nfilter->ch = intf->channel + priv->tx_chan_offset;
nfilter->hw_index = open_index;
if (wake_filter) {
/* Claim next filter */
priv->net_filters[open_index + 1].claimed = true;
priv->net_filters[open_index + 1].wake_filter = true;
priv->net_filters[open_index + 1].hw_index = open_index + 1;
priv->net_filters[open_index + 1].port = intf->port;
priv->net_filters[open_index + 1].ch = intf->channel +
priv->tx_chan_offset;
nfilter->wake_filter = true;
}
}
if (wake_filter && open_index >= 0) {
/* Claim next filter */
priv->net_filters[open_index + 1].claimed = true;
priv->net_filters[open_index + 1].wake_filter = true;
nfilter->wake_filter = true;
}
return nfilter ? nfilter : ERR_PTR(-EINVAL);
return nfilter ? nfilter : ERR_PTR(-ENOSPC);
}
void bcmasp_netfilt_release(struct bcmasp_intf *intf,
@ -733,7 +751,8 @@ void bcmasp_netfilt_release(struct bcmasp_intf *intf,
{
struct bcmasp_priv *priv = intf->parent;
if (nfilt->wake_filter) {
if (nfilt->wake_filter && !(nfilt->hw_index % 2) &&
nfilt->hw_index + 1 < priv->num_net_filters) {
memset(&priv->net_filters[nfilt->hw_index + 1], 0,
sizeof(struct bcmasp_net_filter));
}

View File

@ -250,10 +250,6 @@ struct bcmasp_intf_stats64 {
};
struct bcmasp_mib_counters {
u32 edpkt_ts;
u32 edpkt_rx_pkt_cnt;
u32 edpkt_hdr_ext_cnt;
u32 edpkt_hdr_out_cnt;
u32 umac_frm_cnt;
u32 fb_frm_cnt;
u32 fb_rx_fifo_depth;

View File

@ -236,7 +236,7 @@ static struct sk_buff *bcmasp_csum_offload(struct net_device *dev,
static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bcmasp_intf *intf = netdev_priv(dev);
unsigned int total_bytes, size;
unsigned int total_bytes, size, min_size;
int spb_index, nr_frags, i, j;
struct bcmasp_tx_cb *txcb;
dma_addr_t mapping, valid;
@ -262,16 +262,21 @@ static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev)
if (!skb)
return NETDEV_TX_OK;
min_size = ETH_ZLEN + ETH_FCS_LEN;
if (csum_hw)
min_size += sizeof(struct bcmasp_pkt_offload);
if (skb->len < min_size) {
if (skb_put_padto(skb, min_size))
return NETDEV_TX_OK;
nr_frags = skb_shinfo(skb)->nr_frags;
}
spb_index = intf->tx_spb_index;
valid = intf->tx_spb_dma_valid;
for (i = 0; i <= nr_frags; i++) {
if (!i) {
size = skb_headlen(skb);
if (!nr_frags && size < (ETH_ZLEN + ETH_FCS_LEN)) {
if (skb_put_padto(skb, ETH_ZLEN + ETH_FCS_LEN))
return NETDEV_TX_OK;
size = skb->len;
}
mapping = dma_map_single(kdev, skb->data, size,
DMA_TO_DEVICE);
} else {
@ -285,6 +290,11 @@ static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev)
intf->mib.tx_dma_failed++;
spb_index = intf->tx_spb_index;
for (j = 0; j < i; j++) {
txcb = &intf->tx_cbs[spb_index];
dma_unmap_single(kdev,
dma_unmap_addr(txcb, dma_addr),
dma_unmap_len(txcb, dma_len),
DMA_TO_DEVICE);
bcmasp_clean_txcb(intf, spb_index);
spb_index = incr_ring(spb_index,
DESC_RING_COUNT);
@ -518,6 +528,12 @@ static int bcmasp_rx_poll(struct napi_struct *napi, int budget)
DMA_FROM_DEVICE);
len = desc->size;
if (unlikely(len < 2 + ETH_HLEN + (intf->crc_fwd ? ETH_FCS_LEN : 0))) {
u64_stats_update_begin(&stats->syncp);
u64_stats_inc(&stats->rx_dropped);
u64_stats_update_end(&stats->syncp);
goto next;
}
/* Allocate a page pool page as the SKB data area so the
* kernel can recycle it efficiently after the packet is
@ -1287,7 +1303,7 @@ struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv,
ndev_dn->name);
goto err_free_netdev;
}
intf->phy_dn = ndev_dn;
intf->phy_dn = of_node_get(ndev_dn);
}
/* Map resource */
@ -1327,6 +1343,7 @@ struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv,
err_deregister_fixed_link:
if (of_phy_is_fixed_link(ndev_dn))
of_phy_deregister_fixed_link(ndev_dn);
of_node_put(intf->phy_dn);
err_free_netdev:
free_netdev(ndev);
err:
@ -1339,6 +1356,7 @@ void bcmasp_interface_destroy(struct bcmasp_intf *intf)
unregister_netdev(intf->ndev);
if (of_phy_is_fixed_link(intf->ndev_dn))
of_phy_deregister_fixed_link(intf->ndev_dn);
of_node_put(intf->phy_dn);
free_netdev(intf->ndev);
}