diff options
Diffstat (limited to 'drivers/net/ethernet/amd/pcnet32.c')
| -rw-r--r-- | drivers/net/ethernet/amd/pcnet32.c | 204 |
1 files changed, 118 insertions, 86 deletions
diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index 20e6dab0186..e7cc9174e36 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -494,19 +494,15 @@ static void pcnet32_realloc_tx_ring(struct net_device *dev, } memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size)); - new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t), - GFP_ATOMIC); - if (!new_dma_addr_list) { - netif_err(lp, drv, dev, "Memory allocation failed\n"); + new_dma_addr_list = kcalloc(1 << size, sizeof(dma_addr_t), + GFP_ATOMIC); + if (!new_dma_addr_list) goto free_new_tx_ring; - } - new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *), - GFP_ATOMIC); - if (!new_skb_list) { - netif_err(lp, drv, dev, "Memory allocation failed\n"); + new_skb_list = kcalloc(1 << size, sizeof(struct sk_buff *), + GFP_ATOMIC); + if (!new_skb_list) goto free_new_lists; - } kfree(lp->tx_skbuff); kfree(lp->tx_dma_addr); @@ -553,46 +549,41 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, struct pcnet32_rx_head *new_rx_ring; struct sk_buff **new_skb_list; int new, overlap; + unsigned int entries = 1 << size; new_rx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * - (1 << size), + entries, &new_ring_dma_addr); if (new_rx_ring == NULL) { netif_err(lp, drv, dev, "Consistent memory allocation failed\n"); return; } - memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size)); + memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * entries); - new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t), - GFP_ATOMIC); - if (!new_dma_addr_list) { - netif_err(lp, drv, dev, "Memory allocation failed\n"); + new_dma_addr_list = kcalloc(entries, sizeof(dma_addr_t), GFP_ATOMIC); + if (!new_dma_addr_list) goto free_new_rx_ring; - } - new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *), - GFP_ATOMIC); - if (!new_skb_list) { - netif_err(lp, drv, dev, "Memory allocation failed\n"); + new_skb_list = kcalloc(entries, sizeof(struct sk_buff *), GFP_ATOMIC); + if (!new_skb_list) goto free_new_lists; - } /* first copy the current receive buffers */ - overlap = min(size, lp->rx_ring_size); + overlap = min(entries, lp->rx_ring_size); for (new = 0; new < overlap; new++) { new_rx_ring[new] = lp->rx_ring[new]; new_dma_addr_list[new] = lp->rx_dma_addr[new]; new_skb_list[new] = lp->rx_skbuff[new]; } /* now allocate any new buffers needed */ - for (; new < size; new++) { + for (; new < entries; new++) { struct sk_buff *rx_skbuff; - new_skb_list[new] = dev_alloc_skb(PKT_BUF_SKB); + new_skb_list[new] = netdev_alloc_skb(dev, PKT_BUF_SKB); rx_skbuff = new_skb_list[new]; if (!rx_skbuff) { /* keep the original lists and buffers */ - netif_err(lp, drv, dev, "%s dev_alloc_skb failed\n", + netif_err(lp, drv, dev, "%s netdev_alloc_skb failed\n", __func__); goto free_all_new; } @@ -601,6 +592,13 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, new_dma_addr_list[new] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(lp->pci_dev, + new_dma_addr_list[new])) { + netif_err(lp, drv, dev, "%s dma mapping failed\n", + __func__); + dev_kfree_skb(new_skb_list[new]); + goto free_all_new; + } new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]); new_rx_ring[new].buf_length = cpu_to_le16(NEG_BUF_SIZE); new_rx_ring[new].status = cpu_to_le16(0x8000); @@ -608,8 +606,12 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, /* and free any unneeded buffers */ for (; new < lp->rx_ring_size; new++) { if (lp->rx_skbuff[new]) { - pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new], - PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (!pci_dma_mapping_error(lp->pci_dev, + lp->rx_dma_addr[new])) + pci_unmap_single(lp->pci_dev, + lp->rx_dma_addr[new], + PKT_BUF_SIZE, + PCI_DMA_FROMDEVICE); dev_kfree_skb(lp->rx_skbuff[new]); } } @@ -621,7 +623,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, lp->rx_ring_size, lp->rx_ring, lp->rx_ring_dma_addr); - lp->rx_ring_size = (1 << size); + lp->rx_ring_size = entries; lp->rx_mod_mask = lp->rx_ring_size - 1; lp->rx_len_bits = (size << 4); lp->rx_ring = new_rx_ring; @@ -633,8 +635,12 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, free_all_new: while (--new >= lp->rx_ring_size) { if (new_skb_list[new]) { - pci_unmap_single(lp->pci_dev, new_dma_addr_list[new], - PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (!pci_dma_mapping_error(lp->pci_dev, + new_dma_addr_list[new])) + pci_unmap_single(lp->pci_dev, + new_dma_addr_list[new], + PKT_BUF_SIZE, + PCI_DMA_FROMDEVICE); dev_kfree_skb(new_skb_list[new]); } } @@ -643,8 +649,7 @@ free_new_lists: kfree(new_dma_addr_list); free_new_rx_ring: pci_free_consistent(lp->pci_dev, - sizeof(struct pcnet32_rx_head) * - (1 << size), + sizeof(struct pcnet32_rx_head) * entries, new_rx_ring, new_ring_dma_addr); } @@ -659,8 +664,12 @@ static void pcnet32_purge_rx_ring(struct net_device *dev) lp->rx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->rx_skbuff[i]) { - pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], - PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (!pci_dma_mapping_error(lp->pci_dev, + lp->rx_dma_addr[i])) + pci_unmap_single(lp->pci_dev, + lp->rx_dma_addr[i], + PKT_BUF_SIZE, + PCI_DMA_FROMDEVICE); dev_kfree_skb_any(lp->rx_skbuff[i]); } lp->rx_skbuff[i] = NULL; @@ -909,7 +918,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) /* Initialize Transmit buffers. */ size = data_len + 15; for (x = 0; x < numbuffs; x++) { - skb = dev_alloc_skb(size); + skb = netdev_alloc_skb(dev, size); if (!skb) { netif_printk(lp, hw, KERN_DEBUG, dev, "Cannot allocate skb at line: %d!\n", @@ -939,6 +948,12 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) lp->tx_dma_addr[x] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(lp->pci_dev, lp->tx_dma_addr[x])) { + netif_printk(lp, hw, KERN_DEBUG, dev, + "DMA mapping error at line: %d!\n", + __LINE__); + goto clean_up; + } lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]); wmb(); /* Make sure owner changes after all others are visible */ lp->tx_ring[x].status = cpu_to_le16(status); @@ -1151,31 +1166,42 @@ static void pcnet32_rx_entry(struct net_device *dev, if (pkt_len > rx_copybreak) { struct sk_buff *newskb; + dma_addr_t new_dma_addr; - newskb = dev_alloc_skb(PKT_BUF_SKB); + newskb = netdev_alloc_skb(dev, PKT_BUF_SKB); + /* + * map the new buffer, if mapping fails, drop the packet and + * reuse the old buffer + */ if (newskb) { skb_reserve(newskb, NET_IP_ALIGN); - skb = lp->rx_skbuff[entry]; - pci_unmap_single(lp->pci_dev, - lp->rx_dma_addr[entry], - PKT_BUF_SIZE, - PCI_DMA_FROMDEVICE); - skb_put(skb, pkt_len); - lp->rx_skbuff[entry] = newskb; - lp->rx_dma_addr[entry] = - pci_map_single(lp->pci_dev, - newskb->data, - PKT_BUF_SIZE, - PCI_DMA_FROMDEVICE); - rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]); - rx_in_place = 1; + new_dma_addr = pci_map_single(lp->pci_dev, + newskb->data, + PKT_BUF_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(lp->pci_dev, new_dma_addr)) { + netif_err(lp, rx_err, dev, + "DMA mapping error.\n"); + dev_kfree_skb(newskb); + skb = NULL; + } else { + skb = lp->rx_skbuff[entry]; + pci_unmap_single(lp->pci_dev, + lp->rx_dma_addr[entry], + PKT_BUF_SIZE, + PCI_DMA_FROMDEVICE); + skb_put(skb, pkt_len); + lp->rx_skbuff[entry] = newskb; + lp->rx_dma_addr[entry] = new_dma_addr; + rxp->base = cpu_to_le32(new_dma_addr); + rx_in_place = 1; + } } else skb = NULL; } else - skb = dev_alloc_skb(pkt_len + NET_IP_ALIGN); + skb = netdev_alloc_skb(dev, pkt_len + NET_IP_ALIGN); if (skb == NULL) { - netif_err(lp, drv, dev, "Memory squeeze, dropping packet\n"); dev->stats.rx_dropped++; return; } @@ -1443,7 +1469,7 @@ static const struct ethtool_ops pcnet32_ethtool_ops = { /* only probes for non-PCI devices, the rest are handled by * pci_register_driver via pcnet32_probe_pci */ -static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist) +static void pcnet32_probe_vlbus(unsigned int *pcnet32_portlist) { unsigned int *port, ioaddr; @@ -1462,7 +1488,7 @@ static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist) } } -static int __devinit +static int pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned long ioaddr; @@ -1521,7 +1547,7 @@ static const struct net_device_ops pcnet32_netdev_ops = { * Called from both pcnet32_probe_vlbus and pcnet_probe_pci. * pdev will be NULL when called from pcnet32_probe_vlbus. */ -static int __devinit +static int pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) { struct pcnet32_private *lp; @@ -1531,7 +1557,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) char *chipname; struct net_device *dev; const struct pcnet32_access *a = NULL; - u8 promaddr[6]; + u8 promaddr[ETH_ALEN]; int ret = -ENODEV; /* reset the chip */ @@ -1649,8 +1675,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) dev = alloc_etherdev(sizeof(*lp)); if (!dev) { - if (pcnet32_debug & NETIF_MSG_PROBE) - pr_err("Memory allocation failed\n"); ret = -ENOMEM; goto err_release_region; } @@ -1677,23 +1701,22 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) } /* read PROM address and compare with CSR address */ - for (i = 0; i < 6; i++) + for (i = 0; i < ETH_ALEN; i++) promaddr[i] = inb(ioaddr + i); - if (memcmp(promaddr, dev->dev_addr, 6) || + if (!ether_addr_equal(promaddr, dev->dev_addr) || !is_valid_ether_addr(dev->dev_addr)) { if (is_valid_ether_addr(promaddr)) { if (pcnet32_debug & NETIF_MSG_PROBE) { pr_cont(" warning: CSR address invalid,\n"); pr_info(" using instead PROM address of"); } - memcpy(dev->dev_addr, promaddr, 6); + memcpy(dev->dev_addr, promaddr, ETH_ALEN); } } - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ - if (!is_valid_ether_addr(dev->perm_addr)) + if (!is_valid_ether_addr(dev->dev_addr)) memset(dev->dev_addr, 0, ETH_ALEN); if (pcnet32_debug & NETIF_MSG_PROBE) { @@ -1936,31 +1959,23 @@ static int pcnet32_alloc_ring(struct net_device *dev, const char *name) lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t), GFP_ATOMIC); - if (!lp->tx_dma_addr) { - netif_err(lp, drv, dev, "Memory allocation failed\n"); + if (!lp->tx_dma_addr) return -ENOMEM; - } lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t), GFP_ATOMIC); - if (!lp->rx_dma_addr) { - netif_err(lp, drv, dev, "Memory allocation failed\n"); + if (!lp->rx_dma_addr) return -ENOMEM; - } lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *), GFP_ATOMIC); - if (!lp->tx_skbuff) { - netif_err(lp, drv, dev, "Memory allocation failed\n"); + if (!lp->tx_skbuff) return -ENOMEM; - } lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *), GFP_ATOMIC); - if (!lp->rx_skbuff) { - netif_err(lp, drv, dev, "Memory allocation failed\n"); + if (!lp->rx_skbuff) return -ENOMEM; - } return 0; } @@ -2250,9 +2265,12 @@ static void pcnet32_purge_tx_ring(struct net_device *dev) lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { - pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], - lp->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); + if (!pci_dma_mapping_error(lp->pci_dev, + lp->tx_dma_addr[i])) + pci_unmap_single(lp->pci_dev, + lp->tx_dma_addr[i], + lp->tx_skbuff[i]->len, + PCI_DMA_TODEVICE); dev_kfree_skb_any(lp->tx_skbuff[i]); } lp->tx_skbuff[i] = NULL; @@ -2273,11 +2291,11 @@ static int pcnet32_init_ring(struct net_device *dev) for (i = 0; i < lp->rx_ring_size; i++) { struct sk_buff *rx_skbuff = lp->rx_skbuff[i]; if (rx_skbuff == NULL) { - lp->rx_skbuff[i] = dev_alloc_skb(PKT_BUF_SKB); + lp->rx_skbuff[i] = netdev_alloc_skb(dev, PKT_BUF_SKB); rx_skbuff = lp->rx_skbuff[i]; if (!rx_skbuff) { /* there is not much we can do at this point */ - netif_err(lp, drv, dev, "%s dev_alloc_skb failed\n", + netif_err(lp, drv, dev, "%s netdev_alloc_skb failed\n", __func__); return -1; } @@ -2285,10 +2303,19 @@ static int pcnet32_init_ring(struct net_device *dev) } rmb(); - if (lp->rx_dma_addr[i] == 0) + if (lp->rx_dma_addr[i] == 0) { lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(lp->pci_dev, + lp->rx_dma_addr[i])) { + /* there is not much we can do at this point */ + netif_err(lp, drv, dev, + "%s pci dma mapping error\n", + __func__); + return -1; + } + } lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]); lp->rx_ring[i].buf_length = cpu_to_le16(NEG_BUF_SIZE); wmb(); /* Make sure owner changes after all others are visible */ @@ -2418,9 +2445,14 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb, lp->tx_ring[entry].misc = 0x00000000; - lp->tx_skbuff[entry] = skb; lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(lp->pci_dev, lp->tx_dma_addr[entry])) { + dev_kfree_skb_any(skb); + dev->stats.tx_dropped++; + goto drop_packet; + } + lp->tx_skbuff[entry] = skb; lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]); wmb(); /* Make sure owner changes after all others are visible */ lp->tx_ring[entry].status = cpu_to_le16(status); @@ -2435,6 +2467,7 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb, lp->tx_full = 1; netif_stop_queue(dev); } +drop_packet: spin_unlock_irqrestore(&lp->lock, flags); return NETDEV_TX_OK; } @@ -2825,7 +2858,7 @@ static int pcnet32_pm_resume(struct pci_dev *pdev) return 0; } -static void __devexit pcnet32_remove_one(struct pci_dev *pdev) +static void pcnet32_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -2839,14 +2872,13 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev) lp->init_block, lp->init_dma_addr); free_netdev(dev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); } } static struct pci_driver pcnet32_driver = { .name = DRV_NAME, .probe = pcnet32_probe_pci, - .remove = __devexit_p(pcnet32_remove_one), + .remove = pcnet32_remove_one, .id_table = pcnet32_pci_tbl, .suspend = pcnet32_pm_suspend, .resume = pcnet32_pm_resume, |
