static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac, struct bgmac_slot_info *slot) { struct device *dma_dev = bgmac->core->dma_dev; dma_addr_t dma_addr; struct bgmac_rx_header *rx; void *buf; /* Alloc skb */ buf = netdev_alloc_frag(BGMAC_RX_ALLOC_SIZE); if (!buf) return -ENOMEM; /* Poison - if everything goes fine, hardware will overwrite it */ rx = buf + BGMAC_RX_BUF_OFFSET; rx->len = cpu_to_le16(0xdead); rx->flags = cpu_to_le16(0xbeef); /* Map skb for the DMA */ dma_addr = dma_map_single(dma_dev, buf + BGMAC_RX_BUF_OFFSET, BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(dma_dev, dma_addr)) { bgmac_err(bgmac, "DMA mapping error\n"); put_page(virt_to_head_page(buf)); return -ENOMEM; } /* Update the slot */ slot->buf = buf; slot->dma_addr = dma_addr; return 0; }
static int hip04_alloc_ring(struct net_device *ndev, struct device *d) { struct hip04_priv *priv = netdev_priv(ndev); int i; priv->tx_desc = dma_alloc_coherent(d, TX_DESC_NUM * sizeof(struct tx_desc), &priv->tx_desc_dma, GFP_KERNEL); if (!priv->tx_desc) return -ENOMEM; priv->rx_buf_size = RX_BUF_SIZE + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); for (i = 0; i < RX_DESC_NUM; i++) { priv->rx_buf[i] = netdev_alloc_frag(priv->rx_buf_size); if (!priv->rx_buf[i]) return -ENOMEM; } return 0; }
static int hip04_rx_poll(struct napi_struct *napi, int budget) { struct hip04_priv *priv = container_of(napi, struct hip04_priv, napi); struct net_device *ndev = priv->ndev; struct net_device_stats *stats = &ndev->stats; unsigned int cnt = hip04_recv_cnt(priv); struct rx_desc *desc; struct sk_buff *skb; unsigned char *buf; bool last = false; dma_addr_t phys; int rx = 0; int tx_remaining; u16 len; u32 err; while (cnt && !last) { buf = priv->rx_buf[priv->rx_head]; skb = build_skb(buf, priv->rx_buf_size); if (unlikely(!skb)) { net_dbg_ratelimited("build_skb failed\n"); goto refill; } dma_unmap_single(&ndev->dev, priv->rx_phys[priv->rx_head], RX_BUF_SIZE, DMA_FROM_DEVICE); priv->rx_phys[priv->rx_head] = 0; desc = (struct rx_desc *)skb->data; len = be16_to_cpu(desc->pkt_len); err = be32_to_cpu(desc->pkt_err); if (0 == len) { dev_kfree_skb_any(skb); last = true; } else if ((err & RX_PKT_ERR) || (len >= GMAC_MAX_PKT_LEN)) { dev_kfree_skb_any(skb); stats->rx_dropped++; stats->rx_errors++; } else { skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); skb_put(skb, len); skb->protocol = eth_type_trans(skb, ndev); napi_gro_receive(&priv->napi, skb); stats->rx_packets++; stats->rx_bytes += len; rx++; } refill: buf = netdev_alloc_frag(priv->rx_buf_size); if (!buf) goto done; phys = dma_map_single(&ndev->dev, buf, RX_BUF_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(&ndev->dev, phys)) goto done; priv->rx_buf[priv->rx_head] = buf; priv->rx_phys[priv->rx_head] = phys; hip04_set_recv_desc(priv, phys); priv->rx_head = RX_NEXT(priv->rx_head); if (rx >= budget) goto done; if (--cnt == 0) cnt = hip04_recv_cnt(priv); } if (!(priv->reg_inten & RCV_INT)) { /* enable rx interrupt */ priv->reg_inten |= RCV_INT; writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); } napi_complete(napi); done: /* clean up tx descriptors and start a new timer if necessary */ tx_remaining = hip04_tx_reclaim(ndev, false); if (rx < budget && tx_remaining) hip04_start_tx_timer(priv); return rx; }