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,
|
addr = np->ops->map_page(np->device, page, 0,
|
||||||
PAGE_SIZE, DMA_FROM_DEVICE);
|
PAGE_SIZE, DMA_FROM_DEVICE);
|
||||||
if (!addr) {
|
if (np->ops->mapping_error(np->device, addr)) {
|
||||||
__free_page(page);
|
__free_page(page);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
@@ -6672,6 +6672,8 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb,
|
|||||||
len = skb_headlen(skb);
|
len = skb_headlen(skb);
|
||||||
mapping = np->ops->map_single(np->device, skb->data,
|
mapping = np->ops->map_single(np->device, skb->data,
|
||||||
len, DMA_TO_DEVICE);
|
len, DMA_TO_DEVICE);
|
||||||
|
if (np->ops->mapping_error(np->device, mapping))
|
||||||
|
goto out_drop;
|
||||||
|
|
||||||
prod = rp->prod;
|
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),
|
mapping = np->ops->map_page(np->device, skb_frag_page(frag),
|
||||||
skb_frag_off(frag), len,
|
skb_frag_off(frag), len,
|
||||||
DMA_TO_DEVICE);
|
DMA_TO_DEVICE);
|
||||||
|
if (np->ops->mapping_error(np->device, mapping))
|
||||||
|
goto out_unmap;
|
||||||
|
|
||||||
rp->tx_buffs[prod].skb = NULL;
|
rp->tx_buffs[prod].skb = NULL;
|
||||||
rp->tx_buffs[prod].mapping = mapping;
|
rp->tx_buffs[prod].mapping = mapping;
|
||||||
@@ -6737,6 +6741,19 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb,
|
|||||||
out:
|
out:
|
||||||
return NETDEV_TX_OK;
|
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:
|
out_drop:
|
||||||
rp->tx_errors++;
|
rp->tx_errors++;
|
||||||
kfree_skb(skb);
|
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);
|
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 = {
|
static const struct niu_ops niu_pci_ops = {
|
||||||
.alloc_coherent = niu_pci_alloc_coherent,
|
.alloc_coherent = niu_pci_alloc_coherent,
|
||||||
.free_coherent = niu_pci_free_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,
|
.unmap_page = niu_pci_unmap_page,
|
||||||
.map_single = niu_pci_map_single,
|
.map_single = niu_pci_map_single,
|
||||||
.unmap_single = niu_pci_unmap_single,
|
.unmap_single = niu_pci_unmap_single,
|
||||||
|
.mapping_error = niu_pci_mapping_error,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void niu_driver_version(void)
|
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. */
|
/* 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 = {
|
static const struct niu_ops niu_phys_ops = {
|
||||||
.alloc_coherent = niu_phys_alloc_coherent,
|
.alloc_coherent = niu_phys_alloc_coherent,
|
||||||
.free_coherent = niu_phys_free_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,
|
.unmap_page = niu_phys_unmap_page,
|
||||||
.map_single = niu_phys_map_single,
|
.map_single = niu_phys_map_single,
|
||||||
.unmap_single = niu_phys_unmap_single,
|
.unmap_single = niu_phys_unmap_single,
|
||||||
|
.mapping_error = niu_phys_mapping_error,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int niu_of_probe(struct platform_device *op)
|
static int niu_of_probe(struct platform_device *op)
|
||||||
|
@@ -2879,6 +2879,9 @@ struct tx_ring_info {
|
|||||||
#define NEXT_TX(tp, index) \
|
#define NEXT_TX(tp, index) \
|
||||||
(((index) + 1) < (tp)->pending ? ((index) + 1) : 0)
|
(((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)
|
static inline u32 niu_tx_avail(struct tx_ring_info *tp)
|
||||||
{
|
{
|
||||||
return (tp->pending -
|
return (tp->pending -
|
||||||
@@ -3140,6 +3143,7 @@ struct niu_ops {
|
|||||||
enum dma_data_direction direction);
|
enum dma_data_direction direction);
|
||||||
void (*unmap_single)(struct device *dev, u64 dma_address,
|
void (*unmap_single)(struct device *dev, u64 dma_address,
|
||||||
size_t size, enum dma_data_direction direction);
|
size_t size, enum dma_data_direction direction);
|
||||||
|
int (*mapping_error)(struct device *dev, u64 dma_address);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct niu_link_config {
|
struct niu_link_config {
|
||||||
|
Reference in New Issue
Block a user