Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73a37079 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

forcedeth: fix dma api mismatches



forcedeth doesnt use properly dma api in its tx completion path
and in nv_loopback_test()

pci_map_single() should be paired with pci_unmap_single()
pci_map_page() should be paired with pci_unmap_page()

forcedeth xmit path uses pci_map_single() & pci_map_page(),
but tx completion path only uses pci_unmap_single()

nv_loopback_test() uses pci_map_single() & pci_unmap_page()

Add a dma_single field in struct nv_skb_map, and
define a helper function nv_unmap_txskb

Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
CC: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 81e2a3d5
Loading
Loading
Loading
Loading
+27 −19
Original line number Diff line number Diff line
@@ -719,7 +719,8 @@ static const struct register_test nv_registers_test[] = {
struct nv_skb_map {
	struct sk_buff *skb;
	dma_addr_t dma;
	unsigned int dma_len;
	unsigned int dma_len:31;
	unsigned int dma_single:1;
	struct ring_desc_ex *first_tx_desc;
	struct nv_skb_map *next_tx_ctx;
};
@@ -1912,6 +1913,7 @@ static void nv_init_tx(struct net_device *dev)
		np->tx_skb[i].skb = NULL;
		np->tx_skb[i].dma = 0;
		np->tx_skb[i].dma_len = 0;
		np->tx_skb[i].dma_single = 0;
		np->tx_skb[i].first_tx_desc = NULL;
		np->tx_skb[i].next_tx_ctx = NULL;
	}
@@ -1930,23 +1932,30 @@ static int nv_init_ring(struct net_device *dev)
		return nv_alloc_rx_optimized(dev);
}

static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb)
static void nv_unmap_txskb(struct fe_priv *np, struct nv_skb_map *tx_skb)
{
	struct fe_priv *np = netdev_priv(dev);

	if (tx_skb->dma) {
		if (tx_skb->dma_single)
			pci_unmap_single(np->pci_dev, tx_skb->dma,
					 tx_skb->dma_len,
					 PCI_DMA_TODEVICE);
		else
			pci_unmap_page(np->pci_dev, tx_skb->dma,
				       tx_skb->dma_len,
				       PCI_DMA_TODEVICE);
		tx_skb->dma = 0;
	}
}

static int nv_release_txskb(struct fe_priv *np, struct nv_skb_map *tx_skb)
{
	nv_unmap_txskb(np, tx_skb);
	if (tx_skb->skb) {
		dev_kfree_skb_any(tx_skb->skb);
		tx_skb->skb = NULL;
		return 1;
	} else {
		return 0;
	}
	return 0;
}

static void nv_drain_tx(struct net_device *dev)
@@ -1964,10 +1973,11 @@ static void nv_drain_tx(struct net_device *dev)
			np->tx_ring.ex[i].bufhigh = 0;
			np->tx_ring.ex[i].buflow = 0;
		}
		if (nv_release_txskb(dev, &np->tx_skb[i]))
		if (nv_release_txskb(np, &np->tx_skb[i]))
			dev->stats.tx_dropped++;
		np->tx_skb[i].dma = 0;
		np->tx_skb[i].dma_len = 0;
		np->tx_skb[i].dma_single = 0;
		np->tx_skb[i].first_tx_desc = NULL;
		np->tx_skb[i].next_tx_ctx = NULL;
	}
@@ -2171,6 +2181,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
		np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
						PCI_DMA_TODEVICE);
		np->put_tx_ctx->dma_len = bcnt;
		np->put_tx_ctx->dma_single = 1;
		put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
		put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);

@@ -2196,6 +2207,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
			np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
							   PCI_DMA_TODEVICE);
			np->put_tx_ctx->dma_len = bcnt;
			np->put_tx_ctx->dma_single = 0;
			put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
			put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);

@@ -2291,6 +2303,7 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
		np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
						PCI_DMA_TODEVICE);
		np->put_tx_ctx->dma_len = bcnt;
		np->put_tx_ctx->dma_single = 1;
		put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma));
		put_tx->buflow = cpu_to_le32(dma_low(np->put_tx_ctx->dma));
		put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
@@ -2317,6 +2330,7 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
			np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
							   PCI_DMA_TODEVICE);
			np->put_tx_ctx->dma_len = bcnt;
			np->put_tx_ctx->dma_single = 0;
			put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma));
			put_tx->buflow = cpu_to_le32(dma_low(np->put_tx_ctx->dma));
			put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
@@ -2434,10 +2448,7 @@ static int nv_tx_done(struct net_device *dev, int limit)
		dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n",
					dev->name, flags);

		pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
			       np->get_tx_ctx->dma_len,
			       PCI_DMA_TODEVICE);
		np->get_tx_ctx->dma = 0;
		nv_unmap_txskb(np, np->get_tx_ctx);

		if (np->desc_ver == DESC_VER_1) {
			if (flags & NV_TX_LASTPACKET) {
@@ -2502,10 +2513,7 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit)
		dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
					dev->name, flags);

		pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
			       np->get_tx_ctx->dma_len,
			       PCI_DMA_TODEVICE);
		np->get_tx_ctx->dma = 0;
		nv_unmap_txskb(np, np->get_tx_ctx);

		if (flags & NV_TX2_LASTPACKET) {
			if (!(flags & NV_TX2_ERROR))
@@ -5091,7 +5099,7 @@ static int nv_loopback_test(struct net_device *dev)
		dprintk(KERN_DEBUG "%s: loopback - did not receive test packet\n", dev->name);
	}

	pci_unmap_page(np->pci_dev, test_dma_addr,
	pci_unmap_single(np->pci_dev, test_dma_addr,
		       (skb_end_pointer(tx_skb) - tx_skb->data),
		       PCI_DMA_TODEVICE);
	dev_kfree_skb_any(tx_skb);