diff options
-rw-r--r-- | drivers/net/sis190.c | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 20f48296efcb..abc63b0663be 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c | |||
@@ -212,6 +212,12 @@ enum _DescStatusBit { | |||
212 | THOL2 = 0x20000000, | 212 | THOL2 = 0x20000000, |
213 | THOL1 = 0x10000000, | 213 | THOL1 = 0x10000000, |
214 | THOL0 = 0x00000000, | 214 | THOL0 = 0x00000000, |
215 | |||
216 | WND = 0x00080000, | ||
217 | TABRT = 0x00040000, | ||
218 | FIFO = 0x00020000, | ||
219 | LINK = 0x00010000, | ||
220 | ColCountMask = 0x0000ffff, | ||
215 | /* RxDesc.status */ | 221 | /* RxDesc.status */ |
216 | IPON = 0x20000000, | 222 | IPON = 0x20000000, |
217 | TCPON = 0x10000000, | 223 | TCPON = 0x10000000, |
@@ -653,9 +659,31 @@ static void sis190_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff *skb, | |||
653 | memset(desc, 0x00, sizeof(*desc)); | 659 | memset(desc, 0x00, sizeof(*desc)); |
654 | } | 660 | } |
655 | 661 | ||
662 | static inline int sis190_tx_pkt_err(u32 status, struct net_device_stats *stats) | ||
663 | { | ||
664 | #define TxErrMask (WND | TABRT | FIFO | LINK) | ||
665 | |||
666 | if (!unlikely(status & TxErrMask)) | ||
667 | return 0; | ||
668 | |||
669 | if (status & WND) | ||
670 | stats->tx_window_errors++; | ||
671 | if (status & TABRT) | ||
672 | stats->tx_aborted_errors++; | ||
673 | if (status & FIFO) | ||
674 | stats->tx_fifo_errors++; | ||
675 | if (status & LINK) | ||
676 | stats->tx_carrier_errors++; | ||
677 | |||
678 | stats->tx_errors++; | ||
679 | |||
680 | return -1; | ||
681 | } | ||
682 | |||
656 | static void sis190_tx_interrupt(struct net_device *dev, | 683 | static void sis190_tx_interrupt(struct net_device *dev, |
657 | struct sis190_private *tp, void __iomem *ioaddr) | 684 | struct sis190_private *tp, void __iomem *ioaddr) |
658 | { | 685 | { |
686 | struct net_device_stats *stats = &dev->stats; | ||
659 | u32 pending, dirty_tx = tp->dirty_tx; | 687 | u32 pending, dirty_tx = tp->dirty_tx; |
660 | /* | 688 | /* |
661 | * It would not be needed if queueing was allowed to be enabled | 689 | * It would not be needed if queueing was allowed to be enabled |
@@ -670,15 +698,19 @@ static void sis190_tx_interrupt(struct net_device *dev, | |||
670 | for (; pending; pending--, dirty_tx++) { | 698 | for (; pending; pending--, dirty_tx++) { |
671 | unsigned int entry = dirty_tx % NUM_TX_DESC; | 699 | unsigned int entry = dirty_tx % NUM_TX_DESC; |
672 | struct TxDesc *txd = tp->TxDescRing + entry; | 700 | struct TxDesc *txd = tp->TxDescRing + entry; |
701 | u32 status = le32_to_cpu(txd->status); | ||
673 | struct sk_buff *skb; | 702 | struct sk_buff *skb; |
674 | 703 | ||
675 | if (le32_to_cpu(txd->status) & OWNbit) | 704 | if (status & OWNbit) |
676 | break; | 705 | break; |
677 | 706 | ||
678 | skb = tp->Tx_skbuff[entry]; | 707 | skb = tp->Tx_skbuff[entry]; |
679 | 708 | ||
680 | dev->stats.tx_packets++; | 709 | if (likely(sis190_tx_pkt_err(status, stats) == 0)) { |
681 | dev->stats.tx_bytes += skb->len; | 710 | stats->tx_packets++; |
711 | stats->tx_bytes += skb->len; | ||
712 | stats->collisions += ((status & ColCountMask) - 1); | ||
713 | } | ||
682 | 714 | ||
683 | sis190_unmap_tx_skb(tp->pci_dev, skb, txd); | 715 | sis190_unmap_tx_skb(tp->pci_dev, skb, txd); |
684 | tp->Tx_skbuff[entry] = NULL; | 716 | tp->Tx_skbuff[entry] = NULL; |