diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c index 972474893a6b..f41a79529f10 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c @@ -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)); } diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.h b/drivers/net/ethernet/broadcom/asp2/bcmasp.h index 8c8ffaeadc79..9c9721da1662 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.h +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.h @@ -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; diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c index f2176ef3a127..a855e637b6f0 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c @@ -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); }