示例#1
0
文件: bgmac.c 项目: 545191228/linux
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;
}
示例#2
0
文件: hip04_eth.c 项目: mhei/linux
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;
}
示例#3
0
文件: hip04_eth.c 项目: mhei/linux
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;
}