X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fsis190.c;h=abc63b0663be9ec83854da1a5b79feeefe6d4e66;hb=a292f404fabb342716a9d96e8155b7fb7b651dc1;hp=2e9e88be7b33f59558a06a22f06fee363805755d;hpb=dd07a8db7283f52f347aee468007556944b5b393;p=linux-2.6-omap-h63xx.git diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 2e9e88be7b3..abc63b0663b 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -212,6 +212,12 @@ enum _DescStatusBit { THOL2 = 0x20000000, THOL1 = 0x10000000, THOL0 = 0x00000000, + + WND = 0x00080000, + TABRT = 0x00040000, + FIFO = 0x00020000, + LINK = 0x00010000, + ColCountMask = 0x0000ffff, /* RxDesc.status */ IPON = 0x20000000, TCPON = 0x10000000, @@ -480,30 +486,23 @@ static inline void sis190_make_unusable_by_asic(struct RxDesc *desc) desc->status = 0x0; } -static int sis190_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, - struct RxDesc *desc, u32 rx_buf_sz) +static struct sk_buff *sis190_alloc_rx_skb(struct sis190_private *tp, + struct RxDesc *desc) { + u32 rx_buf_sz = tp->rx_buf_sz; struct sk_buff *skb; - dma_addr_t mapping; - int ret = 0; - - skb = dev_alloc_skb(rx_buf_sz); - if (!skb) - goto err_out; - - *sk_buff = skb; - mapping = pci_map_single(pdev, skb->data, rx_buf_sz, - PCI_DMA_FROMDEVICE); + skb = netdev_alloc_skb(tp->dev, rx_buf_sz); + if (likely(skb)) { + dma_addr_t mapping; - sis190_map_to_asic(desc, mapping, rx_buf_sz); -out: - return ret; + mapping = pci_map_single(tp->pci_dev, skb->data, tp->rx_buf_sz, + PCI_DMA_FROMDEVICE); + sis190_map_to_asic(desc, mapping, rx_buf_sz); + } else + sis190_make_unusable_by_asic(desc); -err_out: - ret = -ENOMEM; - sis190_make_unusable_by_asic(desc); - goto out; + return skb; } static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev, @@ -512,37 +511,41 @@ static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev, u32 cur; for (cur = start; cur < end; cur++) { - int ret, i = cur % NUM_RX_DESC; + unsigned int i = cur % NUM_RX_DESC; if (tp->Rx_skbuff[i]) continue; - ret = sis190_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i, - tp->RxDescRing + i, tp->rx_buf_sz); - if (ret < 0) + tp->Rx_skbuff[i] = sis190_alloc_rx_skb(tp, tp->RxDescRing + i); + + if (!tp->Rx_skbuff[i]) break; } return cur - start; } -static inline int sis190_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, - struct RxDesc *desc, int rx_buf_sz) +static bool sis190_try_rx_copy(struct sis190_private *tp, + struct sk_buff **sk_buff, int pkt_size, + dma_addr_t addr) { - int ret = -1; + struct sk_buff *skb; + bool done = false; - if (pkt_size < rx_copybreak) { - struct sk_buff *skb; + if (pkt_size >= rx_copybreak) + goto out; - skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN); - if (skb) { - skb_reserve(skb, NET_IP_ALIGN); - skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size); - *sk_buff = skb; - sis190_give_to_asic(desc, rx_buf_sz); - ret = 0; - } - } - return ret; + skb = netdev_alloc_skb(tp->dev, pkt_size + 2); + if (!skb) + goto out; + + pci_dma_sync_single_for_device(tp->pci_dev, addr, pkt_size, + PCI_DMA_FROMDEVICE); + skb_reserve(skb, 2); + skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size); + *sk_buff = skb; + done = true; +out: + return done; } static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats) @@ -592,9 +595,9 @@ static int sis190_rx_interrupt(struct net_device *dev, sis190_give_to_asic(desc, tp->rx_buf_sz); else { struct sk_buff *skb = tp->Rx_skbuff[entry]; + dma_addr_t addr = le32_to_cpu(desc->addr); int pkt_size = (status & RxSizeMask) - 4; - void (*pci_action)(struct pci_dev *, dma_addr_t, - size_t, int) = pci_dma_sync_single_for_device; + struct pci_dev *pdev = tp->pci_dev; if (unlikely(pkt_size > tp->rx_buf_sz)) { net_intr(tp, KERN_INFO @@ -606,20 +609,18 @@ static int sis190_rx_interrupt(struct net_device *dev, continue; } - pci_dma_sync_single_for_cpu(tp->pci_dev, - le32_to_cpu(desc->addr), tp->rx_buf_sz, - PCI_DMA_FROMDEVICE); - if (sis190_try_rx_copy(&skb, pkt_size, desc, - tp->rx_buf_sz)) { - pci_action = pci_unmap_single; + if (sis190_try_rx_copy(tp, &skb, pkt_size, addr)) { + pci_dma_sync_single_for_device(pdev, addr, + tp->rx_buf_sz, PCI_DMA_FROMDEVICE); + sis190_give_to_asic(desc, tp->rx_buf_sz); + } else { + pci_unmap_single(pdev, addr, tp->rx_buf_sz, + PCI_DMA_FROMDEVICE); tp->Rx_skbuff[entry] = NULL; sis190_make_unusable_by_asic(desc); } - pci_action(tp->pci_dev, le32_to_cpu(desc->addr), - tp->rx_buf_sz, PCI_DMA_FROMDEVICE); - skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); @@ -658,9 +659,31 @@ static void sis190_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff *skb, memset(desc, 0x00, sizeof(*desc)); } +static inline int sis190_tx_pkt_err(u32 status, struct net_device_stats *stats) +{ +#define TxErrMask (WND | TABRT | FIFO | LINK) + + if (!unlikely(status & TxErrMask)) + return 0; + + if (status & WND) + stats->tx_window_errors++; + if (status & TABRT) + stats->tx_aborted_errors++; + if (status & FIFO) + stats->tx_fifo_errors++; + if (status & LINK) + stats->tx_carrier_errors++; + + stats->tx_errors++; + + return -1; +} + static void sis190_tx_interrupt(struct net_device *dev, struct sis190_private *tp, void __iomem *ioaddr) { + struct net_device_stats *stats = &dev->stats; u32 pending, dirty_tx = tp->dirty_tx; /* * It would not be needed if queueing was allowed to be enabled @@ -675,15 +698,19 @@ static void sis190_tx_interrupt(struct net_device *dev, for (; pending; pending--, dirty_tx++) { unsigned int entry = dirty_tx % NUM_TX_DESC; struct TxDesc *txd = tp->TxDescRing + entry; + u32 status = le32_to_cpu(txd->status); struct sk_buff *skb; - if (le32_to_cpu(txd->status) & OWNbit) + if (status & OWNbit) break; skb = tp->Tx_skbuff[entry]; - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; + if (likely(sis190_tx_pkt_err(status, stats) == 0)) { + stats->tx_packets++; + stats->tx_bytes += skb->len; + stats->collisions += ((status & ColCountMask) - 1); + } sis190_unmap_tx_skb(tp->pci_dev, skb, txd); tp->Tx_skbuff[entry] = NULL; @@ -904,10 +931,9 @@ static void sis190_phy_task(struct work_struct *work) mod_timer(&tp->timer, jiffies + HZ/10); } else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) & BMSR_ANEGCOMPLETE)) { - net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n", - dev->name); netif_carrier_off(dev); - mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET); + net_link(tp, KERN_WARNING "%s: auto-negotiating...\n", + dev->name); mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT); } else { /* Rejoice ! */ @@ -1630,15 +1656,21 @@ static inline void sis190_init_rxfilter(struct net_device *dev) SIS_PCI_COMMIT(); } -static int sis190_get_mac_addr(struct pci_dev *pdev, struct net_device *dev) +static int __devinit sis190_get_mac_addr(struct pci_dev *pdev, + struct net_device *dev) { - u8 from; + int rc; + + rc = sis190_get_mac_addr_from_eeprom(pdev, dev); + if (rc < 0) { + u8 reg; - pci_read_config_byte(pdev, 0x73, &from); + pci_read_config_byte(pdev, 0x73, ®); - return (from & 0x00000001) ? - sis190_get_mac_addr_from_apc(pdev, dev) : - sis190_get_mac_addr_from_eeprom(pdev, dev); + if (reg & 0x00000001) + rc = sis190_get_mac_addr_from_apc(pdev, dev); + } + return rc; } static void sis190_set_speed_auto(struct net_device *dev)