nui: Fix dma_mapping_error() check
[ Upstream commit 561aa0e22b70a5e7246b73d62a824b3aef3fc375 ]
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: ec2deec1f3
("niu: Fix to check for dma mapping errors.")
Signed-off-by: Thomas Fourier <fourier.thomas@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
7a1841c960
commit
5ea2a10be7
@@ -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;
|
||||
}
|
||||
@@ -6672,6 +6672,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;
|
||||
|
||||
@@ -6713,6 +6715,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;
|
||||
@@ -6737,6 +6741,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);
|
||||
@@ -9636,6 +9653,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,
|
||||
@@ -9643,6 +9665,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)
|
||||
@@ -10009,6 +10032,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,
|
||||
@@ -10016,6 +10044,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)
|
||||
|
@@ -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 {
|
||||
|
Reference in New Issue
Block a user