162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci drivers/net/ethernet/dec/tulip/interrupt.c 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci Copyright 2000,2001 The Linux Kernel Team 562306a36Sopenharmony_ci Written/copyright 1994-2001 by Donald Becker. 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci This software may be used and distributed according to the terms 862306a36Sopenharmony_ci of the GNU General Public License, incorporated herein by reference. 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci Please submit bugs to http://bugzilla.kernel.org/ . 1162306a36Sopenharmony_ci*/ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include "tulip.h" 1562306a36Sopenharmony_ci#include <linux/etherdevice.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciint tulip_rx_copybreak; 1862306a36Sopenharmony_ciunsigned int tulip_max_interrupt_work; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 2162306a36Sopenharmony_ci#define MIT_SIZE 15 2262306a36Sopenharmony_ci#define MIT_TABLE 15 /* We use 0 or max */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic unsigned int mit_table[MIT_SIZE+1] = 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci /* CRS11 21143 hardware Mitigation Control Interrupt 2762306a36Sopenharmony_ci We use only RX mitigation we other techniques for 2862306a36Sopenharmony_ci TX intr. mitigation. 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci 31 Cycle Size (timer control) 3162306a36Sopenharmony_ci 30:27 TX timer in 16 * Cycle size 3262306a36Sopenharmony_ci 26:24 TX No pkts before Int. 3362306a36Sopenharmony_ci 23:20 RX timer in Cycle size 3462306a36Sopenharmony_ci 19:17 RX No pkts before Int. 3562306a36Sopenharmony_ci 16 Continues Mode (CM) 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci 0x0, /* IM disabled */ 3962306a36Sopenharmony_ci 0x80150000, /* RX time = 1, RX pkts = 2, CM = 1 */ 4062306a36Sopenharmony_ci 0x80150000, 4162306a36Sopenharmony_ci 0x80270000, 4262306a36Sopenharmony_ci 0x80370000, 4362306a36Sopenharmony_ci 0x80490000, 4462306a36Sopenharmony_ci 0x80590000, 4562306a36Sopenharmony_ci 0x80690000, 4662306a36Sopenharmony_ci 0x807B0000, 4762306a36Sopenharmony_ci 0x808B0000, 4862306a36Sopenharmony_ci 0x809D0000, 4962306a36Sopenharmony_ci 0x80AD0000, 5062306a36Sopenharmony_ci 0x80BD0000, 5162306a36Sopenharmony_ci 0x80CF0000, 5262306a36Sopenharmony_ci 0x80DF0000, 5362306a36Sopenharmony_ci// 0x80FF0000 /* RX time = 16, RX pkts = 7, CM = 1 */ 5462306a36Sopenharmony_ci 0x80F10000 /* RX time = 16, RX pkts = 0, CM = 1 */ 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci#endif 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciint tulip_refill_rx(struct net_device *dev) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct tulip_private *tp = netdev_priv(dev); 6262306a36Sopenharmony_ci int entry; 6362306a36Sopenharmony_ci int refilled = 0; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* Refill the Rx ring buffers. */ 6662306a36Sopenharmony_ci for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { 6762306a36Sopenharmony_ci entry = tp->dirty_rx % RX_RING_SIZE; 6862306a36Sopenharmony_ci if (tp->rx_buffers[entry].skb == NULL) { 6962306a36Sopenharmony_ci struct sk_buff *skb; 7062306a36Sopenharmony_ci dma_addr_t mapping; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci skb = tp->rx_buffers[entry].skb = 7362306a36Sopenharmony_ci netdev_alloc_skb(dev, PKT_BUF_SZ); 7462306a36Sopenharmony_ci if (skb == NULL) 7562306a36Sopenharmony_ci break; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci mapping = dma_map_single(&tp->pdev->dev, skb->data, 7862306a36Sopenharmony_ci PKT_BUF_SZ, DMA_FROM_DEVICE); 7962306a36Sopenharmony_ci if (dma_mapping_error(&tp->pdev->dev, mapping)) { 8062306a36Sopenharmony_ci dev_kfree_skb(skb); 8162306a36Sopenharmony_ci tp->rx_buffers[entry].skb = NULL; 8262306a36Sopenharmony_ci break; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci tp->rx_buffers[entry].mapping = mapping; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci tp->rx_ring[entry].buffer1 = cpu_to_le32(mapping); 8862306a36Sopenharmony_ci refilled++; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci tp->rx_ring[entry].status = cpu_to_le32(DescOwned); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci if(tp->chip_id == LC82C168) { 9362306a36Sopenharmony_ci if(((ioread32(tp->base_addr + CSR5)>>17)&0x07) == 4) { 9462306a36Sopenharmony_ci /* Rx stopped due to out of buffers, 9562306a36Sopenharmony_ci * restart it 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci iowrite32(0x01, tp->base_addr + CSR2); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci return refilled; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_civoid oom_timer(struct timer_list *t) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct tulip_private *tp = from_timer(tp, t, oom_timer); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci napi_schedule(&tp->napi); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ciint tulip_poll(struct napi_struct *napi, int budget) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct tulip_private *tp = container_of(napi, struct tulip_private, napi); 11562306a36Sopenharmony_ci struct net_device *dev = tp->dev; 11662306a36Sopenharmony_ci int entry = tp->cur_rx % RX_RING_SIZE; 11762306a36Sopenharmony_ci int work_done = 0; 11862306a36Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 11962306a36Sopenharmony_ci int received = 0; 12062306a36Sopenharmony_ci#endif 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* that one buffer is needed for mit activation; or might be a 12562306a36Sopenharmony_ci bug in the ring buffer code; check later -- JHS*/ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (budget >=RX_RING_SIZE) budget--; 12862306a36Sopenharmony_ci#endif 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (tulip_debug > 4) 13162306a36Sopenharmony_ci netdev_dbg(dev, " In tulip_rx(), entry %d %08x\n", 13262306a36Sopenharmony_ci entry, tp->rx_ring[entry].status); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci do { 13562306a36Sopenharmony_ci if (ioread32(tp->base_addr + CSR5) == 0xffffffff) { 13662306a36Sopenharmony_ci netdev_dbg(dev, " In tulip_poll(), hardware disappeared\n"); 13762306a36Sopenharmony_ci break; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci /* Acknowledge current RX interrupt sources. */ 14062306a36Sopenharmony_ci iowrite32((RxIntr | RxNoBuf), tp->base_addr + CSR5); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* If we own the next entry, it is a new packet. Send it up. */ 14462306a36Sopenharmony_ci while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 14562306a36Sopenharmony_ci s32 status = le32_to_cpu(tp->rx_ring[entry].status); 14662306a36Sopenharmony_ci short pkt_len; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (tulip_debug > 5) 15262306a36Sopenharmony_ci netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", 15362306a36Sopenharmony_ci entry, status); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (++work_done >= budget) 15662306a36Sopenharmony_ci goto not_done; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* 15962306a36Sopenharmony_ci * Omit the four octet CRC from the length. 16062306a36Sopenharmony_ci * (May not be considered valid until we have 16162306a36Sopenharmony_ci * checked status for RxLengthOver2047 bits) 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci pkt_len = ((status >> 16) & 0x7ff) - 4; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* 16662306a36Sopenharmony_ci * Maximum pkt_len is 1518 (1514 + vlan header) 16762306a36Sopenharmony_ci * Anything higher than this is always invalid 16862306a36Sopenharmony_ci * regardless of RxLengthOver2047 bits 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if ((status & (RxLengthOver2047 | 17262306a36Sopenharmony_ci RxDescCRCError | 17362306a36Sopenharmony_ci RxDescCollisionSeen | 17462306a36Sopenharmony_ci RxDescRunt | 17562306a36Sopenharmony_ci RxDescDescErr | 17662306a36Sopenharmony_ci RxWholePkt)) != RxWholePkt || 17762306a36Sopenharmony_ci pkt_len > 1518) { 17862306a36Sopenharmony_ci if ((status & (RxLengthOver2047 | 17962306a36Sopenharmony_ci RxWholePkt)) != RxWholePkt) { 18062306a36Sopenharmony_ci /* Ingore earlier buffers. */ 18162306a36Sopenharmony_ci if ((status & 0xffff) != 0x7fff) { 18262306a36Sopenharmony_ci if (tulip_debug > 1) 18362306a36Sopenharmony_ci dev_warn(&dev->dev, 18462306a36Sopenharmony_ci "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", 18562306a36Sopenharmony_ci status); 18662306a36Sopenharmony_ci dev->stats.rx_length_errors++; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci } else { 18962306a36Sopenharmony_ci /* There was a fatal error. */ 19062306a36Sopenharmony_ci if (tulip_debug > 2) 19162306a36Sopenharmony_ci netdev_dbg(dev, "Receive error, Rx status %08x\n", 19262306a36Sopenharmony_ci status); 19362306a36Sopenharmony_ci dev->stats.rx_errors++; /* end of a packet.*/ 19462306a36Sopenharmony_ci if (pkt_len > 1518 || 19562306a36Sopenharmony_ci (status & RxDescRunt)) 19662306a36Sopenharmony_ci dev->stats.rx_length_errors++; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (status & 0x0004) 19962306a36Sopenharmony_ci dev->stats.rx_frame_errors++; 20062306a36Sopenharmony_ci if (status & 0x0002) 20162306a36Sopenharmony_ci dev->stats.rx_crc_errors++; 20262306a36Sopenharmony_ci if (status & 0x0001) 20362306a36Sopenharmony_ci dev->stats.rx_fifo_errors++; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci } else { 20662306a36Sopenharmony_ci struct sk_buff *skb; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Check if the packet is long enough to accept without copying 20962306a36Sopenharmony_ci to a minimally-sized skbuff. */ 21062306a36Sopenharmony_ci if (pkt_len < tulip_rx_copybreak && 21162306a36Sopenharmony_ci (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { 21262306a36Sopenharmony_ci skb_reserve(skb, 2); /* 16 byte align the IP header */ 21362306a36Sopenharmony_ci dma_sync_single_for_cpu(&tp->pdev->dev, 21462306a36Sopenharmony_ci tp->rx_buffers[entry].mapping, 21562306a36Sopenharmony_ci pkt_len, 21662306a36Sopenharmony_ci DMA_FROM_DEVICE); 21762306a36Sopenharmony_ci#if ! defined(__alpha__) 21862306a36Sopenharmony_ci skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data, 21962306a36Sopenharmony_ci pkt_len); 22062306a36Sopenharmony_ci skb_put(skb, pkt_len); 22162306a36Sopenharmony_ci#else 22262306a36Sopenharmony_ci skb_put_data(skb, 22362306a36Sopenharmony_ci tp->rx_buffers[entry].skb->data, 22462306a36Sopenharmony_ci pkt_len); 22562306a36Sopenharmony_ci#endif 22662306a36Sopenharmony_ci dma_sync_single_for_device(&tp->pdev->dev, 22762306a36Sopenharmony_ci tp->rx_buffers[entry].mapping, 22862306a36Sopenharmony_ci pkt_len, 22962306a36Sopenharmony_ci DMA_FROM_DEVICE); 23062306a36Sopenharmony_ci } else { /* Pass up the skb already on the Rx ring. */ 23162306a36Sopenharmony_ci char *temp = skb_put(skb = tp->rx_buffers[entry].skb, 23262306a36Sopenharmony_ci pkt_len); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci#ifndef final_version 23562306a36Sopenharmony_ci if (tp->rx_buffers[entry].mapping != 23662306a36Sopenharmony_ci le32_to_cpu(tp->rx_ring[entry].buffer1)) { 23762306a36Sopenharmony_ci dev_err(&dev->dev, 23862306a36Sopenharmony_ci "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %08llx %p / %p\n", 23962306a36Sopenharmony_ci le32_to_cpu(tp->rx_ring[entry].buffer1), 24062306a36Sopenharmony_ci (unsigned long long)tp->rx_buffers[entry].mapping, 24162306a36Sopenharmony_ci skb->head, temp); 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci#endif 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci dma_unmap_single(&tp->pdev->dev, 24662306a36Sopenharmony_ci tp->rx_buffers[entry].mapping, 24762306a36Sopenharmony_ci PKT_BUF_SZ, 24862306a36Sopenharmony_ci DMA_FROM_DEVICE); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci tp->rx_buffers[entry].skb = NULL; 25162306a36Sopenharmony_ci tp->rx_buffers[entry].mapping = 0; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci netif_receive_skb(skb); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci dev->stats.rx_packets++; 25862306a36Sopenharmony_ci dev->stats.rx_bytes += pkt_len; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 26162306a36Sopenharmony_ci received++; 26262306a36Sopenharmony_ci#endif 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci entry = (++tp->cur_rx) % RX_RING_SIZE; 26562306a36Sopenharmony_ci if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) 26662306a36Sopenharmony_ci tulip_refill_rx(dev); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* New ack strategy... irq does not ack Rx any longer 27162306a36Sopenharmony_ci hopefully this helps */ 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Really bad things can happen here... If new packet arrives 27462306a36Sopenharmony_ci * and an irq arrives (tx or just due to occasionally unset 27562306a36Sopenharmony_ci * mask), it will be acked by irq handler, but new thread 27662306a36Sopenharmony_ci * is not scheduled. It is major hole in design. 27762306a36Sopenharmony_ci * No idea how to fix this if "playing with fire" will fail 27862306a36Sopenharmony_ci * tomorrow (night 011029). If it will not fail, we won 27962306a36Sopenharmony_ci * finally: amount of IO did not increase at all. */ 28062306a36Sopenharmony_ci } while ((ioread32(tp->base_addr + CSR5) & RxIntr)); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* We use this simplistic scheme for IM. It's proven by 28562306a36Sopenharmony_ci real life installations. We can have IM enabled 28662306a36Sopenharmony_ci continuesly but this would cause unnecessary latency. 28762306a36Sopenharmony_ci Unfortunely we can't use all the NET_RX_* feedback here. 28862306a36Sopenharmony_ci This would turn on IM for devices that is not contributing 28962306a36Sopenharmony_ci to backlog congestion with unnecessary latency. 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci We monitor the device RX-ring and have: 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci HW Interrupt Mitigation either ON or OFF. 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci ON: More then 1 pkt received (per intr.) OR we are dropping 29662306a36Sopenharmony_ci OFF: Only 1 pkt received 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci Note. We only use min and max (0, 15) settings from mit_table */ 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if( tp->flags & HAS_INTR_MITIGATION) { 30262306a36Sopenharmony_ci if( received > 1 ) { 30362306a36Sopenharmony_ci if( ! tp->mit_on ) { 30462306a36Sopenharmony_ci tp->mit_on = 1; 30562306a36Sopenharmony_ci iowrite32(mit_table[MIT_TABLE], tp->base_addr + CSR11); 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci else { 30962306a36Sopenharmony_ci if( tp->mit_on ) { 31062306a36Sopenharmony_ci tp->mit_on = 0; 31162306a36Sopenharmony_ci iowrite32(0, tp->base_addr + CSR11); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */ 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci tulip_refill_rx(dev); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* If RX ring is not full we are out of memory. */ 32162306a36Sopenharmony_ci if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 32262306a36Sopenharmony_ci goto oom; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* Remove us from polling list and enable RX intr. */ 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci napi_complete_done(napi, work_done); 32762306a36Sopenharmony_ci iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* The last op happens after poll completion. Which means the following: 33062306a36Sopenharmony_ci * 1. it can race with disabling irqs in irq handler 33162306a36Sopenharmony_ci * 2. it can race with dise/enabling irqs in other poll threads 33262306a36Sopenharmony_ci * 3. if an irq raised after beginning loop, it will be immediately 33362306a36Sopenharmony_ci * triggered here. 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * Summarizing: the logic results in some redundant irqs both 33662306a36Sopenharmony_ci * due to races in masking and due to too late acking of already 33762306a36Sopenharmony_ci * processed irqs. But it must not result in losing events. 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return work_done; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci not_done: 34362306a36Sopenharmony_ci if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || 34462306a36Sopenharmony_ci tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 34562306a36Sopenharmony_ci tulip_refill_rx(dev); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 34862306a36Sopenharmony_ci goto oom; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return work_done; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci oom: /* Executed with RX ints disabled */ 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* Start timer, stop polling, but do not enable rx interrupts. */ 35562306a36Sopenharmony_ci mod_timer(&tp->oom_timer, jiffies+1); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* Think: timer_pending() was an explicit signature of bug. 35862306a36Sopenharmony_ci * Timer can be pending now but fired and completed 35962306a36Sopenharmony_ci * before we did napi_complete(). See? We would lose it. */ 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* remove ourselves from the polling list */ 36262306a36Sopenharmony_ci napi_complete_done(napi, work_done); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return work_done; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci#else /* CONFIG_TULIP_NAPI */ 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic int tulip_rx(struct net_device *dev) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct tulip_private *tp = netdev_priv(dev); 37262306a36Sopenharmony_ci int entry = tp->cur_rx % RX_RING_SIZE; 37362306a36Sopenharmony_ci int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; 37462306a36Sopenharmony_ci int received = 0; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (tulip_debug > 4) 37762306a36Sopenharmony_ci netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", 37862306a36Sopenharmony_ci entry, tp->rx_ring[entry].status); 37962306a36Sopenharmony_ci /* If we own the next entry, it is a new packet. Send it up. */ 38062306a36Sopenharmony_ci while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 38162306a36Sopenharmony_ci s32 status = le32_to_cpu(tp->rx_ring[entry].status); 38262306a36Sopenharmony_ci short pkt_len; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (tulip_debug > 5) 38562306a36Sopenharmony_ci netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", 38662306a36Sopenharmony_ci entry, status); 38762306a36Sopenharmony_ci if (--rx_work_limit < 0) 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci Omit the four octet CRC from the length. 39262306a36Sopenharmony_ci (May not be considered valid until we have 39362306a36Sopenharmony_ci checked status for RxLengthOver2047 bits) 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci pkt_len = ((status >> 16) & 0x7ff) - 4; 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci Maximum pkt_len is 1518 (1514 + vlan header) 39862306a36Sopenharmony_ci Anything higher than this is always invalid 39962306a36Sopenharmony_ci regardless of RxLengthOver2047 bits 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if ((status & (RxLengthOver2047 | 40362306a36Sopenharmony_ci RxDescCRCError | 40462306a36Sopenharmony_ci RxDescCollisionSeen | 40562306a36Sopenharmony_ci RxDescRunt | 40662306a36Sopenharmony_ci RxDescDescErr | 40762306a36Sopenharmony_ci RxWholePkt)) != RxWholePkt || 40862306a36Sopenharmony_ci pkt_len > 1518) { 40962306a36Sopenharmony_ci if ((status & (RxLengthOver2047 | 41062306a36Sopenharmony_ci RxWholePkt)) != RxWholePkt) { 41162306a36Sopenharmony_ci /* Ingore earlier buffers. */ 41262306a36Sopenharmony_ci if ((status & 0xffff) != 0x7fff) { 41362306a36Sopenharmony_ci if (tulip_debug > 1) 41462306a36Sopenharmony_ci netdev_warn(dev, 41562306a36Sopenharmony_ci "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", 41662306a36Sopenharmony_ci status); 41762306a36Sopenharmony_ci dev->stats.rx_length_errors++; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci } else { 42062306a36Sopenharmony_ci /* There was a fatal error. */ 42162306a36Sopenharmony_ci if (tulip_debug > 2) 42262306a36Sopenharmony_ci netdev_dbg(dev, "Receive error, Rx status %08x\n", 42362306a36Sopenharmony_ci status); 42462306a36Sopenharmony_ci dev->stats.rx_errors++; /* end of a packet.*/ 42562306a36Sopenharmony_ci if (pkt_len > 1518 || 42662306a36Sopenharmony_ci (status & RxDescRunt)) 42762306a36Sopenharmony_ci dev->stats.rx_length_errors++; 42862306a36Sopenharmony_ci if (status & 0x0004) 42962306a36Sopenharmony_ci dev->stats.rx_frame_errors++; 43062306a36Sopenharmony_ci if (status & 0x0002) 43162306a36Sopenharmony_ci dev->stats.rx_crc_errors++; 43262306a36Sopenharmony_ci if (status & 0x0001) 43362306a36Sopenharmony_ci dev->stats.rx_fifo_errors++; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci } else { 43662306a36Sopenharmony_ci struct sk_buff *skb; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Check if the packet is long enough to accept without copying 43962306a36Sopenharmony_ci to a minimally-sized skbuff. */ 44062306a36Sopenharmony_ci if (pkt_len < tulip_rx_copybreak && 44162306a36Sopenharmony_ci (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { 44262306a36Sopenharmony_ci skb_reserve(skb, 2); /* 16 byte align the IP header */ 44362306a36Sopenharmony_ci dma_sync_single_for_cpu(&tp->pdev->dev, 44462306a36Sopenharmony_ci tp->rx_buffers[entry].mapping, 44562306a36Sopenharmony_ci pkt_len, 44662306a36Sopenharmony_ci DMA_FROM_DEVICE); 44762306a36Sopenharmony_ci#if ! defined(__alpha__) 44862306a36Sopenharmony_ci skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data, 44962306a36Sopenharmony_ci pkt_len); 45062306a36Sopenharmony_ci skb_put(skb, pkt_len); 45162306a36Sopenharmony_ci#else 45262306a36Sopenharmony_ci skb_put_data(skb, 45362306a36Sopenharmony_ci tp->rx_buffers[entry].skb->data, 45462306a36Sopenharmony_ci pkt_len); 45562306a36Sopenharmony_ci#endif 45662306a36Sopenharmony_ci dma_sync_single_for_device(&tp->pdev->dev, 45762306a36Sopenharmony_ci tp->rx_buffers[entry].mapping, 45862306a36Sopenharmony_ci pkt_len, 45962306a36Sopenharmony_ci DMA_FROM_DEVICE); 46062306a36Sopenharmony_ci } else { /* Pass up the skb already on the Rx ring. */ 46162306a36Sopenharmony_ci char *temp = skb_put(skb = tp->rx_buffers[entry].skb, 46262306a36Sopenharmony_ci pkt_len); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci#ifndef final_version 46562306a36Sopenharmony_ci if (tp->rx_buffers[entry].mapping != 46662306a36Sopenharmony_ci le32_to_cpu(tp->rx_ring[entry].buffer1)) { 46762306a36Sopenharmony_ci dev_err(&dev->dev, 46862306a36Sopenharmony_ci "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %Lx %p / %p\n", 46962306a36Sopenharmony_ci le32_to_cpu(tp->rx_ring[entry].buffer1), 47062306a36Sopenharmony_ci (long long)tp->rx_buffers[entry].mapping, 47162306a36Sopenharmony_ci skb->head, temp); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci#endif 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci dma_unmap_single(&tp->pdev->dev, 47662306a36Sopenharmony_ci tp->rx_buffers[entry].mapping, 47762306a36Sopenharmony_ci PKT_BUF_SZ, DMA_FROM_DEVICE); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci tp->rx_buffers[entry].skb = NULL; 48062306a36Sopenharmony_ci tp->rx_buffers[entry].mapping = 0; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci netif_rx(skb); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci dev->stats.rx_packets++; 48762306a36Sopenharmony_ci dev->stats.rx_bytes += pkt_len; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci received++; 49062306a36Sopenharmony_ci entry = (++tp->cur_rx) % RX_RING_SIZE; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci return received; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci#endif /* CONFIG_TULIP_NAPI */ 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic inline unsigned int phy_interrupt (struct net_device *dev) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci#ifdef __hppa__ 49962306a36Sopenharmony_ci struct tulip_private *tp = netdev_priv(dev); 50062306a36Sopenharmony_ci int csr12 = ioread32(tp->base_addr + CSR12) & 0xff; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (csr12 != tp->csr12_shadow) { 50362306a36Sopenharmony_ci /* ack interrupt */ 50462306a36Sopenharmony_ci iowrite32(csr12 | 0x02, tp->base_addr + CSR12); 50562306a36Sopenharmony_ci tp->csr12_shadow = csr12; 50662306a36Sopenharmony_ci /* do link change stuff */ 50762306a36Sopenharmony_ci spin_lock(&tp->lock); 50862306a36Sopenharmony_ci tulip_check_duplex(dev); 50962306a36Sopenharmony_ci spin_unlock(&tp->lock); 51062306a36Sopenharmony_ci /* clear irq ack bit */ 51162306a36Sopenharmony_ci iowrite32(csr12 & ~0x02, tp->base_addr + CSR12); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return 1; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci#endif 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return 0; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci/* The interrupt handler does all of the Rx thread work and cleans up 52162306a36Sopenharmony_ci after the Tx thread. */ 52262306a36Sopenharmony_ciirqreturn_t tulip_interrupt(int irq, void *dev_instance) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct net_device *dev = (struct net_device *)dev_instance; 52562306a36Sopenharmony_ci struct tulip_private *tp = netdev_priv(dev); 52662306a36Sopenharmony_ci void __iomem *ioaddr = tp->base_addr; 52762306a36Sopenharmony_ci int csr5; 52862306a36Sopenharmony_ci int missed; 52962306a36Sopenharmony_ci int rx = 0; 53062306a36Sopenharmony_ci int tx = 0; 53162306a36Sopenharmony_ci int oi = 0; 53262306a36Sopenharmony_ci int maxrx = RX_RING_SIZE; 53362306a36Sopenharmony_ci int maxtx = TX_RING_SIZE; 53462306a36Sopenharmony_ci int maxoi = TX_RING_SIZE; 53562306a36Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI 53662306a36Sopenharmony_ci int rxd = 0; 53762306a36Sopenharmony_ci#else 53862306a36Sopenharmony_ci int entry; 53962306a36Sopenharmony_ci#endif 54062306a36Sopenharmony_ci unsigned int work_count = tulip_max_interrupt_work; 54162306a36Sopenharmony_ci unsigned int handled = 0; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* Let's see whether the interrupt really is for us */ 54462306a36Sopenharmony_ci csr5 = ioread32(ioaddr + CSR5); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (tp->flags & HAS_PHY_IRQ) 54762306a36Sopenharmony_ci handled = phy_interrupt (dev); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) 55062306a36Sopenharmony_ci return IRQ_RETVAL(handled); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci tp->nir++; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci do { 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { 55962306a36Sopenharmony_ci rxd++; 56062306a36Sopenharmony_ci /* Mask RX intrs and add the device to poll list. */ 56162306a36Sopenharmony_ci iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); 56262306a36Sopenharmony_ci napi_schedule(&tp->napi); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) 56562306a36Sopenharmony_ci break; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* Acknowledge the interrupt sources we handle here ASAP 56962306a36Sopenharmony_ci the poll function does Rx and RxNoBuf acking */ 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci iowrite32(csr5 & 0x0001ff3f, ioaddr + CSR5); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci#else 57462306a36Sopenharmony_ci /* Acknowledge all of the current interrupt sources ASAP. */ 57562306a36Sopenharmony_ci iowrite32(csr5 & 0x0001ffff, ioaddr + CSR5); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (csr5 & (RxIntr | RxNoBuf)) { 57962306a36Sopenharmony_ci rx += tulip_rx(dev); 58062306a36Sopenharmony_ci tulip_refill_rx(dev); 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci#endif /* CONFIG_TULIP_NAPI */ 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (tulip_debug > 4) 58662306a36Sopenharmony_ci netdev_dbg(dev, "interrupt csr5=%#8.8x new csr5=%#8.8x\n", 58762306a36Sopenharmony_ci csr5, ioread32(ioaddr + CSR5)); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { 59162306a36Sopenharmony_ci unsigned int dirty_tx; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci spin_lock(&tp->lock); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; 59662306a36Sopenharmony_ci dirty_tx++) { 59762306a36Sopenharmony_ci int entry = dirty_tx % TX_RING_SIZE; 59862306a36Sopenharmony_ci int status = le32_to_cpu(tp->tx_ring[entry].status); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (status < 0) 60162306a36Sopenharmony_ci break; /* It still has not been Txed */ 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* Check for Rx filter setup frames. */ 60462306a36Sopenharmony_ci if (tp->tx_buffers[entry].skb == NULL) { 60562306a36Sopenharmony_ci /* test because dummy frames not mapped */ 60662306a36Sopenharmony_ci if (tp->tx_buffers[entry].mapping) 60762306a36Sopenharmony_ci dma_unmap_single(&tp->pdev->dev, 60862306a36Sopenharmony_ci tp->tx_buffers[entry].mapping, 60962306a36Sopenharmony_ci sizeof(tp->setup_frame), 61062306a36Sopenharmony_ci DMA_TO_DEVICE); 61162306a36Sopenharmony_ci continue; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (status & 0x8000) { 61562306a36Sopenharmony_ci /* There was an major error, log it. */ 61662306a36Sopenharmony_ci#ifndef final_version 61762306a36Sopenharmony_ci if (tulip_debug > 1) 61862306a36Sopenharmony_ci netdev_dbg(dev, "Transmit error, Tx status %08x\n", 61962306a36Sopenharmony_ci status); 62062306a36Sopenharmony_ci#endif 62162306a36Sopenharmony_ci dev->stats.tx_errors++; 62262306a36Sopenharmony_ci if (status & 0x4104) 62362306a36Sopenharmony_ci dev->stats.tx_aborted_errors++; 62462306a36Sopenharmony_ci if (status & 0x0C00) 62562306a36Sopenharmony_ci dev->stats.tx_carrier_errors++; 62662306a36Sopenharmony_ci if (status & 0x0200) 62762306a36Sopenharmony_ci dev->stats.tx_window_errors++; 62862306a36Sopenharmony_ci if (status & 0x0002) 62962306a36Sopenharmony_ci dev->stats.tx_fifo_errors++; 63062306a36Sopenharmony_ci if ((status & 0x0080) && tp->full_duplex == 0) 63162306a36Sopenharmony_ci dev->stats.tx_heartbeat_errors++; 63262306a36Sopenharmony_ci } else { 63362306a36Sopenharmony_ci dev->stats.tx_bytes += 63462306a36Sopenharmony_ci tp->tx_buffers[entry].skb->len; 63562306a36Sopenharmony_ci dev->stats.collisions += (status >> 3) & 15; 63662306a36Sopenharmony_ci dev->stats.tx_packets++; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci dma_unmap_single(&tp->pdev->dev, 64062306a36Sopenharmony_ci tp->tx_buffers[entry].mapping, 64162306a36Sopenharmony_ci tp->tx_buffers[entry].skb->len, 64262306a36Sopenharmony_ci DMA_TO_DEVICE); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* Free the original skb. */ 64562306a36Sopenharmony_ci dev_kfree_skb_irq(tp->tx_buffers[entry].skb); 64662306a36Sopenharmony_ci tp->tx_buffers[entry].skb = NULL; 64762306a36Sopenharmony_ci tp->tx_buffers[entry].mapping = 0; 64862306a36Sopenharmony_ci tx++; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci#ifndef final_version 65262306a36Sopenharmony_ci if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { 65362306a36Sopenharmony_ci dev_err(&dev->dev, 65462306a36Sopenharmony_ci "Out-of-sync dirty pointer, %d vs. %d\n", 65562306a36Sopenharmony_ci dirty_tx, tp->cur_tx); 65662306a36Sopenharmony_ci dirty_tx += TX_RING_SIZE; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci#endif 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) 66162306a36Sopenharmony_ci netif_wake_queue(dev); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci tp->dirty_tx = dirty_tx; 66462306a36Sopenharmony_ci if (csr5 & TxDied) { 66562306a36Sopenharmony_ci if (tulip_debug > 2) 66662306a36Sopenharmony_ci dev_warn(&dev->dev, 66762306a36Sopenharmony_ci "The transmitter stopped. CSR5 is %x, CSR6 %x, new CSR6 %x\n", 66862306a36Sopenharmony_ci csr5, ioread32(ioaddr + CSR6), 66962306a36Sopenharmony_ci tp->csr6); 67062306a36Sopenharmony_ci tulip_restart_rxtx(tp); 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci spin_unlock(&tp->lock); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Log errors. */ 67662306a36Sopenharmony_ci if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ 67762306a36Sopenharmony_ci if (csr5 == 0xffffffff) 67862306a36Sopenharmony_ci break; 67962306a36Sopenharmony_ci if (csr5 & TxJabber) 68062306a36Sopenharmony_ci dev->stats.tx_errors++; 68162306a36Sopenharmony_ci if (csr5 & TxFIFOUnderflow) { 68262306a36Sopenharmony_ci if ((tp->csr6 & 0xC000) != 0xC000) 68362306a36Sopenharmony_ci tp->csr6 += 0x4000; /* Bump up the Tx threshold */ 68462306a36Sopenharmony_ci else 68562306a36Sopenharmony_ci tp->csr6 |= 0x00200000; /* Store-n-forward. */ 68662306a36Sopenharmony_ci /* Restart the transmit process. */ 68762306a36Sopenharmony_ci tulip_restart_rxtx(tp); 68862306a36Sopenharmony_ci iowrite32(0, ioaddr + CSR1); 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci if (csr5 & (RxDied | RxNoBuf)) { 69162306a36Sopenharmony_ci if (tp->flags & COMET_MAC_ADDR) { 69262306a36Sopenharmony_ci iowrite32(tp->mc_filter[0], ioaddr + 0xAC); 69362306a36Sopenharmony_ci iowrite32(tp->mc_filter[1], ioaddr + 0xB0); 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci if (csr5 & RxDied) { /* Missed a Rx frame. */ 69762306a36Sopenharmony_ci dev->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff; 69862306a36Sopenharmony_ci dev->stats.rx_errors++; 69962306a36Sopenharmony_ci tulip_start_rxtx(tp); 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci /* 70262306a36Sopenharmony_ci * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this 70362306a36Sopenharmony_ci * call is ever done under the spinlock 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_ci if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { 70662306a36Sopenharmony_ci if (tp->link_change) 70762306a36Sopenharmony_ci (tp->link_change)(dev, csr5); 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci if (csr5 & SystemError) { 71062306a36Sopenharmony_ci int error = (csr5 >> 23) & 7; 71162306a36Sopenharmony_ci /* oops, we hit a PCI error. The code produced corresponds 71262306a36Sopenharmony_ci * to the reason: 71362306a36Sopenharmony_ci * 0 - parity error 71462306a36Sopenharmony_ci * 1 - master abort 71562306a36Sopenharmony_ci * 2 - target abort 71662306a36Sopenharmony_ci * Note that on parity error, we should do a software reset 71762306a36Sopenharmony_ci * of the chip to get it back into a sane state (according 71862306a36Sopenharmony_ci * to the 21142/3 docs that is). 71962306a36Sopenharmony_ci * -- rmk 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci dev_err(&dev->dev, 72262306a36Sopenharmony_ci "(%lu) System Error occurred (%d)\n", 72362306a36Sopenharmony_ci tp->nir, error); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci /* Clear all error sources, included undocumented ones! */ 72662306a36Sopenharmony_ci iowrite32(0x0800f7ba, ioaddr + CSR5); 72762306a36Sopenharmony_ci oi++; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci if (csr5 & TimerInt) { 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (tulip_debug > 2) 73262306a36Sopenharmony_ci dev_err(&dev->dev, 73362306a36Sopenharmony_ci "Re-enabling interrupts, %08x\n", 73462306a36Sopenharmony_ci csr5); 73562306a36Sopenharmony_ci iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); 73662306a36Sopenharmony_ci tp->ttimer = 0; 73762306a36Sopenharmony_ci oi++; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci if (tx > maxtx || rx > maxrx || oi > maxoi) { 74062306a36Sopenharmony_ci if (tulip_debug > 1) 74162306a36Sopenharmony_ci dev_warn(&dev->dev, "Too much work during an interrupt, csr5=0x%08x. (%lu) (%d,%d,%d)\n", 74262306a36Sopenharmony_ci csr5, tp->nir, tx, rx, oi); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci /* Acknowledge all interrupt sources. */ 74562306a36Sopenharmony_ci iowrite32(0x8001ffff, ioaddr + CSR5); 74662306a36Sopenharmony_ci if (tp->flags & HAS_INTR_MITIGATION) { 74762306a36Sopenharmony_ci /* Josip Loncaric at ICASE did extensive experimentation 74862306a36Sopenharmony_ci to develop a good interrupt mitigation setting.*/ 74962306a36Sopenharmony_ci iowrite32(0x8b240000, ioaddr + CSR11); 75062306a36Sopenharmony_ci } else if (tp->chip_id == LC82C168) { 75162306a36Sopenharmony_ci /* the LC82C168 doesn't have a hw timer.*/ 75262306a36Sopenharmony_ci iowrite32(0x00, ioaddr + CSR7); 75362306a36Sopenharmony_ci mod_timer(&tp->timer, RUN_AT(HZ/50)); 75462306a36Sopenharmony_ci } else { 75562306a36Sopenharmony_ci /* Mask all interrupting sources, set timer to 75662306a36Sopenharmony_ci re-enable. */ 75762306a36Sopenharmony_ci iowrite32(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); 75862306a36Sopenharmony_ci iowrite32(0x0012, ioaddr + CSR11); 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci break; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci work_count--; 76462306a36Sopenharmony_ci if (work_count == 0) 76562306a36Sopenharmony_ci break; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci csr5 = ioread32(ioaddr + CSR5); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI 77062306a36Sopenharmony_ci if (rxd) 77162306a36Sopenharmony_ci csr5 &= ~RxPollInt; 77262306a36Sopenharmony_ci } while ((csr5 & (TxNoBuf | 77362306a36Sopenharmony_ci TxDied | 77462306a36Sopenharmony_ci TxIntr | 77562306a36Sopenharmony_ci TimerInt | 77662306a36Sopenharmony_ci /* Abnormal intr. */ 77762306a36Sopenharmony_ci RxDied | 77862306a36Sopenharmony_ci TxFIFOUnderflow | 77962306a36Sopenharmony_ci TxJabber | 78062306a36Sopenharmony_ci TPLnkFail | 78162306a36Sopenharmony_ci SystemError )) != 0); 78262306a36Sopenharmony_ci#else 78362306a36Sopenharmony_ci } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci tulip_refill_rx(dev); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci /* check if the card is in suspend mode */ 78862306a36Sopenharmony_ci entry = tp->dirty_rx % RX_RING_SIZE; 78962306a36Sopenharmony_ci if (tp->rx_buffers[entry].skb == NULL) { 79062306a36Sopenharmony_ci if (tulip_debug > 1) 79162306a36Sopenharmony_ci dev_warn(&dev->dev, 79262306a36Sopenharmony_ci "in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", 79362306a36Sopenharmony_ci tp->nir, tp->cur_rx, tp->ttimer, rx); 79462306a36Sopenharmony_ci if (tp->chip_id == LC82C168) { 79562306a36Sopenharmony_ci iowrite32(0x00, ioaddr + CSR7); 79662306a36Sopenharmony_ci mod_timer(&tp->timer, RUN_AT(HZ/50)); 79762306a36Sopenharmony_ci } else { 79862306a36Sopenharmony_ci if (tp->ttimer == 0 || (ioread32(ioaddr + CSR11) & 0xffff) == 0) { 79962306a36Sopenharmony_ci if (tulip_debug > 1) 80062306a36Sopenharmony_ci dev_warn(&dev->dev, 80162306a36Sopenharmony_ci "in rx suspend mode: (%lu) set timer\n", 80262306a36Sopenharmony_ci tp->nir); 80362306a36Sopenharmony_ci iowrite32(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, 80462306a36Sopenharmony_ci ioaddr + CSR7); 80562306a36Sopenharmony_ci iowrite32(TimerInt, ioaddr + CSR5); 80662306a36Sopenharmony_ci iowrite32(12, ioaddr + CSR11); 80762306a36Sopenharmony_ci tp->ttimer = 1; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci#endif /* CONFIG_TULIP_NAPI */ 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if ((missed = ioread32(ioaddr + CSR8) & 0x1ffff)) { 81462306a36Sopenharmony_ci dev->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci if (tulip_debug > 4) 81862306a36Sopenharmony_ci netdev_dbg(dev, "exiting interrupt, csr5=%#04x\n", 81962306a36Sopenharmony_ci ioread32(ioaddr + CSR5)); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return IRQ_HANDLED; 82262306a36Sopenharmony_ci} 823