Commit 0f8ab89e authored by Benjamin Li's avatar Benjamin Li Committed by Jeff Garzik

qla3xxx: Check return code from pci_map_single() in...

qla3xxx: Check return code from pci_map_single() in ql_release_to_lrg_buf_free_list(), ql_populate_free_queue(), ql_alloc_large_buffers(), and ql3xxx_send()

pci_map_single() could fail.  We need to properly check the return
code from pci_map_single().  If we can not properly map this address,
then we should cleanup and return the proper return code.
Signed-off-by: default avatarBenjamin Li <benjamin.li@qlogic.com>
Signed-off-by: default avatarRon Mercer <ron.mercer@qlogic.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 3e71f6dd
...@@ -276,7 +276,8 @@ static void ql_enable_interrupts(struct ql3_adapter *qdev) ...@@ -276,7 +276,8 @@ static void ql_enable_interrupts(struct ql3_adapter *qdev)
static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev, static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
struct ql_rcv_buf_cb *lrg_buf_cb) struct ql_rcv_buf_cb *lrg_buf_cb)
{ {
u64 map; dma_addr_t map;
int err;
lrg_buf_cb->next = NULL; lrg_buf_cb->next = NULL;
if (qdev->lrg_buf_free_tail == NULL) { /* The list is empty */ if (qdev->lrg_buf_free_tail == NULL) { /* The list is empty */
...@@ -304,6 +305,17 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev, ...@@ -304,6 +305,17 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
qdev->lrg_buffer_len - qdev->lrg_buffer_len -
QL_HEADER_SPACE, QL_HEADER_SPACE,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
err = pci_dma_mapping_error(map);
if(err) {
printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
qdev->ndev->name, err);
dev_kfree_skb(lrg_buf_cb->skb);
lrg_buf_cb->skb = NULL;
qdev->lrg_buf_skb_check++;
return;
}
lrg_buf_cb->buf_phy_addr_low = lrg_buf_cb->buf_phy_addr_low =
cpu_to_le32(LS_64BITS(map)); cpu_to_le32(LS_64BITS(map));
lrg_buf_cb->buf_phy_addr_high = lrg_buf_cb->buf_phy_addr_high =
...@@ -1624,7 +1636,8 @@ static const struct ethtool_ops ql3xxx_ethtool_ops = { ...@@ -1624,7 +1636,8 @@ static const struct ethtool_ops ql3xxx_ethtool_ops = {
static int ql_populate_free_queue(struct ql3_adapter *qdev) static int ql_populate_free_queue(struct ql3_adapter *qdev)
{ {
struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head; struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head;
u64 map; dma_addr_t map;
int err;
while (lrg_buf_cb) { while (lrg_buf_cb) {
if (!lrg_buf_cb->skb) { if (!lrg_buf_cb->skb) {
...@@ -1646,6 +1659,17 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev) ...@@ -1646,6 +1659,17 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
qdev->lrg_buffer_len - qdev->lrg_buffer_len -
QL_HEADER_SPACE, QL_HEADER_SPACE,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
err = pci_dma_mapping_error(map);
if(err) {
printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
qdev->ndev->name, err);
dev_kfree_skb(lrg_buf_cb->skb);
lrg_buf_cb->skb = NULL;
break;
}
lrg_buf_cb->buf_phy_addr_low = lrg_buf_cb->buf_phy_addr_low =
cpu_to_le32(LS_64BITS(map)); cpu_to_le32(LS_64BITS(map));
lrg_buf_cb->buf_phy_addr_high = lrg_buf_cb->buf_phy_addr_high =
...@@ -2147,7 +2171,9 @@ static int ql_send_map(struct ql3_adapter *qdev, ...@@ -2147,7 +2171,9 @@ static int ql_send_map(struct ql3_adapter *qdev,
struct oal *oal; struct oal *oal;
struct oal_entry *oal_entry; struct oal_entry *oal_entry;
int len = skb_headlen(skb); int len = skb_headlen(skb);
u64 map; dma_addr_t map;
int err;
int completed_segs, i;
int seg_cnt, seg = 0; int seg_cnt, seg = 0;
int frag_cnt = (int)skb_shinfo(skb)->nr_frags; int frag_cnt = (int)skb_shinfo(skb)->nr_frags;
...@@ -2160,6 +2186,15 @@ static int ql_send_map(struct ql3_adapter *qdev, ...@@ -2160,6 +2186,15 @@ static int ql_send_map(struct ql3_adapter *qdev,
* Map the skb buffer first. * Map the skb buffer first.
*/ */
map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE); map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
err = pci_dma_mapping_error(map);
if(err) {
printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
qdev->ndev->name, err);
return NETDEV_TX_BUSY;
}
oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low; oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
...@@ -2173,10 +2208,9 @@ static int ql_send_map(struct ql3_adapter *qdev, ...@@ -2173,10 +2208,9 @@ static int ql_send_map(struct ql3_adapter *qdev,
oal_entry->len = oal_entry->len =
cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY); cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
} else { } else {
int i;
oal = tx_cb->oal; oal = tx_cb->oal;
for (i=0; i<frag_cnt; i++,seg++) { for (completed_segs=0; completed_segs<frag_cnt; completed_segs++,seg++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; skb_frag_t *frag = &skb_shinfo(skb)->frags[completed_segs];
oal_entry++; oal_entry++;
if ((seg == 2 && seg_cnt > 3) || /* Check for continuation */ if ((seg == 2 && seg_cnt > 3) || /* Check for continuation */
(seg == 7 && seg_cnt > 8) || /* requirements. It's strange */ (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */
...@@ -2186,6 +2220,15 @@ static int ql_send_map(struct ql3_adapter *qdev, ...@@ -2186,6 +2220,15 @@ static int ql_send_map(struct ql3_adapter *qdev,
map = pci_map_single(qdev->pdev, oal, map = pci_map_single(qdev->pdev, oal,
sizeof(struct oal), sizeof(struct oal),
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
err = pci_dma_mapping_error(map);
if(err) {
printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n",
qdev->ndev->name, err);
goto map_error;
}
oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
oal_entry->len = oal_entry->len =
...@@ -2204,6 +2247,14 @@ static int ql_send_map(struct ql3_adapter *qdev, ...@@ -2204,6 +2247,14 @@ static int ql_send_map(struct ql3_adapter *qdev,
pci_map_page(qdev->pdev, frag->page, pci_map_page(qdev->pdev, frag->page,
frag->page_offset, frag->size, frag->page_offset, frag->size,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
err = pci_dma_mapping_error(map);
if(err) {
printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n",
qdev->ndev->name, err);
goto map_error;
}
oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
oal_entry->len = cpu_to_le32(frag->size); oal_entry->len = cpu_to_le32(frag->size);
...@@ -2215,7 +2266,46 @@ static int ql_send_map(struct ql3_adapter *qdev, ...@@ -2215,7 +2266,46 @@ static int ql_send_map(struct ql3_adapter *qdev,
oal_entry->len = oal_entry->len =
cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY); cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
} }
return NETDEV_TX_OK; return NETDEV_TX_OK;
map_error:
/* A PCI mapping failed and now we will need to back out
* We need to traverse through the oal's and associated pages which
* have been mapped and now we must unmap them to clean up properly
*/
seg = 1;
oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
oal = tx_cb->oal;
for (i=0; i<completed_segs; i++,seg++) {
oal_entry++;
if((seg == 2 && seg_cnt > 3) || /* Check for continuation */
(seg == 7 && seg_cnt > 8) || /* requirements. It's strange */
(seg == 12 && seg_cnt > 13) || /* but necessary. */
(seg == 17 && seg_cnt > 18)) {
pci_unmap_single(qdev->pdev,
pci_unmap_addr(&tx_cb->map[seg], mapaddr),
pci_unmap_len(&tx_cb->map[seg], maplen),
PCI_DMA_TODEVICE);
oal++;
seg++;
}
pci_unmap_page(qdev->pdev,
pci_unmap_addr(&tx_cb->map[seg], mapaddr),
pci_unmap_len(&tx_cb->map[seg], maplen),
PCI_DMA_TODEVICE);
}
pci_unmap_single(qdev->pdev,
pci_unmap_addr(&tx_cb->map[0], mapaddr),
pci_unmap_addr(&tx_cb->map[0], maplen),
PCI_DMA_TODEVICE);
return NETDEV_TX_BUSY;
} }
/* /*
...@@ -2528,7 +2618,8 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev) ...@@ -2528,7 +2618,8 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
int i; int i;
struct ql_rcv_buf_cb *lrg_buf_cb; struct ql_rcv_buf_cb *lrg_buf_cb;
struct sk_buff *skb; struct sk_buff *skb;
u64 map; dma_addr_t map;
int err;
for (i = 0; i < qdev->num_large_buffers; i++) { for (i = 0; i < qdev->num_large_buffers; i++) {
skb = netdev_alloc_skb(qdev->ndev, skb = netdev_alloc_skb(qdev->ndev,
...@@ -2558,6 +2649,15 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev) ...@@ -2558,6 +2649,15 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
qdev->lrg_buffer_len - qdev->lrg_buffer_len -
QL_HEADER_SPACE, QL_HEADER_SPACE,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
err = pci_dma_mapping_error(map);
if(err) {
printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
qdev->ndev->name, err);
ql_free_large_buffers(qdev);
return -ENOMEM;
}
pci_unmap_addr_set(lrg_buf_cb, mapaddr, map); pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
pci_unmap_len_set(lrg_buf_cb, maplen, pci_unmap_len_set(lrg_buf_cb, maplen,
qdev->lrg_buffer_len - qdev->lrg_buffer_len -
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment