static void awg_setup_rxdesc(struct awg_softc *sc, int index, bus_addr_t paddr) { uint32_t status, size; status = RX_DESC_CTL; size = MCLBYTES - 1; sc->rx.desc_ring[index].addr = htole32((uint32_t)paddr); sc->rx.desc_ring[index].size = htole32(size); sc->rx.desc_ring[index].next = htole32(sc->rx.desc_ring_paddr + DESC_OFF(RX_NEXT(index))); sc->rx.desc_ring[index].status = htole32(status); }
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; }