Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+107 −7
Original line number Diff line number Diff line
@@ -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,
					    struct ql_rcv_buf_cb *lrg_buf_cb)
{
	u64 map;
	dma_addr_t map;
	int err;
	lrg_buf_cb->next = NULL;

	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,
					     qdev->lrg_buffer_len -
					     QL_HEADER_SPACE,
					     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 =
			    cpu_to_le32(LS_64BITS(map));
			lrg_buf_cb->buf_phy_addr_high =
@@ -1624,7 +1636,8 @@ static const struct ethtool_ops ql3xxx_ethtool_ops = {
static int ql_populate_free_queue(struct ql3_adapter *qdev)
{
	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) {
		if (!lrg_buf_cb->skb) {
@@ -1646,6 +1659,17 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
						     qdev->lrg_buffer_len -
						     QL_HEADER_SPACE,
						     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 =
				    cpu_to_le32(LS_64BITS(map));
				lrg_buf_cb->buf_phy_addr_high =
@@ -2147,7 +2171,9 @@ static int ql_send_map(struct ql3_adapter *qdev,
	struct oal *oal;
	struct oal_entry *oal_entry;
	int len = skb_headlen(skb);
	u64 map;
	dma_addr_t map;
	int err;
	int completed_segs, i;
	int seg_cnt, seg = 0;
	int frag_cnt = (int)skb_shinfo(skb)->nr_frags;

@@ -2160,6 +2186,15 @@ static int ql_send_map(struct ql3_adapter *qdev,
	 * Map the skb buffer first.
	 */
	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->dma_lo = cpu_to_le32(LS_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,
		oal_entry->len =
		    cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
	} else {
		int i;
		oal = tx_cb->oal;
		for (i=0; i<frag_cnt; i++,seg++) {
			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
		for (completed_segs=0; completed_segs<frag_cnt; completed_segs++,seg++) {
			skb_frag_t *frag = &skb_shinfo(skb)->frags[completed_segs];
			oal_entry++;
			if ((seg == 2 && seg_cnt > 3) ||	/* Check for continuation */
			    (seg == 7 && seg_cnt > 8) ||	/* requirements. It's strange */
@@ -2186,6 +2220,15 @@ static int ql_send_map(struct ql3_adapter *qdev,
				map = pci_map_single(qdev->pdev, oal,
						     sizeof(struct oal),
						     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_hi = cpu_to_le32(MS_64BITS(map));
				oal_entry->len =
@@ -2204,6 +2247,14 @@ static int ql_send_map(struct ql3_adapter *qdev,
			    pci_map_page(qdev->pdev, frag->page,
					 frag->page_offset, frag->size,
					 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_hi = cpu_to_le32(MS_64BITS(map));
			oal_entry->len = cpu_to_le32(frag->size);
@@ -2215,7 +2266,46 @@ static int ql_send_map(struct ql3_adapter *qdev,
		oal_entry->len =
		    cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
	}

	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)
	int i;
	struct ql_rcv_buf_cb *lrg_buf_cb;
	struct sk_buff *skb;
	u64 map;
	dma_addr_t map;
	int err;

	for (i = 0; i < qdev->num_large_buffers; i++) {
		skb = netdev_alloc_skb(qdev->ndev,
@@ -2558,6 +2649,15 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
					     qdev->lrg_buffer_len -
					     QL_HEADER_SPACE,
					     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_len_set(lrg_buf_cb, maplen,
					  qdev->lrg_buffer_len -