diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c | 102 |
1 files changed, 61 insertions, 41 deletions
diff --git a/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c b/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c index 7ddbf8a10a..68b5bc0cd0 100644 --- a/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c +++ b/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6368-enetsw.c @@ -25,6 +25,8 @@ #define ENETSW_TAG_SIZE 6 #define ENETSW_MTU_OVERHEAD (VLAN_ETH_HLEN + VLAN_HLEN + \ ENETSW_TAG_SIZE) +#define ENETSW_FRAG_SIZE(x) (SKB_DATA_ALIGN(NET_SKB_PAD + x + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))) /* default number of descriptor */ #define ENETSW_DEF_RX_DESC 64 @@ -170,13 +172,16 @@ struct bcm6368_enetsw { /* next dirty rx descriptor to refill */ int rx_dirty_desc; - /* size of allocated rx skbs */ - unsigned int rx_skb_size; + /* size of allocated rx buffer */ + unsigned int rx_buf_size; - /* list of skb given to hw for rx */ - struct sk_buff **rx_skb; + /* size of allocated rx frag */ + unsigned int rx_frag_size; - /* used when rx skb allocation failed, so we defer rx queue + /* list of buffer given to hw for rx */ + unsigned char **rx_buf; + + /* used when rx buffer allocation failed, so we defer rx queue * refill */ struct timer_list rx_timeout; @@ -257,26 +262,27 @@ static int bcm6368_enetsw_refill_rx(struct net_device *dev) while (priv->rx_desc_count < priv->rx_ring_size) { struct bcm6368_enetsw_desc *desc; - struct sk_buff *skb; - dma_addr_t p; int desc_idx; u32 len_stat; desc_idx = priv->rx_dirty_desc; desc = &priv->rx_desc_cpu[desc_idx]; - if (!priv->rx_skb[desc_idx]) { - skb = netdev_alloc_skb(dev, priv->rx_skb_size); - if (!skb) + if (!priv->rx_buf[desc_idx]) { + unsigned char *buf = + netdev_alloc_frag(priv->rx_frag_size); + + if (unlikely(!buf)) break; - priv->rx_skb[desc_idx] = skb; - p = dma_map_single(&priv->pdev->dev, skb->data, - priv->rx_skb_size, - DMA_FROM_DEVICE); - desc->address = p; + + priv->rx_buf[desc_idx] = buf; + desc->address = dma_map_single(&priv->pdev->dev, + buf + NET_SKB_PAD, + priv->rx_buf_size, + DMA_FROM_DEVICE); } - len_stat = priv->rx_skb_size << DMADESC_LENGTH_SHIFT; + len_stat = priv->rx_buf_size << DMADESC_LENGTH_SHIFT; len_stat |= DMADESC_OWNER_MASK; if (priv->rx_dirty_desc == priv->rx_ring_size - 1) { len_stat |= DMADESC_WRAP_MASK; @@ -333,7 +339,9 @@ static int bcm6368_enetsw_receive_queue(struct net_device *dev, int budget) do { struct bcm6368_enetsw_desc *desc; + unsigned int frag_size; struct sk_buff *skb; + unsigned char *buf; int desc_idx; u32 len_stat; unsigned int len; @@ -365,17 +373,17 @@ static int bcm6368_enetsw_receive_queue(struct net_device *dev, int budget) } /* valid packet */ - skb = priv->rx_skb[desc_idx]; + buf = priv->rx_buf[desc_idx]; len = (len_stat & DMADESC_LENGTH_MASK) >> DMADESC_LENGTH_SHIFT; /* don't include FCS */ len -= 4; if (len < priv->copybreak) { - struct sk_buff *nskb; + unsigned int nfrag_size = ENETSW_FRAG_SIZE(len); + unsigned char *nbuf = napi_alloc_frag(nfrag_size); - nskb = netdev_alloc_skb(dev, len); - if (!nskb) { + if (unlikely(!nbuf)) { /* forget packet, just rearm desc */ dev->stats.rx_dropped++; continue; @@ -383,16 +391,26 @@ static int bcm6368_enetsw_receive_queue(struct net_device *dev, int budget) dma_sync_single_for_cpu(kdev, desc->address, len, DMA_FROM_DEVICE); - memcpy(nskb->data, skb->data, len); + memcpy(nbuf + NET_SKB_PAD, buf + NET_SKB_PAD, len); dma_sync_single_for_device(kdev, desc->address, len, DMA_FROM_DEVICE); - skb = nskb; + buf = nbuf; + frag_size = nfrag_size; } else { - dma_unmap_single(&priv->pdev->dev, desc->address, - priv->rx_skb_size, DMA_FROM_DEVICE); - priv->rx_skb[desc_idx] = NULL; + dma_unmap_single(kdev, desc->address, + priv->rx_buf_size, DMA_FROM_DEVICE); + priv->rx_buf[desc_idx] = NULL; + frag_size = priv->rx_frag_size; + } + + skb = build_skb(buf, frag_size); + if (unlikely(!skb)) { + skb_free_frag(buf); + dev->stats.rx_dropped++; + continue; } + skb_reserve(skb, NET_SKB_PAD); skb_put(skb, len); skb->protocol = eth_type_trans(skb, dev); dev->stats.rx_packets++; @@ -680,7 +698,7 @@ static int bcm6368_enetsw_open(struct net_device *dev) priv->tx_skb = kzalloc(sizeof(struct sk_buff *) * priv->tx_ring_size, GFP_KERNEL); if (!priv->tx_skb) { - dev_err(kdev, "cannot allocate rx skb queue\n"); + dev_err(kdev, "cannot allocate tx skb queue\n"); ret = -ENOMEM; goto out_free_tx_ring; } @@ -690,11 +708,11 @@ static int bcm6368_enetsw_open(struct net_device *dev) priv->tx_curr_desc = 0; spin_lock_init(&priv->tx_lock); - /* init & fill rx ring with skbs */ - priv->rx_skb = kzalloc(sizeof(struct sk_buff *) * priv->rx_ring_size, + /* init & fill rx ring with buffers */ + priv->rx_buf = kzalloc(sizeof(unsigned char *) * priv->rx_ring_size, GFP_KERNEL); - if (!priv->rx_skb) { - dev_err(kdev, "cannot allocate rx skb queue\n"); + if (!priv->rx_buf) { + dev_err(kdev, "cannot allocate rx buffer queue\n"); ret = -ENOMEM; goto out_free_tx_skb; } @@ -708,7 +726,7 @@ static int bcm6368_enetsw_open(struct net_device *dev) DMA_BUFALLOC_REG(priv->rx_chan)); if (bcm6368_enetsw_refill_rx(dev)) { - dev_err(kdev, "cannot allocate rx skb queue\n"); + dev_err(kdev, "cannot allocate rx buffer queue\n"); ret = -ENOMEM; goto out; } @@ -770,15 +788,15 @@ out: for (i = 0; i < priv->rx_ring_size; i++) { struct bcm6368_enetsw_desc *desc; - if (!priv->rx_skb[i]) + if (!priv->rx_buf[i]) continue; desc = &priv->rx_desc_cpu[i]; - dma_unmap_single(kdev, desc->address, priv->rx_skb_size, + dma_unmap_single(kdev, desc->address, priv->rx_buf_size, DMA_FROM_DEVICE); - kfree_skb(priv->rx_skb[i]); + skb_free_frag(priv->rx_buf[i]); } - kfree(priv->rx_skb); + kfree(priv->rx_buf); out_free_tx_skb: kfree(priv->tx_skb); @@ -823,22 +841,22 @@ static int bcm6368_enetsw_stop(struct net_device *dev) /* force reclaim of all tx buffers */ bcm6368_enetsw_tx_reclaim(dev, 1); - /* free the rx skb ring */ + /* free the rx buffer ring */ for (i = 0; i < priv->rx_ring_size; i++) { struct bcm6368_enetsw_desc *desc; - if (!priv->rx_skb[i]) + if (!priv->rx_buf[i]) continue; desc = &priv->rx_desc_cpu[i]; - dma_unmap_single_attrs(kdev, desc->address, priv->rx_skb_size, + dma_unmap_single_attrs(kdev, desc->address, priv->rx_buf_size, DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); - kfree_skb(priv->rx_skb[i]); + skb_free_frag(priv->rx_buf[i]); } /* free remaining allocated memory */ - kfree(priv->rx_skb); + kfree(priv->rx_buf); kfree(priv->tx_skb); dma_free_coherent(kdev, priv->rx_desc_alloc_size, priv->rx_desc_cpu, priv->rx_desc_dma); @@ -960,9 +978,11 @@ static int bcm6368_enetsw_probe(struct platform_device *pdev) dev_info(dev, "random mac %pM\n", ndev->dev_addr); } - priv->rx_skb_size = ALIGN(ndev->mtu + ENETSW_MTU_OVERHEAD, + priv->rx_buf_size = ALIGN(ndev->mtu + ENETSW_MTU_OVERHEAD, priv->dma_maxburst * 4); + priv->rx_frag_size = ENETSW_FRAG_SIZE(priv->rx_buf_size); + priv->num_clocks = of_clk_get_parent_count(node); if (priv->num_clocks) { priv->clock = devm_kcalloc(dev, priv->num_clocks, |