Commit 561aa0e2 authored by Thomas Fourier's avatar Thomas Fourier Committed by David S. Miller
Browse files

nui: Fix dma_mapping_error() check



dma_map_XXX() functions return values DMA_MAPPING_ERROR as error values
which is often ~0.  The error value should be tested with
dma_mapping_error().

This patch creates a new function in niu_ops to test if the mapping
failed.  The test is fixed in niu_rbr_add_page(), added in
niu_start_xmit() and the successfully mapped pages are unmaped upon error.

Fixes: ec2deec1 ("niu: Fix to check for dma mapping errors.")
Signed-off-by: default avatarThomas Fourier <fourier.thomas@gmail.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 34a500ca
Loading
Loading
Loading
Loading
+30 −1
Original line number Diff line number Diff line
@@ -3336,7 +3336,7 @@ static int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp,

	addr = np->ops->map_page(np->device, page, 0,
				 PAGE_SIZE, DMA_FROM_DEVICE);
	if (!addr) {
	if (np->ops->mapping_error(np->device, addr)) {
		__free_page(page);
		return -ENOMEM;
	}
@@ -6676,6 +6676,8 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb,
	len = skb_headlen(skb);
	mapping = np->ops->map_single(np->device, skb->data,
				      len, DMA_TO_DEVICE);
	if (np->ops->mapping_error(np->device, mapping))
		goto out_drop;

	prod = rp->prod;

@@ -6717,6 +6719,8 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb,
		mapping = np->ops->map_page(np->device, skb_frag_page(frag),
					    skb_frag_off(frag), len,
					    DMA_TO_DEVICE);
		if (np->ops->mapping_error(np->device, mapping))
			goto out_unmap;

		rp->tx_buffs[prod].skb = NULL;
		rp->tx_buffs[prod].mapping = mapping;
@@ -6741,6 +6745,19 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb,
out:
	return NETDEV_TX_OK;

out_unmap:
	while (i--) {
		const skb_frag_t *frag;

		prod = PREVIOUS_TX(rp, prod);
		frag = &skb_shinfo(skb)->frags[i];
		np->ops->unmap_page(np->device, rp->tx_buffs[prod].mapping,
				    skb_frag_size(frag), DMA_TO_DEVICE);
	}

	np->ops->unmap_single(np->device, rp->tx_buffs[rp->prod].mapping,
			      skb_headlen(skb), DMA_TO_DEVICE);

out_drop:
	rp->tx_errors++;
	kfree_skb(skb);
@@ -9644,6 +9661,11 @@ static void niu_pci_unmap_single(struct device *dev, u64 dma_address,
	dma_unmap_single(dev, dma_address, size, direction);
}

static int niu_pci_mapping_error(struct device *dev, u64 addr)
{
	return dma_mapping_error(dev, addr);
}

static const struct niu_ops niu_pci_ops = {
	.alloc_coherent	= niu_pci_alloc_coherent,
	.free_coherent	= niu_pci_free_coherent,
@@ -9651,6 +9673,7 @@ static const struct niu_ops niu_pci_ops = {
	.unmap_page	= niu_pci_unmap_page,
	.map_single	= niu_pci_map_single,
	.unmap_single	= niu_pci_unmap_single,
	.mapping_error	= niu_pci_mapping_error,
};

static void niu_driver_version(void)
@@ -10019,6 +10042,11 @@ static void niu_phys_unmap_single(struct device *dev, u64 dma_address,
	/* Nothing to do.  */
}

static int niu_phys_mapping_error(struct device *dev, u64 dma_address)
{
	return false;
}

static const struct niu_ops niu_phys_ops = {
	.alloc_coherent	= niu_phys_alloc_coherent,
	.free_coherent	= niu_phys_free_coherent,
@@ -10026,6 +10054,7 @@ static const struct niu_ops niu_phys_ops = {
	.unmap_page	= niu_phys_unmap_page,
	.map_single	= niu_phys_map_single,
	.unmap_single	= niu_phys_unmap_single,
	.mapping_error	= niu_phys_mapping_error,
};

static int niu_of_probe(struct platform_device *op)
+4 −0
Original line number Diff line number Diff line
@@ -2879,6 +2879,9 @@ struct tx_ring_info {
#define NEXT_TX(tp, index) \
	(((index) + 1) < (tp)->pending ? ((index) + 1) : 0)

#define PREVIOUS_TX(tp, index) \
	(((index) - 1) >= 0 ? ((index) - 1) : (((tp)->pending) - 1))

static inline u32 niu_tx_avail(struct tx_ring_info *tp)
{
	return (tp->pending -
@@ -3140,6 +3143,7 @@ struct niu_ops {
			  enum dma_data_direction direction);
	void (*unmap_single)(struct device *dev, u64 dma_address,
			     size_t size, enum dma_data_direction direction);
	int (*mapping_error)(struct device *dev, u64 dma_address);
};

struct niu_link_config {