11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 23396c7823efb3a5b8630388c464e1034ea031cedPaul Gortmaker drivers/net/ethernet/dec/tulip/interrupt.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright 2000,2001 The Linux Kernel Team 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Written/copyright 1994-2001 by Donald Becker. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This software may be used and distributed according to the terms 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds of the GNU General Public License, incorporated herein by reference. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1078a655181409d9d0f2b730ccb897c18794826495Grant Grundler Please submit bugs to http://bugzilla.kernel.org/ . 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "tulip.h" 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint tulip_rx_copybreak; 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int tulip_max_interrupt_work; 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MIT_SIZE 15 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MIT_TABLE 15 /* We use 0 or max */ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int mit_table[MIT_SIZE+1] = 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CRS11 21143 hardware Mitigation Control Interrupt 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds We use only RX mitigation we other techniques for 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TX intr. mitigation. 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31 Cycle Size (timer control) 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30:27 TX timer in 16 * Cycle size 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26:24 TX No pkts before Int. 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23:20 RX timer in Cycle size 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19:17 RX No pkts before Int. 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16 Continues Mode (CM) 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x0, /* IM disabled */ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80150000, /* RX time = 1, RX pkts = 2, CM = 1 */ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80150000, 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80270000, 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80370000, 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80490000, 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80590000, 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80690000, 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x807B0000, 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x808B0000, 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x809D0000, 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80AD0000, 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80BD0000, 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80CF0000, 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80DF0000, 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// 0x80FF0000 /* RX time = 16, RX pkts = 7, CM = 1 */ 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x80F10000 /* RX time = 16, RX pkts = 0, CM = 1 */ 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint tulip_refill_rx(struct net_device *dev) 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tulip_private *tp = netdev_priv(dev); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int entry; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int refilled = 0; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Refill the Rx ring buffers. */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = tp->dirty_rx % RX_RING_SIZE; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->rx_buffers[entry].skb == NULL) { 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t mapping; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7221a4e46995fa1a76281ac0281ff837f706231a37Pradeep A Dalvi skb = tp->rx_buffers[entry].skb = 7321a4e46995fa1a76281ac0281ff837f706231a37Pradeep A Dalvi netdev_alloc_skb(dev, PKT_BUF_SZ); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb == NULL) 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77689be43945e9ca7dd704522e55af1b8a73a994d3David S. Miller mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ, 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_DMA_FROMDEVICE); 79c9bfbb31af7c8428267b34eb9706a621ac219a28Neil Horman if (dma_mapping_error(&tp->pdev->dev, mapping)) { 80c9bfbb31af7c8428267b34eb9706a621ac219a28Neil Horman dev_kfree_skb(skb); 81c9bfbb31af7c8428267b34eb9706a621ac219a28Neil Horman tp->rx_buffers[entry].skb = NULL; 82c9bfbb31af7c8428267b34eb9706a621ac219a28Neil Horman break; 83c9bfbb31af7c8428267b34eb9706a621ac219a28Neil Horman } 84c9bfbb31af7c8428267b34eb9706a621ac219a28Neil Horman 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_buffers[entry].mapping = mapping; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_ring[entry].buffer1 = cpu_to_le32(mapping); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds refilled++; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_ring[entry].status = cpu_to_le32(DescOwned); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(tp->chip_id == LC82C168) { 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(((ioread32(tp->base_addr + CSR5)>>17)&0x07) == 4) { 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Rx stopped due to out of buffers, 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * restart it 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x01, tp->base_addr + CSR2); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return refilled; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_TULIP_NAPI 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid oom_timer(unsigned long data) 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = (struct net_device *)data; 108bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger struct tulip_private *tp = netdev_priv(dev); 109288379f050284087578b77e04f040b57db3db3f8Ben Hutchings napi_schedule(&tp->napi); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 112bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemmingerint tulip_poll(struct napi_struct *napi, int budget) 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 114bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger struct tulip_private *tp = container_of(napi, struct tulip_private, napi); 115bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger struct net_device *dev = tp->dev; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int entry = tp->cur_rx % RX_RING_SIZE; 117bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger int work_done = 0; 118bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int received = 0; 120bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger#endif 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* that one buffer is needed for mit activation; or might be a 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bug in the ring buffer code; check later -- JHS*/ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 127bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger if (budget >=RX_RING_SIZE) budget--; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 4) 131726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, " In tulip_rx(), entry %d %08x\n", 132726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches entry, tp->rx_ring[entry].status); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ioread32(tp->base_addr + CSR5) == 0xffffffff) { 136726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, " In tulip_poll(), hardware disappeared\n"); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Acknowledge current RX interrupt sources. */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32((RxIntr | RxNoBuf), tp->base_addr + CSR5); 141f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 142f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we own the next entry, it is a new packet. Send it up. */ 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s32 status = le32_to_cpu(tp->rx_ring[entry].status); 1461f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech short pkt_len; 147f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 150f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 151726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches if (tulip_debug > 5) 152726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", 153726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches entry, status); 154c6a1b62de9d043f274ec3ae2e207908c6d5feff3Stephen Hemminger 155c6a1b62de9d043f274ec3ae2e207908c6d5feff3Stephen Hemminger if (++work_done >= budget) 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto not_done; 157f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 1581f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech /* 1591f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech * Omit the four octet CRC from the length. 1601f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech * (May not be considered valid until we have 1611f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech * checked status for RxLengthOver2047 bits) 1621f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech */ 1631f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech pkt_len = ((status >> 16) & 0x7ff) - 4; 1641f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech 1651f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech /* 1661f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech * Maximum pkt_len is 1518 (1514 + vlan header) 1671f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech * Anything higher than this is always invalid 1681f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech * regardless of RxLengthOver2047 bits 1691f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech */ 1701f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech 1711f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech if ((status & (RxLengthOver2047 | 1721f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech RxDescCRCError | 1731f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech RxDescCollisionSeen | 1741f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech RxDescRunt | 1751f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech RxDescDescErr | 1768e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches RxWholePkt)) != RxWholePkt || 1778e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches pkt_len > 1518) { 1781f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech if ((status & (RxLengthOver2047 | 1791f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech RxWholePkt)) != RxWholePkt) { 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ingore earlier buffers. */ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & 0xffff) != 0x7fff) { 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 183abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dev_warn(&dev->dev, 184abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", 185abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches status); 1861a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_length_errors++; 1871a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet } 1881f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech } else { 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There was a fatal error. */ 190726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches if (tulip_debug > 2) 191726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "Receive error, Rx status %08x\n", 192726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches status); 1931a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_errors++; /* end of a packet.*/ 1941a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (pkt_len > 1518 || 1951a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet (status & RxDescRunt)) 1961a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_length_errors++; 1971a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet 1981a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (status & 0x0004) 1991a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_frame_errors++; 2001a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (status & 0x0002) 2011a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_crc_errors++; 2021a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (status & 0x0001) 2031a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_fifo_errors++; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 207f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check if the packet is long enough to accept without copying 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to a minimally-sized skbuff. */ 2108e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if (pkt_len < tulip_rx_copybreak && 21121a4e46995fa1a76281ac0281ff837f706231a37Pradeep A Dalvi (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skb, 2); /* 16 byte align the IP header */ 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_dma_sync_single_for_cpu(tp->pdev, 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_buffers[entry].mapping, 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len, PCI_DMA_FROMDEVICE); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if ! defined(__alpha__) 2178c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data, 2188c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller pkt_len); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_put(skb, pkt_len); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, pkt_len), 222689be43945e9ca7dd704522e55af1b8a73a994d3David S. Miller tp->rx_buffers[entry].skb->data, 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_dma_sync_single_for_device(tp->pdev, 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_buffers[entry].mapping, 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len, PCI_DMA_FROMDEVICE); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* Pass up the skb already on the Rx ring. */ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *temp = skb_put(skb = tp->rx_buffers[entry].skb, 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len); 231f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->rx_buffers[entry].mapping != 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(tp->rx_ring[entry].buffer1)) { 235abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dev_err(&dev->dev, 236abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %08llx %p / %p\n", 237abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches le32_to_cpu(tp->rx_ring[entry].buffer1), 238abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches (unsigned long long)tp->rx_buffers[entry].mapping, 239abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches skb->head, temp); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 242f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping, 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PKT_BUF_SZ, PCI_DMA_FROMDEVICE); 245f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_buffers[entry].skb = NULL; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_buffers[entry].mapping = 0; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans(skb, dev); 250f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_receive_skb(skb); 252f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2531a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_packets++; 2541a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_bytes += pkt_len; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 256bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 257bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger received++; 258bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger#endif 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = (++tp->cur_rx) % RX_RING_SIZE; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_refill_rx(dev); 263f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 265f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* New ack strategy... irq does not ack Rx any longer 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hopefully this helps */ 268f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Really bad things can happen here... If new packet arrives 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and an irq arrives (tx or just due to occasionally unset 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mask), it will be acked by irq handler, but new thread 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is not scheduled. It is major hole in design. 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No idea how to fix this if "playing with fire" will fail 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tomorrow (night 011029). If it will not fail, we won 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * finally: amount of IO did not increase at all. */ 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while ((ioread32(tp->base_addr + CSR5) & RxIntr)); 277f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 279f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We use this simplistic scheme for IM. It's proven by 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds real life installations. We can have IM enabled 282f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik continuesly but this would cause unnecessary latency. 283f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik Unfortunely we can't use all the NET_RX_* feedback here. 284f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik This would turn on IM for devices that is not contributing 285f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik to backlog congestion with unnecessary latency. 286f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 28759c51591a0ac7568824f541f57de967e88adaa07Michael Opdenacker We monitor the device RX-ring and have: 288f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HW Interrupt Mitigation either ON or OFF. 290f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 291f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik ON: More then 1 pkt received (per intr.) OR we are dropping 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OFF: Only 1 pkt received 293f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Note. We only use min and max (0, 15) settings from mit_table */ 295f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 296f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if( tp->flags & HAS_INTR_MITIGATION) { 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if( received > 1 ) { 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if( ! tp->mit_on ) { 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->mit_on = 1; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(mit_table[MIT_TABLE], tp->base_addr + CSR11); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if( tp->mit_on ) { 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->mit_on = 0; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0, tp->base_addr + CSR11); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */ 313f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_refill_rx(dev); 315f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If RX ring is not full we are out of memory. */ 317bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 318bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger goto oom; 319f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Remove us from polling list and enable RX intr. */ 321f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 322288379f050284087578b77e04f040b57db3db3f8Ben Hutchings napi_complete(napi); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7); 324f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The last op happens after poll completion. Which means the following: 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. it can race with disabling irqs in irq handler 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. it can race with dise/enabling irqs in other poll threads 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3. if an irq raised after beginning loop, it will be immediately 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * triggered here. 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Summarizing: the logic results in some redundant irqs both 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * due to races in masking and due to too late acking of already 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * processed irqs. But it must not result in losing events. 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 335f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 336bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger return work_done; 337f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds not_done: 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_refill_rx(dev); 342f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 343bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 344bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger goto oom; 345f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 346bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger return work_done; 347f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oom: /* Executed with RX ints disabled */ 349f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start timer, stop polling, but do not enable rx interrupts. */ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer(&tp->oom_timer, jiffies+1); 352f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Think: timer_pending() was an explicit signature of bug. 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Timer can be pending now but fired and completed 355288379f050284087578b77e04f040b57db3db3f8Ben Hutchings * before we did napi_complete(). See? We would lose it. */ 356f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* remove ourselves from the polling list */ 358288379f050284087578b77e04f040b57db3db3f8Ben Hutchings napi_complete(napi); 359f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 360bea3348eef27e6044b6161fd04c3152215f96411Stephen Hemminger return work_done; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* CONFIG_TULIP_NAPI */ 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int tulip_rx(struct net_device *dev) 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tulip_private *tp = netdev_priv(dev); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int entry = tp->cur_rx % RX_RING_SIZE; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int received = 0; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 4) 373726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", 374726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches entry, tp->rx_ring[entry].status); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we own the next entry, it is a new packet. Send it up. */ 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s32 status = le32_to_cpu(tp->rx_ring[entry].status); 3781f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech short pkt_len; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 5) 381726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", 382726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches entry, status); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (--rx_work_limit < 0) 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3851f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech 3861f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech /* 3871f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech Omit the four octet CRC from the length. 3881f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech (May not be considered valid until we have 3891f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech checked status for RxLengthOver2047 bits) 3901f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech */ 3911f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech pkt_len = ((status >> 16) & 0x7ff) - 4; 3921f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech /* 3931f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech Maximum pkt_len is 1518 (1514 + vlan header) 3941f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech Anything higher than this is always invalid 3951f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech regardless of RxLengthOver2047 bits 3961f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech */ 3971f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech 3981f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech if ((status & (RxLengthOver2047 | 3991f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech RxDescCRCError | 4001f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech RxDescCollisionSeen | 4011f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech RxDescRunt | 4021f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech RxDescDescErr | 4038e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches RxWholePkt)) != RxWholePkt || 4048e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches pkt_len > 1518) { 4051f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech if ((status & (RxLengthOver2047 | 4061f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech RxWholePkt)) != RxWholePkt) { 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ingore earlier buffers. */ 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & 0xffff) != 0x7fff) { 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 410726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_warn(dev, 411726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", 412726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches status); 4131a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_length_errors++; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4151f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech } else { 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There was a fatal error. */ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 2) 418726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "Receive error, Rx status %08x\n", 419726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches status); 4201a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_errors++; /* end of a packet.*/ 4211f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech if (pkt_len > 1518 || 4221f8ae0a21d83f43006d7f6d2862e921dbf2eedddTomasz Lemiech (status & RxDescRunt)) 4231a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_length_errors++; 4241a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (status & 0x0004) 4251a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_frame_errors++; 4261a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (status & 0x0002) 4271a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_crc_errors++; 4281a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (status & 0x0001) 4291a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_fifo_errors++; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check if the packet is long enough to accept without copying 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to a minimally-sized skbuff. */ 4368e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if (pkt_len < tulip_rx_copybreak && 43721a4e46995fa1a76281ac0281ff837f706231a37Pradeep A Dalvi (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skb, 2); /* 16 byte align the IP header */ 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_dma_sync_single_for_cpu(tp->pdev, 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_buffers[entry].mapping, 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len, PCI_DMA_FROMDEVICE); 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if ! defined(__alpha__) 4438c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data, 4448c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller pkt_len); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_put(skb, pkt_len); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, pkt_len), 448689be43945e9ca7dd704522e55af1b8a73a994d3David S. Miller tp->rx_buffers[entry].skb->data, 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_dma_sync_single_for_device(tp->pdev, 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_buffers[entry].mapping, 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len, PCI_DMA_FROMDEVICE); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* Pass up the skb already on the Rx ring. */ 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *temp = skb_put(skb = tp->rx_buffers[entry].skb, 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->rx_buffers[entry].mapping != 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(tp->rx_ring[entry].buffer1)) { 461abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dev_err(&dev->dev, 462abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %Lx %p / %p\n", 463abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches le32_to_cpu(tp->rx_ring[entry].buffer1), 464abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches (long long)tp->rx_buffers[entry].mapping, 465abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches skb->head, temp); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping, 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PKT_BUF_SZ, PCI_DMA_FROMDEVICE); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_buffers[entry].skb = NULL; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->rx_buffers[entry].mapping = 0; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans(skb, dev); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_packets++; 4801a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_bytes += pkt_len; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds received++; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = (++tp->cur_rx) % RX_RING_SIZE; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return received; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_TULIP_NAPI */ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned int phy_interrupt (struct net_device *dev) 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __hppa__ 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tulip_private *tp = netdev_priv(dev); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int csr12 = ioread32(tp->base_addr + CSR12) & 0xff; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr12 != tp->csr12_shadow) { 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ack interrupt */ 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr12 | 0x02, tp->base_addr + CSR12); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->csr12_shadow = csr12; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* do link change stuff */ 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&tp->lock); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_check_duplex(dev); 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&tp->lock); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear irq ack bit */ 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr12 & ~0x02, tp->base_addr + CSR12); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The interrupt handler does all of the Rx thread work and cleans up 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds after the Tx thread. */ 5157d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsirqreturn_t tulip_interrupt(int irq, void *dev_instance) 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = (struct net_device *)dev_instance; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tulip_private *tp = netdev_priv(dev); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *ioaddr = tp->base_addr; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int csr5; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int missed; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx = 0; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx = 0; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int oi = 0; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int maxrx = RX_RING_SIZE; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int maxtx = TX_RING_SIZE; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int maxoi = TX_RING_SIZE; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_TULIP_NAPI 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rxd = 0; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int entry; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int work_count = tulip_max_interrupt_work; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int handled = 0; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Let's see whether the interrupt really is for us */ 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr5 = ioread32(ioaddr + CSR5); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 539f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik if (tp->flags & HAS_PHY_IRQ) 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handled = phy_interrupt (dev); 541f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_RETVAL(handled); 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->nir++; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_TULIP_NAPI 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rxd++; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Mask RX intrs and add the device to poll list. */ 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); 555288379f050284087578b77e04f040b57db3db3f8Ben Hutchings napi_schedule(&tp->napi); 556f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 560f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Acknowledge the interrupt sources we handle here ASAP 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the poll function does Rx and RxNoBuf acking */ 563f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr5 & 0x0001ff3f, ioaddr + CSR5); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 566f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik#else 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Acknowledge all of the current interrupt sources ASAP. */ 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(csr5 & 0x0001ffff, ioaddr + CSR5); 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr5 & (RxIntr | RxNoBuf)) { 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx += tulip_rx(dev); 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_refill_rx(dev); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_TULIP_NAPI */ 577f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 4) 579726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "interrupt csr5=%#8.8x new csr5=%#8.8x\n", 580726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches csr5, ioread32(ioaddr + CSR5)); 581f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int dirty_tx; 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&tp->lock); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dirty_tx++) { 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int entry = dirty_tx % TX_RING_SIZE; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status = le32_to_cpu(tp->tx_ring[entry].status); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status < 0) 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* It still has not been Txed */ 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check for Rx filter setup frames. */ 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->tx_buffers[entry].skb == NULL) { 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* test because dummy frames not mapped */ 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->tx_buffers[entry].mapping) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_unmap_single(tp->pdev, 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tx_buffers[entry].mapping, 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(tp->setup_frame), 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_DMA_TODEVICE); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & 0x8000) { 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There was an major error, log it. */ 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 611726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "Transmit error, Tx status %08x\n", 612726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches status); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6141a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.tx_errors++; 6151a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (status & 0x4104) 6161a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.tx_aborted_errors++; 6171a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (status & 0x0C00) 6181a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.tx_carrier_errors++; 6191a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (status & 0x0200) 6201a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.tx_window_errors++; 6211a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (status & 0x0002) 6221a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.tx_fifo_errors++; 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & 0x0080) && tp->full_duplex == 0) 6241a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.tx_heartbeat_errors++; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6261a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.tx_bytes += 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tx_buffers[entry].skb->len; 6281a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.collisions += (status >> 3) & 15; 6291a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.tx_packets++; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tx_buffers[entry].skb->len, 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_DMA_TODEVICE); 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Free the original skb. */ 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_irq(tp->tx_buffers[entry].skb); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tx_buffers[entry].skb = NULL; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tx_buffers[entry].mapping = 0; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx++; 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { 645abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dev_err(&dev->dev, 646abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches "Out-of-sync dirty pointer, %d vs. %d\n", 647abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dirty_tx, tp->cur_tx); 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dirty_tx += TX_RING_SIZE; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->dirty_tx = dirty_tx; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr5 & TxDied) { 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 2) 658abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dev_warn(&dev->dev, 659abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches "The transmitter stopped. CSR5 is %x, CSR6 %x, new CSR6 %x\n", 660abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches csr5, ioread32(ioaddr + CSR6), 661abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches tp->csr6); 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_restart_rxtx(tp); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&tp->lock); 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Log errors. */ 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr5 == 0xffffffff) 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6711a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet if (csr5 & TxJabber) 6721a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.tx_errors++; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr5 & TxFIFOUnderflow) { 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tp->csr6 & 0xC000) != 0xC000) 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->csr6 += 0x4000; /* Bump up the Tx threshold */ 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->csr6 |= 0x00200000; /* Store-n-forward. */ 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Restart the transmit process. */ 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_restart_rxtx(tp); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0, ioaddr + CSR1); 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr5 & (RxDied | RxNoBuf)) { 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->flags & COMET_MAC_ADDR) { 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(tp->mc_filter[0], ioaddr + 0xAC); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(tp->mc_filter[1], ioaddr + 0xB0); 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr5 & RxDied) { /* Missed a Rx frame. */ 6891a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff; 6901a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_errors++; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_start_rxtx(tp); 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * call is ever done under the spinlock 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->link_change) 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (tp->link_change)(dev, csr5); 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7011ddb98618d5b797cb5300f093c1df1f38f79d9baValerie Henson if (csr5 & SystemError) { 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error = (csr5 >> 23) & 7; 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* oops, we hit a PCI error. The code produced corresponds 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the reason: 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0 - parity error 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1 - master abort 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 - target abort 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that on parity error, we should do a software reset 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the chip to get it back into a sane state (according 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the 21142/3 docs that is). 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -- rmk 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 713abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dev_err(&dev->dev, 714abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches "(%lu) System Error occurred (%d)\n", 715abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches tp->nir, error); 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear all error sources, included undocumented ones! */ 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x0800f7ba, ioaddr + CSR5); 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oi++; 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr5 & TimerInt) { 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 2) 724abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dev_err(&dev->dev, 725abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches "Re-enabling interrupts, %08x\n", 726abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches csr5); 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->ttimer = 0; 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oi++; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx > maxtx || rx > maxrx || oi > maxoi) { 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 733abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dev_warn(&dev->dev, "Too much work during an interrupt, csr5=0x%08x. (%lu) (%d,%d,%d)\n", 734abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches csr5, tp->nir, tx, rx, oi); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Acknowledge all interrupt sources. */ 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x8001ffff, ioaddr + CSR5); 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->flags & HAS_INTR_MITIGATION) { 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Josip Loncaric at ICASE did extensive experimentation 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to develop a good interrupt mitigation setting.*/ 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x8b240000, ioaddr + CSR11); 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (tp->chip_id == LC82C168) { 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the LC82C168 doesn't have a hw timer.*/ 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x00, ioaddr + CSR7); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer(&tp->timer, RUN_AT(HZ/50)); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Mask all interrupting sources, set timer to 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds re-enable. */ 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x0012, ioaddr + CSR11); 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds work_count--; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (work_count == 0) 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr5 = ioread32(ioaddr + CSR5); 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_TULIP_NAPI 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rxd) 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr5 &= ~RxPollInt; 764f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik } while ((csr5 & (TxNoBuf | 765f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik TxDied | 766f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik TxIntr | 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TimerInt | 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Abnormal intr. */ 769f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik RxDied | 770f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik TxFIFOUnderflow | 771f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik TxJabber | 772f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik TPLnkFail | 7731ddb98618d5b797cb5300f093c1df1f38f79d9baValerie Henson SystemError )) != 0); 774f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik#else 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tulip_refill_rx(dev); 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if the card is in suspend mode */ 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = tp->dirty_rx % RX_RING_SIZE; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->rx_buffers[entry].skb == NULL) { 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 783abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dev_warn(&dev->dev, 784abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches "in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", 785abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches tp->nir, tp->cur_rx, tp->ttimer, rx); 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->chip_id == LC82C168) { 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(0x00, ioaddr + CSR7); 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer(&tp->timer, RUN_AT(HZ/50)); 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->ttimer == 0 || (ioread32(ioaddr + CSR11) & 0xffff) == 0) { 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 1) 792abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches dev_warn(&dev->dev, 793abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches "in rx suspend mode: (%lu) set timer\n", 794abe02af8263ae17e201994a1be7fc5eac6642acfJoe Perches tp->nir); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr + CSR7); 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(TimerInt, ioaddr + CSR5); 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iowrite32(12, ioaddr + CSR11); 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->ttimer = 1; 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_TULIP_NAPI */ 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((missed = ioread32(ioaddr + CSR8) & 0x1ffff)) { 8061a18abaa87c4c68a13c2ffcace39a078605b980aEric Dumazet dev->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tulip_debug > 4) 810726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches netdev_dbg(dev, "exiting interrupt, csr5=%#04x\n", 811726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches ioread32(ioaddr + CSR5)); 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 815