enic: check dma_mapping_error
This patch checks for pci_dma_mapping_error() after dma mapping the data. If the dma mapping fails we remove the previously queued frags and return NETDEV_TX_OK. Reported-by: Jan Stancek <jstancek@redhat.com> Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
5e32066d00
commit
065df159ec
@@ -242,6 +242,18 @@ static inline unsigned int enic_msix_notify_intr(struct enic *enic)
|
|||||||
return enic->rq_count + enic->wq_count + 1;
|
return enic->rq_count + enic->wq_count + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int enic_dma_map_check(struct enic *enic, dma_addr_t dma_addr)
|
||||||
|
{
|
||||||
|
if (unlikely(pci_dma_mapping_error(enic->pdev, dma_addr))) {
|
||||||
|
net_warn_ratelimited("%s: PCI dma mapping failed!\n",
|
||||||
|
enic->netdev->name);
|
||||||
|
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void enic_reset_addr_lists(struct enic *enic);
|
void enic_reset_addr_lists(struct enic *enic);
|
||||||
int enic_sriov_enabled(struct enic *enic);
|
int enic_sriov_enabled(struct enic *enic);
|
||||||
int enic_is_valid_vf(struct enic *enic, int vf);
|
int enic_is_valid_vf(struct enic *enic, int vf);
|
||||||
|
@@ -351,80 +351,94 @@ static irqreturn_t enic_isr_msix_notify(int irq, void *data)
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void enic_queue_wq_skb_cont(struct enic *enic,
|
static int enic_queue_wq_skb_cont(struct enic *enic, struct vnic_wq *wq,
|
||||||
struct vnic_wq *wq, struct sk_buff *skb,
|
struct sk_buff *skb, unsigned int len_left,
|
||||||
unsigned int len_left, int loopback)
|
int loopback)
|
||||||
{
|
{
|
||||||
const skb_frag_t *frag;
|
const skb_frag_t *frag;
|
||||||
|
dma_addr_t dma_addr;
|
||||||
|
|
||||||
/* Queue additional data fragments */
|
/* Queue additional data fragments */
|
||||||
for (frag = skb_shinfo(skb)->frags; len_left; frag++) {
|
for (frag = skb_shinfo(skb)->frags; len_left; frag++) {
|
||||||
len_left -= skb_frag_size(frag);
|
len_left -= skb_frag_size(frag);
|
||||||
enic_queue_wq_desc_cont(wq, skb,
|
dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag, 0,
|
||||||
skb_frag_dma_map(&enic->pdev->dev,
|
|
||||||
frag, 0, skb_frag_size(frag),
|
|
||||||
DMA_TO_DEVICE),
|
|
||||||
skb_frag_size(frag),
|
skb_frag_size(frag),
|
||||||
|
DMA_TO_DEVICE);
|
||||||
|
if (unlikely(enic_dma_map_check(enic, dma_addr)))
|
||||||
|
return -ENOMEM;
|
||||||
|
enic_queue_wq_desc_cont(wq, skb, dma_addr, skb_frag_size(frag),
|
||||||
(len_left == 0), /* EOP? */
|
(len_left == 0), /* EOP? */
|
||||||
loopback);
|
loopback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void enic_queue_wq_skb_vlan(struct enic *enic,
|
static int enic_queue_wq_skb_vlan(struct enic *enic, struct vnic_wq *wq,
|
||||||
struct vnic_wq *wq, struct sk_buff *skb,
|
struct sk_buff *skb, int vlan_tag_insert,
|
||||||
int vlan_tag_insert, unsigned int vlan_tag, int loopback)
|
unsigned int vlan_tag, int loopback)
|
||||||
{
|
{
|
||||||
unsigned int head_len = skb_headlen(skb);
|
unsigned int head_len = skb_headlen(skb);
|
||||||
unsigned int len_left = skb->len - head_len;
|
unsigned int len_left = skb->len - head_len;
|
||||||
int eop = (len_left == 0);
|
int eop = (len_left == 0);
|
||||||
|
dma_addr_t dma_addr;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
dma_addr = pci_map_single(enic->pdev, skb->data, head_len,
|
||||||
|
PCI_DMA_TODEVICE);
|
||||||
|
if (unlikely(enic_dma_map_check(enic, dma_addr)))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Queue the main skb fragment. The fragments are no larger
|
/* Queue the main skb fragment. The fragments are no larger
|
||||||
* than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less
|
* than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less
|
||||||
* than WQ_ENET_MAX_DESC_LEN length. So only one descriptor
|
* than WQ_ENET_MAX_DESC_LEN length. So only one descriptor
|
||||||
* per fragment is queued.
|
* per fragment is queued.
|
||||||
*/
|
*/
|
||||||
enic_queue_wq_desc(wq, skb,
|
enic_queue_wq_desc(wq, skb, dma_addr, head_len, vlan_tag_insert,
|
||||||
pci_map_single(enic->pdev, skb->data,
|
vlan_tag, eop, loopback);
|
||||||
head_len, PCI_DMA_TODEVICE),
|
|
||||||
head_len,
|
|
||||||
vlan_tag_insert, vlan_tag,
|
|
||||||
eop, loopback);
|
|
||||||
|
|
||||||
if (!eop)
|
if (!eop)
|
||||||
enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
|
err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void enic_queue_wq_skb_csum_l4(struct enic *enic,
|
static int enic_queue_wq_skb_csum_l4(struct enic *enic, struct vnic_wq *wq,
|
||||||
struct vnic_wq *wq, struct sk_buff *skb,
|
struct sk_buff *skb, int vlan_tag_insert,
|
||||||
int vlan_tag_insert, unsigned int vlan_tag, int loopback)
|
unsigned int vlan_tag, int loopback)
|
||||||
{
|
{
|
||||||
unsigned int head_len = skb_headlen(skb);
|
unsigned int head_len = skb_headlen(skb);
|
||||||
unsigned int len_left = skb->len - head_len;
|
unsigned int len_left = skb->len - head_len;
|
||||||
unsigned int hdr_len = skb_checksum_start_offset(skb);
|
unsigned int hdr_len = skb_checksum_start_offset(skb);
|
||||||
unsigned int csum_offset = hdr_len + skb->csum_offset;
|
unsigned int csum_offset = hdr_len + skb->csum_offset;
|
||||||
int eop = (len_left == 0);
|
int eop = (len_left == 0);
|
||||||
|
dma_addr_t dma_addr;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
dma_addr = pci_map_single(enic->pdev, skb->data, head_len,
|
||||||
|
PCI_DMA_TODEVICE);
|
||||||
|
if (unlikely(enic_dma_map_check(enic, dma_addr)))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Queue the main skb fragment. The fragments are no larger
|
/* Queue the main skb fragment. The fragments are no larger
|
||||||
* than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less
|
* than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less
|
||||||
* than WQ_ENET_MAX_DESC_LEN length. So only one descriptor
|
* than WQ_ENET_MAX_DESC_LEN length. So only one descriptor
|
||||||
* per fragment is queued.
|
* per fragment is queued.
|
||||||
*/
|
*/
|
||||||
enic_queue_wq_desc_csum_l4(wq, skb,
|
enic_queue_wq_desc_csum_l4(wq, skb, dma_addr, head_len, csum_offset,
|
||||||
pci_map_single(enic->pdev, skb->data,
|
hdr_len, vlan_tag_insert, vlan_tag, eop,
|
||||||
head_len, PCI_DMA_TODEVICE),
|
loopback);
|
||||||
head_len,
|
|
||||||
csum_offset,
|
|
||||||
hdr_len,
|
|
||||||
vlan_tag_insert, vlan_tag,
|
|
||||||
eop, loopback);
|
|
||||||
|
|
||||||
if (!eop)
|
if (!eop)
|
||||||
enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
|
err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void enic_queue_wq_skb_tso(struct enic *enic,
|
static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq,
|
||||||
struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss,
|
struct sk_buff *skb, unsigned int mss,
|
||||||
int vlan_tag_insert, unsigned int vlan_tag, int loopback)
|
int vlan_tag_insert, unsigned int vlan_tag,
|
||||||
|
int loopback)
|
||||||
{
|
{
|
||||||
unsigned int frag_len_left = skb_headlen(skb);
|
unsigned int frag_len_left = skb_headlen(skb);
|
||||||
unsigned int len_left = skb->len - frag_len_left;
|
unsigned int len_left = skb->len - frag_len_left;
|
||||||
@@ -454,12 +468,11 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic,
|
|||||||
*/
|
*/
|
||||||
while (frag_len_left) {
|
while (frag_len_left) {
|
||||||
len = min(frag_len_left, (unsigned int)WQ_ENET_MAX_DESC_LEN);
|
len = min(frag_len_left, (unsigned int)WQ_ENET_MAX_DESC_LEN);
|
||||||
dma_addr = pci_map_single(enic->pdev, skb->data + offset,
|
dma_addr = pci_map_single(enic->pdev, skb->data + offset, len,
|
||||||
len, PCI_DMA_TODEVICE);
|
PCI_DMA_TODEVICE);
|
||||||
enic_queue_wq_desc_tso(wq, skb,
|
if (unlikely(enic_dma_map_check(enic, dma_addr)))
|
||||||
dma_addr,
|
return -ENOMEM;
|
||||||
len,
|
enic_queue_wq_desc_tso(wq, skb, dma_addr, len, mss, hdr_len,
|
||||||
mss, hdr_len,
|
|
||||||
vlan_tag_insert, vlan_tag,
|
vlan_tag_insert, vlan_tag,
|
||||||
eop && (len == frag_len_left), loopback);
|
eop && (len == frag_len_left), loopback);
|
||||||
frag_len_left -= len;
|
frag_len_left -= len;
|
||||||
@@ -467,7 +480,7 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (eop)
|
if (eop)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
/* Queue WQ_ENET_MAX_DESC_LEN length descriptors
|
/* Queue WQ_ENET_MAX_DESC_LEN length descriptors
|
||||||
* for additional data fragments
|
* for additional data fragments
|
||||||
@@ -483,16 +496,18 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic,
|
|||||||
dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag,
|
dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag,
|
||||||
offset, len,
|
offset, len,
|
||||||
DMA_TO_DEVICE);
|
DMA_TO_DEVICE);
|
||||||
enic_queue_wq_desc_cont(wq, skb,
|
if (unlikely(enic_dma_map_check(enic, dma_addr)))
|
||||||
dma_addr,
|
return -ENOMEM;
|
||||||
len,
|
enic_queue_wq_desc_cont(wq, skb, dma_addr, len,
|
||||||
(len_left == 0) &&
|
(len_left == 0) &&
|
||||||
(len == frag_len_left), /* EOP? */
|
(len == frag_len_left),/*EOP*/
|
||||||
loopback);
|
loopback);
|
||||||
frag_len_left -= len;
|
frag_len_left -= len;
|
||||||
offset += len;
|
offset += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void enic_queue_wq_skb(struct enic *enic,
|
static inline void enic_queue_wq_skb(struct enic *enic,
|
||||||
@@ -502,6 +517,7 @@ static inline void enic_queue_wq_skb(struct enic *enic,
|
|||||||
unsigned int vlan_tag = 0;
|
unsigned int vlan_tag = 0;
|
||||||
int vlan_tag_insert = 0;
|
int vlan_tag_insert = 0;
|
||||||
int loopback = 0;
|
int loopback = 0;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (vlan_tx_tag_present(skb)) {
|
if (vlan_tx_tag_present(skb)) {
|
||||||
/* VLAN tag from trunking driver */
|
/* VLAN tag from trunking driver */
|
||||||
@@ -513,14 +529,30 @@ static inline void enic_queue_wq_skb(struct enic *enic,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mss)
|
if (mss)
|
||||||
enic_queue_wq_skb_tso(enic, wq, skb, mss,
|
err = enic_queue_wq_skb_tso(enic, wq, skb, mss,
|
||||||
vlan_tag_insert, vlan_tag, loopback);
|
vlan_tag_insert, vlan_tag,
|
||||||
|
loopback);
|
||||||
else if (skb->ip_summed == CHECKSUM_PARTIAL)
|
else if (skb->ip_summed == CHECKSUM_PARTIAL)
|
||||||
enic_queue_wq_skb_csum_l4(enic, wq, skb,
|
err = enic_queue_wq_skb_csum_l4(enic, wq, skb, vlan_tag_insert,
|
||||||
vlan_tag_insert, vlan_tag, loopback);
|
vlan_tag, loopback);
|
||||||
else
|
else
|
||||||
enic_queue_wq_skb_vlan(enic, wq, skb,
|
err = enic_queue_wq_skb_vlan(enic, wq, skb, vlan_tag_insert,
|
||||||
vlan_tag_insert, vlan_tag, loopback);
|
vlan_tag, loopback);
|
||||||
|
if (unlikely(err)) {
|
||||||
|
struct vnic_wq_buf *buf;
|
||||||
|
|
||||||
|
buf = wq->to_use->prev;
|
||||||
|
/* while not EOP of previous pkt && queue not empty.
|
||||||
|
* For all non EOP bufs, os_buf is NULL.
|
||||||
|
*/
|
||||||
|
while (!buf->os_buf && (buf->next != wq->to_clean)) {
|
||||||
|
enic_free_wq_buf(wq, buf);
|
||||||
|
wq->ring.desc_avail++;
|
||||||
|
buf = buf->prev;
|
||||||
|
}
|
||||||
|
wq->to_use = buf->next;
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* netif_tx_lock held, process context with BHs disabled, or BH */
|
/* netif_tx_lock held, process context with BHs disabled, or BH */
|
||||||
@@ -950,8 +982,12 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq)
|
|||||||
if (!skb)
|
if (!skb)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
dma_addr = pci_map_single(enic->pdev, skb->data,
|
dma_addr = pci_map_single(enic->pdev, skb->data, len,
|
||||||
len, PCI_DMA_FROMDEVICE);
|
PCI_DMA_FROMDEVICE);
|
||||||
|
if (unlikely(enic_dma_map_check(enic, dma_addr))) {
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
enic_queue_rq_desc(rq, skb, os_buf_index,
|
enic_queue_rq_desc(rq, skb, os_buf_index,
|
||||||
dma_addr, len);
|
dma_addr, len);
|
||||||
|
Reference in New Issue
Block a user