18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci drivers/net/ethernet/dec/tulip/interrupt.c 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci Copyright 2000,2001 The Linux Kernel Team 58c2ecf20Sopenharmony_ci Written/copyright 1994-2001 by Donald Becker. 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci This software may be used and distributed according to the terms 88c2ecf20Sopenharmony_ci of the GNU General Public License, incorporated herein by reference. 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci Please submit bugs to http://bugzilla.kernel.org/ . 118c2ecf20Sopenharmony_ci*/ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include "tulip.h" 158c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ciint tulip_rx_copybreak; 188c2ecf20Sopenharmony_ciunsigned int tulip_max_interrupt_work; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 218c2ecf20Sopenharmony_ci#define MIT_SIZE 15 228c2ecf20Sopenharmony_ci#define MIT_TABLE 15 /* We use 0 or max */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic unsigned int mit_table[MIT_SIZE+1] = 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci /* CRS11 21143 hardware Mitigation Control Interrupt 278c2ecf20Sopenharmony_ci We use only RX mitigation we other techniques for 288c2ecf20Sopenharmony_ci TX intr. mitigation. 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 31 Cycle Size (timer control) 318c2ecf20Sopenharmony_ci 30:27 TX timer in 16 * Cycle size 328c2ecf20Sopenharmony_ci 26:24 TX No pkts before Int. 338c2ecf20Sopenharmony_ci 23:20 RX timer in Cycle size 348c2ecf20Sopenharmony_ci 19:17 RX No pkts before Int. 358c2ecf20Sopenharmony_ci 16 Continues Mode (CM) 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci 0x0, /* IM disabled */ 398c2ecf20Sopenharmony_ci 0x80150000, /* RX time = 1, RX pkts = 2, CM = 1 */ 408c2ecf20Sopenharmony_ci 0x80150000, 418c2ecf20Sopenharmony_ci 0x80270000, 428c2ecf20Sopenharmony_ci 0x80370000, 438c2ecf20Sopenharmony_ci 0x80490000, 448c2ecf20Sopenharmony_ci 0x80590000, 458c2ecf20Sopenharmony_ci 0x80690000, 468c2ecf20Sopenharmony_ci 0x807B0000, 478c2ecf20Sopenharmony_ci 0x808B0000, 488c2ecf20Sopenharmony_ci 0x809D0000, 498c2ecf20Sopenharmony_ci 0x80AD0000, 508c2ecf20Sopenharmony_ci 0x80BD0000, 518c2ecf20Sopenharmony_ci 0x80CF0000, 528c2ecf20Sopenharmony_ci 0x80DF0000, 538c2ecf20Sopenharmony_ci// 0x80FF0000 /* RX time = 16, RX pkts = 7, CM = 1 */ 548c2ecf20Sopenharmony_ci 0x80F10000 /* RX time = 16, RX pkts = 0, CM = 1 */ 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci#endif 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciint tulip_refill_rx(struct net_device *dev) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct tulip_private *tp = netdev_priv(dev); 628c2ecf20Sopenharmony_ci int entry; 638c2ecf20Sopenharmony_ci int refilled = 0; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Refill the Rx ring buffers. */ 668c2ecf20Sopenharmony_ci for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { 678c2ecf20Sopenharmony_ci entry = tp->dirty_rx % RX_RING_SIZE; 688c2ecf20Sopenharmony_ci if (tp->rx_buffers[entry].skb == NULL) { 698c2ecf20Sopenharmony_ci struct sk_buff *skb; 708c2ecf20Sopenharmony_ci dma_addr_t mapping; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci skb = tp->rx_buffers[entry].skb = 738c2ecf20Sopenharmony_ci netdev_alloc_skb(dev, PKT_BUF_SZ); 748c2ecf20Sopenharmony_ci if (skb == NULL) 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci mapping = dma_map_single(&tp->pdev->dev, skb->data, 788c2ecf20Sopenharmony_ci PKT_BUF_SZ, DMA_FROM_DEVICE); 798c2ecf20Sopenharmony_ci if (dma_mapping_error(&tp->pdev->dev, mapping)) { 808c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 818c2ecf20Sopenharmony_ci tp->rx_buffers[entry].skb = NULL; 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci tp->rx_buffers[entry].mapping = mapping; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci tp->rx_ring[entry].buffer1 = cpu_to_le32(mapping); 888c2ecf20Sopenharmony_ci refilled++; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci tp->rx_ring[entry].status = cpu_to_le32(DescOwned); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci if(tp->chip_id == LC82C168) { 938c2ecf20Sopenharmony_ci if(((ioread32(tp->base_addr + CSR5)>>17)&0x07) == 4) { 948c2ecf20Sopenharmony_ci /* Rx stopped due to out of buffers, 958c2ecf20Sopenharmony_ci * restart it 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci iowrite32(0x01, tp->base_addr + CSR2); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci return refilled; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_civoid oom_timer(struct timer_list *t) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct tulip_private *tp = from_timer(tp, t, oom_timer); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci napi_schedule(&tp->napi); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciint tulip_poll(struct napi_struct *napi, int budget) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct tulip_private *tp = container_of(napi, struct tulip_private, napi); 1158c2ecf20Sopenharmony_ci struct net_device *dev = tp->dev; 1168c2ecf20Sopenharmony_ci int entry = tp->cur_rx % RX_RING_SIZE; 1178c2ecf20Sopenharmony_ci int work_done = 0; 1188c2ecf20Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 1198c2ecf20Sopenharmony_ci int received = 0; 1208c2ecf20Sopenharmony_ci#endif 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* that one buffer is needed for mit activation; or might be a 1258c2ecf20Sopenharmony_ci bug in the ring buffer code; check later -- JHS*/ 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (budget >=RX_RING_SIZE) budget--; 1288c2ecf20Sopenharmony_ci#endif 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (tulip_debug > 4) 1318c2ecf20Sopenharmony_ci netdev_dbg(dev, " In tulip_rx(), entry %d %08x\n", 1328c2ecf20Sopenharmony_ci entry, tp->rx_ring[entry].status); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci do { 1358c2ecf20Sopenharmony_ci if (ioread32(tp->base_addr + CSR5) == 0xffffffff) { 1368c2ecf20Sopenharmony_ci netdev_dbg(dev, " In tulip_poll(), hardware disappeared\n"); 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci /* Acknowledge current RX interrupt sources. */ 1408c2ecf20Sopenharmony_ci iowrite32((RxIntr | RxNoBuf), tp->base_addr + CSR5); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* If we own the next entry, it is a new packet. Send it up. */ 1448c2ecf20Sopenharmony_ci while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 1458c2ecf20Sopenharmony_ci s32 status = le32_to_cpu(tp->rx_ring[entry].status); 1468c2ecf20Sopenharmony_ci short pkt_len; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (tulip_debug > 5) 1528c2ecf20Sopenharmony_ci netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", 1538c2ecf20Sopenharmony_ci entry, status); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (++work_done >= budget) 1568c2ecf20Sopenharmony_ci goto not_done; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* 1598c2ecf20Sopenharmony_ci * Omit the four octet CRC from the length. 1608c2ecf20Sopenharmony_ci * (May not be considered valid until we have 1618c2ecf20Sopenharmony_ci * checked status for RxLengthOver2047 bits) 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci pkt_len = ((status >> 16) & 0x7ff) - 4; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* 1668c2ecf20Sopenharmony_ci * Maximum pkt_len is 1518 (1514 + vlan header) 1678c2ecf20Sopenharmony_ci * Anything higher than this is always invalid 1688c2ecf20Sopenharmony_ci * regardless of RxLengthOver2047 bits 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if ((status & (RxLengthOver2047 | 1728c2ecf20Sopenharmony_ci RxDescCRCError | 1738c2ecf20Sopenharmony_ci RxDescCollisionSeen | 1748c2ecf20Sopenharmony_ci RxDescRunt | 1758c2ecf20Sopenharmony_ci RxDescDescErr | 1768c2ecf20Sopenharmony_ci RxWholePkt)) != RxWholePkt || 1778c2ecf20Sopenharmony_ci pkt_len > 1518) { 1788c2ecf20Sopenharmony_ci if ((status & (RxLengthOver2047 | 1798c2ecf20Sopenharmony_ci RxWholePkt)) != RxWholePkt) { 1808c2ecf20Sopenharmony_ci /* Ingore earlier buffers. */ 1818c2ecf20Sopenharmony_ci if ((status & 0xffff) != 0x7fff) { 1828c2ecf20Sopenharmony_ci if (tulip_debug > 1) 1838c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 1848c2ecf20Sopenharmony_ci "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", 1858c2ecf20Sopenharmony_ci status); 1868c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci } else { 1898c2ecf20Sopenharmony_ci /* There was a fatal error. */ 1908c2ecf20Sopenharmony_ci if (tulip_debug > 2) 1918c2ecf20Sopenharmony_ci netdev_dbg(dev, "Receive error, Rx status %08x\n", 1928c2ecf20Sopenharmony_ci status); 1938c2ecf20Sopenharmony_ci dev->stats.rx_errors++; /* end of a packet.*/ 1948c2ecf20Sopenharmony_ci if (pkt_len > 1518 || 1958c2ecf20Sopenharmony_ci (status & RxDescRunt)) 1968c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (status & 0x0004) 1998c2ecf20Sopenharmony_ci dev->stats.rx_frame_errors++; 2008c2ecf20Sopenharmony_ci if (status & 0x0002) 2018c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors++; 2028c2ecf20Sopenharmony_ci if (status & 0x0001) 2038c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci } else { 2068c2ecf20Sopenharmony_ci struct sk_buff *skb; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Check if the packet is long enough to accept without copying 2098c2ecf20Sopenharmony_ci to a minimally-sized skbuff. */ 2108c2ecf20Sopenharmony_ci if (pkt_len < tulip_rx_copybreak && 2118c2ecf20Sopenharmony_ci (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { 2128c2ecf20Sopenharmony_ci skb_reserve(skb, 2); /* 16 byte align the IP header */ 2138c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&tp->pdev->dev, 2148c2ecf20Sopenharmony_ci tp->rx_buffers[entry].mapping, 2158c2ecf20Sopenharmony_ci pkt_len, 2168c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 2178c2ecf20Sopenharmony_ci#if ! defined(__alpha__) 2188c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data, 2198c2ecf20Sopenharmony_ci pkt_len); 2208c2ecf20Sopenharmony_ci skb_put(skb, pkt_len); 2218c2ecf20Sopenharmony_ci#else 2228c2ecf20Sopenharmony_ci skb_put_data(skb, 2238c2ecf20Sopenharmony_ci tp->rx_buffers[entry].skb->data, 2248c2ecf20Sopenharmony_ci pkt_len); 2258c2ecf20Sopenharmony_ci#endif 2268c2ecf20Sopenharmony_ci dma_sync_single_for_device(&tp->pdev->dev, 2278c2ecf20Sopenharmony_ci tp->rx_buffers[entry].mapping, 2288c2ecf20Sopenharmony_ci pkt_len, 2298c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 2308c2ecf20Sopenharmony_ci } else { /* Pass up the skb already on the Rx ring. */ 2318c2ecf20Sopenharmony_ci char *temp = skb_put(skb = tp->rx_buffers[entry].skb, 2328c2ecf20Sopenharmony_ci pkt_len); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci#ifndef final_version 2358c2ecf20Sopenharmony_ci if (tp->rx_buffers[entry].mapping != 2368c2ecf20Sopenharmony_ci le32_to_cpu(tp->rx_ring[entry].buffer1)) { 2378c2ecf20Sopenharmony_ci dev_err(&dev->dev, 2388c2ecf20Sopenharmony_ci "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %08llx %p / %p\n", 2398c2ecf20Sopenharmony_ci le32_to_cpu(tp->rx_ring[entry].buffer1), 2408c2ecf20Sopenharmony_ci (unsigned long long)tp->rx_buffers[entry].mapping, 2418c2ecf20Sopenharmony_ci skb->head, temp); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci#endif 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci dma_unmap_single(&tp->pdev->dev, 2468c2ecf20Sopenharmony_ci tp->rx_buffers[entry].mapping, 2478c2ecf20Sopenharmony_ci PKT_BUF_SZ, 2488c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci tp->rx_buffers[entry].skb = NULL; 2518c2ecf20Sopenharmony_ci tp->rx_buffers[entry].mapping = 0; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci netif_receive_skb(skb); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 2588c2ecf20Sopenharmony_ci dev->stats.rx_bytes += pkt_len; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 2618c2ecf20Sopenharmony_ci received++; 2628c2ecf20Sopenharmony_ci#endif 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci entry = (++tp->cur_rx) % RX_RING_SIZE; 2658c2ecf20Sopenharmony_ci if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) 2668c2ecf20Sopenharmony_ci tulip_refill_rx(dev); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* New ack strategy... irq does not ack Rx any longer 2718c2ecf20Sopenharmony_ci hopefully this helps */ 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* Really bad things can happen here... If new packet arrives 2748c2ecf20Sopenharmony_ci * and an irq arrives (tx or just due to occasionally unset 2758c2ecf20Sopenharmony_ci * mask), it will be acked by irq handler, but new thread 2768c2ecf20Sopenharmony_ci * is not scheduled. It is major hole in design. 2778c2ecf20Sopenharmony_ci * No idea how to fix this if "playing with fire" will fail 2788c2ecf20Sopenharmony_ci * tomorrow (night 011029). If it will not fail, we won 2798c2ecf20Sopenharmony_ci * finally: amount of IO did not increase at all. */ 2808c2ecf20Sopenharmony_ci } while ((ioread32(tp->base_addr + CSR5) & RxIntr)); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* We use this simplistic scheme for IM. It's proven by 2858c2ecf20Sopenharmony_ci real life installations. We can have IM enabled 2868c2ecf20Sopenharmony_ci continuesly but this would cause unnecessary latency. 2878c2ecf20Sopenharmony_ci Unfortunely we can't use all the NET_RX_* feedback here. 2888c2ecf20Sopenharmony_ci This would turn on IM for devices that is not contributing 2898c2ecf20Sopenharmony_ci to backlog congestion with unnecessary latency. 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci We monitor the device RX-ring and have: 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci HW Interrupt Mitigation either ON or OFF. 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci ON: More then 1 pkt received (per intr.) OR we are dropping 2968c2ecf20Sopenharmony_ci OFF: Only 1 pkt received 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci Note. We only use min and max (0, 15) settings from mit_table */ 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if( tp->flags & HAS_INTR_MITIGATION) { 3028c2ecf20Sopenharmony_ci if( received > 1 ) { 3038c2ecf20Sopenharmony_ci if( ! tp->mit_on ) { 3048c2ecf20Sopenharmony_ci tp->mit_on = 1; 3058c2ecf20Sopenharmony_ci iowrite32(mit_table[MIT_TABLE], tp->base_addr + CSR11); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci else { 3098c2ecf20Sopenharmony_ci if( tp->mit_on ) { 3108c2ecf20Sopenharmony_ci tp->mit_on = 0; 3118c2ecf20Sopenharmony_ci iowrite32(0, tp->base_addr + CSR11); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */ 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci tulip_refill_rx(dev); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* If RX ring is not full we are out of memory. */ 3218c2ecf20Sopenharmony_ci if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 3228c2ecf20Sopenharmony_ci goto oom; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Remove us from polling list and enable RX intr. */ 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 3278c2ecf20Sopenharmony_ci iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* The last op happens after poll completion. Which means the following: 3308c2ecf20Sopenharmony_ci * 1. it can race with disabling irqs in irq handler 3318c2ecf20Sopenharmony_ci * 2. it can race with dise/enabling irqs in other poll threads 3328c2ecf20Sopenharmony_ci * 3. if an irq raised after beginning loop, it will be immediately 3338c2ecf20Sopenharmony_ci * triggered here. 3348c2ecf20Sopenharmony_ci * 3358c2ecf20Sopenharmony_ci * Summarizing: the logic results in some redundant irqs both 3368c2ecf20Sopenharmony_ci * due to races in masking and due to too late acking of already 3378c2ecf20Sopenharmony_ci * processed irqs. But it must not result in losing events. 3388c2ecf20Sopenharmony_ci */ 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return work_done; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci not_done: 3438c2ecf20Sopenharmony_ci if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || 3448c2ecf20Sopenharmony_ci tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 3458c2ecf20Sopenharmony_ci tulip_refill_rx(dev); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) 3488c2ecf20Sopenharmony_ci goto oom; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return work_done; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci oom: /* Executed with RX ints disabled */ 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* Start timer, stop polling, but do not enable rx interrupts. */ 3558c2ecf20Sopenharmony_ci mod_timer(&tp->oom_timer, jiffies+1); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Think: timer_pending() was an explicit signature of bug. 3588c2ecf20Sopenharmony_ci * Timer can be pending now but fired and completed 3598c2ecf20Sopenharmony_ci * before we did napi_complete(). See? We would lose it. */ 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* remove ourselves from the polling list */ 3628c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return work_done; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci#else /* CONFIG_TULIP_NAPI */ 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic int tulip_rx(struct net_device *dev) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct tulip_private *tp = netdev_priv(dev); 3728c2ecf20Sopenharmony_ci int entry = tp->cur_rx % RX_RING_SIZE; 3738c2ecf20Sopenharmony_ci int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; 3748c2ecf20Sopenharmony_ci int received = 0; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (tulip_debug > 4) 3778c2ecf20Sopenharmony_ci netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", 3788c2ecf20Sopenharmony_ci entry, tp->rx_ring[entry].status); 3798c2ecf20Sopenharmony_ci /* If we own the next entry, it is a new packet. Send it up. */ 3808c2ecf20Sopenharmony_ci while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 3818c2ecf20Sopenharmony_ci s32 status = le32_to_cpu(tp->rx_ring[entry].status); 3828c2ecf20Sopenharmony_ci short pkt_len; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (tulip_debug > 5) 3858c2ecf20Sopenharmony_ci netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", 3868c2ecf20Sopenharmony_ci entry, status); 3878c2ecf20Sopenharmony_ci if (--rx_work_limit < 0) 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* 3918c2ecf20Sopenharmony_ci Omit the four octet CRC from the length. 3928c2ecf20Sopenharmony_ci (May not be considered valid until we have 3938c2ecf20Sopenharmony_ci checked status for RxLengthOver2047 bits) 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_ci pkt_len = ((status >> 16) & 0x7ff) - 4; 3968c2ecf20Sopenharmony_ci /* 3978c2ecf20Sopenharmony_ci Maximum pkt_len is 1518 (1514 + vlan header) 3988c2ecf20Sopenharmony_ci Anything higher than this is always invalid 3998c2ecf20Sopenharmony_ci regardless of RxLengthOver2047 bits 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if ((status & (RxLengthOver2047 | 4038c2ecf20Sopenharmony_ci RxDescCRCError | 4048c2ecf20Sopenharmony_ci RxDescCollisionSeen | 4058c2ecf20Sopenharmony_ci RxDescRunt | 4068c2ecf20Sopenharmony_ci RxDescDescErr | 4078c2ecf20Sopenharmony_ci RxWholePkt)) != RxWholePkt || 4088c2ecf20Sopenharmony_ci pkt_len > 1518) { 4098c2ecf20Sopenharmony_ci if ((status & (RxLengthOver2047 | 4108c2ecf20Sopenharmony_ci RxWholePkt)) != RxWholePkt) { 4118c2ecf20Sopenharmony_ci /* Ingore earlier buffers. */ 4128c2ecf20Sopenharmony_ci if ((status & 0xffff) != 0x7fff) { 4138c2ecf20Sopenharmony_ci if (tulip_debug > 1) 4148c2ecf20Sopenharmony_ci netdev_warn(dev, 4158c2ecf20Sopenharmony_ci "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", 4168c2ecf20Sopenharmony_ci status); 4178c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci } else { 4208c2ecf20Sopenharmony_ci /* There was a fatal error. */ 4218c2ecf20Sopenharmony_ci if (tulip_debug > 2) 4228c2ecf20Sopenharmony_ci netdev_dbg(dev, "Receive error, Rx status %08x\n", 4238c2ecf20Sopenharmony_ci status); 4248c2ecf20Sopenharmony_ci dev->stats.rx_errors++; /* end of a packet.*/ 4258c2ecf20Sopenharmony_ci if (pkt_len > 1518 || 4268c2ecf20Sopenharmony_ci (status & RxDescRunt)) 4278c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 4288c2ecf20Sopenharmony_ci if (status & 0x0004) 4298c2ecf20Sopenharmony_ci dev->stats.rx_frame_errors++; 4308c2ecf20Sopenharmony_ci if (status & 0x0002) 4318c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors++; 4328c2ecf20Sopenharmony_ci if (status & 0x0001) 4338c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci } else { 4368c2ecf20Sopenharmony_ci struct sk_buff *skb; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Check if the packet is long enough to accept without copying 4398c2ecf20Sopenharmony_ci to a minimally-sized skbuff. */ 4408c2ecf20Sopenharmony_ci if (pkt_len < tulip_rx_copybreak && 4418c2ecf20Sopenharmony_ci (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { 4428c2ecf20Sopenharmony_ci skb_reserve(skb, 2); /* 16 byte align the IP header */ 4438c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&tp->pdev->dev, 4448c2ecf20Sopenharmony_ci tp->rx_buffers[entry].mapping, 4458c2ecf20Sopenharmony_ci pkt_len, 4468c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 4478c2ecf20Sopenharmony_ci#if ! defined(__alpha__) 4488c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data, 4498c2ecf20Sopenharmony_ci pkt_len); 4508c2ecf20Sopenharmony_ci skb_put(skb, pkt_len); 4518c2ecf20Sopenharmony_ci#else 4528c2ecf20Sopenharmony_ci skb_put_data(skb, 4538c2ecf20Sopenharmony_ci tp->rx_buffers[entry].skb->data, 4548c2ecf20Sopenharmony_ci pkt_len); 4558c2ecf20Sopenharmony_ci#endif 4568c2ecf20Sopenharmony_ci dma_sync_single_for_device(&tp->pdev->dev, 4578c2ecf20Sopenharmony_ci tp->rx_buffers[entry].mapping, 4588c2ecf20Sopenharmony_ci pkt_len, 4598c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 4608c2ecf20Sopenharmony_ci } else { /* Pass up the skb already on the Rx ring. */ 4618c2ecf20Sopenharmony_ci char *temp = skb_put(skb = tp->rx_buffers[entry].skb, 4628c2ecf20Sopenharmony_ci pkt_len); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci#ifndef final_version 4658c2ecf20Sopenharmony_ci if (tp->rx_buffers[entry].mapping != 4668c2ecf20Sopenharmony_ci le32_to_cpu(tp->rx_ring[entry].buffer1)) { 4678c2ecf20Sopenharmony_ci dev_err(&dev->dev, 4688c2ecf20Sopenharmony_ci "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %Lx %p / %p\n", 4698c2ecf20Sopenharmony_ci le32_to_cpu(tp->rx_ring[entry].buffer1), 4708c2ecf20Sopenharmony_ci (long long)tp->rx_buffers[entry].mapping, 4718c2ecf20Sopenharmony_ci skb->head, temp); 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci#endif 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci dma_unmap_single(&tp->pdev->dev, 4768c2ecf20Sopenharmony_ci tp->rx_buffers[entry].mapping, 4778c2ecf20Sopenharmony_ci PKT_BUF_SZ, DMA_FROM_DEVICE); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci tp->rx_buffers[entry].skb = NULL; 4808c2ecf20Sopenharmony_ci tp->rx_buffers[entry].mapping = 0; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci netif_rx(skb); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 4878c2ecf20Sopenharmony_ci dev->stats.rx_bytes += pkt_len; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci received++; 4908c2ecf20Sopenharmony_ci entry = (++tp->cur_rx) % RX_RING_SIZE; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci return received; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci#endif /* CONFIG_TULIP_NAPI */ 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic inline unsigned int phy_interrupt (struct net_device *dev) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci#ifdef __hppa__ 4998c2ecf20Sopenharmony_ci struct tulip_private *tp = netdev_priv(dev); 5008c2ecf20Sopenharmony_ci int csr12 = ioread32(tp->base_addr + CSR12) & 0xff; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (csr12 != tp->csr12_shadow) { 5038c2ecf20Sopenharmony_ci /* ack interrupt */ 5048c2ecf20Sopenharmony_ci iowrite32(csr12 | 0x02, tp->base_addr + CSR12); 5058c2ecf20Sopenharmony_ci tp->csr12_shadow = csr12; 5068c2ecf20Sopenharmony_ci /* do link change stuff */ 5078c2ecf20Sopenharmony_ci spin_lock(&tp->lock); 5088c2ecf20Sopenharmony_ci tulip_check_duplex(dev); 5098c2ecf20Sopenharmony_ci spin_unlock(&tp->lock); 5108c2ecf20Sopenharmony_ci /* clear irq ack bit */ 5118c2ecf20Sopenharmony_ci iowrite32(csr12 & ~0x02, tp->base_addr + CSR12); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci return 1; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci#endif 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/* The interrupt handler does all of the Rx thread work and cleans up 5218c2ecf20Sopenharmony_ci after the Tx thread. */ 5228c2ecf20Sopenharmony_ciirqreturn_t tulip_interrupt(int irq, void *dev_instance) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *)dev_instance; 5258c2ecf20Sopenharmony_ci struct tulip_private *tp = netdev_priv(dev); 5268c2ecf20Sopenharmony_ci void __iomem *ioaddr = tp->base_addr; 5278c2ecf20Sopenharmony_ci int csr5; 5288c2ecf20Sopenharmony_ci int missed; 5298c2ecf20Sopenharmony_ci int rx = 0; 5308c2ecf20Sopenharmony_ci int tx = 0; 5318c2ecf20Sopenharmony_ci int oi = 0; 5328c2ecf20Sopenharmony_ci int maxrx = RX_RING_SIZE; 5338c2ecf20Sopenharmony_ci int maxtx = TX_RING_SIZE; 5348c2ecf20Sopenharmony_ci int maxoi = TX_RING_SIZE; 5358c2ecf20Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI 5368c2ecf20Sopenharmony_ci int rxd = 0; 5378c2ecf20Sopenharmony_ci#else 5388c2ecf20Sopenharmony_ci int entry; 5398c2ecf20Sopenharmony_ci#endif 5408c2ecf20Sopenharmony_ci unsigned int work_count = tulip_max_interrupt_work; 5418c2ecf20Sopenharmony_ci unsigned int handled = 0; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* Let's see whether the interrupt really is for us */ 5448c2ecf20Sopenharmony_ci csr5 = ioread32(ioaddr + CSR5); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (tp->flags & HAS_PHY_IRQ) 5478c2ecf20Sopenharmony_ci handled = phy_interrupt (dev); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) 5508c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci tp->nir++; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci do { 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { 5598c2ecf20Sopenharmony_ci rxd++; 5608c2ecf20Sopenharmony_ci /* Mask RX intrs and add the device to poll list. */ 5618c2ecf20Sopenharmony_ci iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); 5628c2ecf20Sopenharmony_ci napi_schedule(&tp->napi); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) 5658c2ecf20Sopenharmony_ci break; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* Acknowledge the interrupt sources we handle here ASAP 5698c2ecf20Sopenharmony_ci the poll function does Rx and RxNoBuf acking */ 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci iowrite32(csr5 & 0x0001ff3f, ioaddr + CSR5); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci#else 5748c2ecf20Sopenharmony_ci /* Acknowledge all of the current interrupt sources ASAP. */ 5758c2ecf20Sopenharmony_ci iowrite32(csr5 & 0x0001ffff, ioaddr + CSR5); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (csr5 & (RxIntr | RxNoBuf)) { 5798c2ecf20Sopenharmony_ci rx += tulip_rx(dev); 5808c2ecf20Sopenharmony_ci tulip_refill_rx(dev); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci#endif /* CONFIG_TULIP_NAPI */ 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (tulip_debug > 4) 5868c2ecf20Sopenharmony_ci netdev_dbg(dev, "interrupt csr5=%#8.8x new csr5=%#8.8x\n", 5878c2ecf20Sopenharmony_ci csr5, ioread32(ioaddr + CSR5)); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { 5918c2ecf20Sopenharmony_ci unsigned int dirty_tx; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci spin_lock(&tp->lock); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; 5968c2ecf20Sopenharmony_ci dirty_tx++) { 5978c2ecf20Sopenharmony_ci int entry = dirty_tx % TX_RING_SIZE; 5988c2ecf20Sopenharmony_ci int status = le32_to_cpu(tp->tx_ring[entry].status); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (status < 0) 6018c2ecf20Sopenharmony_ci break; /* It still has not been Txed */ 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* Check for Rx filter setup frames. */ 6048c2ecf20Sopenharmony_ci if (tp->tx_buffers[entry].skb == NULL) { 6058c2ecf20Sopenharmony_ci /* test because dummy frames not mapped */ 6068c2ecf20Sopenharmony_ci if (tp->tx_buffers[entry].mapping) 6078c2ecf20Sopenharmony_ci dma_unmap_single(&tp->pdev->dev, 6088c2ecf20Sopenharmony_ci tp->tx_buffers[entry].mapping, 6098c2ecf20Sopenharmony_ci sizeof(tp->setup_frame), 6108c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6118c2ecf20Sopenharmony_ci continue; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (status & 0x8000) { 6158c2ecf20Sopenharmony_ci /* There was an major error, log it. */ 6168c2ecf20Sopenharmony_ci#ifndef final_version 6178c2ecf20Sopenharmony_ci if (tulip_debug > 1) 6188c2ecf20Sopenharmony_ci netdev_dbg(dev, "Transmit error, Tx status %08x\n", 6198c2ecf20Sopenharmony_ci status); 6208c2ecf20Sopenharmony_ci#endif 6218c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 6228c2ecf20Sopenharmony_ci if (status & 0x4104) 6238c2ecf20Sopenharmony_ci dev->stats.tx_aborted_errors++; 6248c2ecf20Sopenharmony_ci if (status & 0x0C00) 6258c2ecf20Sopenharmony_ci dev->stats.tx_carrier_errors++; 6268c2ecf20Sopenharmony_ci if (status & 0x0200) 6278c2ecf20Sopenharmony_ci dev->stats.tx_window_errors++; 6288c2ecf20Sopenharmony_ci if (status & 0x0002) 6298c2ecf20Sopenharmony_ci dev->stats.tx_fifo_errors++; 6308c2ecf20Sopenharmony_ci if ((status & 0x0080) && tp->full_duplex == 0) 6318c2ecf20Sopenharmony_ci dev->stats.tx_heartbeat_errors++; 6328c2ecf20Sopenharmony_ci } else { 6338c2ecf20Sopenharmony_ci dev->stats.tx_bytes += 6348c2ecf20Sopenharmony_ci tp->tx_buffers[entry].skb->len; 6358c2ecf20Sopenharmony_ci dev->stats.collisions += (status >> 3) & 15; 6368c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci dma_unmap_single(&tp->pdev->dev, 6408c2ecf20Sopenharmony_ci tp->tx_buffers[entry].mapping, 6418c2ecf20Sopenharmony_ci tp->tx_buffers[entry].skb->len, 6428c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Free the original skb. */ 6458c2ecf20Sopenharmony_ci dev_kfree_skb_irq(tp->tx_buffers[entry].skb); 6468c2ecf20Sopenharmony_ci tp->tx_buffers[entry].skb = NULL; 6478c2ecf20Sopenharmony_ci tp->tx_buffers[entry].mapping = 0; 6488c2ecf20Sopenharmony_ci tx++; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci#ifndef final_version 6528c2ecf20Sopenharmony_ci if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { 6538c2ecf20Sopenharmony_ci dev_err(&dev->dev, 6548c2ecf20Sopenharmony_ci "Out-of-sync dirty pointer, %d vs. %d\n", 6558c2ecf20Sopenharmony_ci dirty_tx, tp->cur_tx); 6568c2ecf20Sopenharmony_ci dirty_tx += TX_RING_SIZE; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci#endif 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) 6618c2ecf20Sopenharmony_ci netif_wake_queue(dev); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci tp->dirty_tx = dirty_tx; 6648c2ecf20Sopenharmony_ci if (csr5 & TxDied) { 6658c2ecf20Sopenharmony_ci if (tulip_debug > 2) 6668c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 6678c2ecf20Sopenharmony_ci "The transmitter stopped. CSR5 is %x, CSR6 %x, new CSR6 %x\n", 6688c2ecf20Sopenharmony_ci csr5, ioread32(ioaddr + CSR6), 6698c2ecf20Sopenharmony_ci tp->csr6); 6708c2ecf20Sopenharmony_ci tulip_restart_rxtx(tp); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci spin_unlock(&tp->lock); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci /* Log errors. */ 6768c2ecf20Sopenharmony_ci if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ 6778c2ecf20Sopenharmony_ci if (csr5 == 0xffffffff) 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci if (csr5 & TxJabber) 6808c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 6818c2ecf20Sopenharmony_ci if (csr5 & TxFIFOUnderflow) { 6828c2ecf20Sopenharmony_ci if ((tp->csr6 & 0xC000) != 0xC000) 6838c2ecf20Sopenharmony_ci tp->csr6 += 0x4000; /* Bump up the Tx threshold */ 6848c2ecf20Sopenharmony_ci else 6858c2ecf20Sopenharmony_ci tp->csr6 |= 0x00200000; /* Store-n-forward. */ 6868c2ecf20Sopenharmony_ci /* Restart the transmit process. */ 6878c2ecf20Sopenharmony_ci tulip_restart_rxtx(tp); 6888c2ecf20Sopenharmony_ci iowrite32(0, ioaddr + CSR1); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci if (csr5 & (RxDied | RxNoBuf)) { 6918c2ecf20Sopenharmony_ci if (tp->flags & COMET_MAC_ADDR) { 6928c2ecf20Sopenharmony_ci iowrite32(tp->mc_filter[0], ioaddr + 0xAC); 6938c2ecf20Sopenharmony_ci iowrite32(tp->mc_filter[1], ioaddr + 0xB0); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci if (csr5 & RxDied) { /* Missed a Rx frame. */ 6978c2ecf20Sopenharmony_ci dev->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff; 6988c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 6998c2ecf20Sopenharmony_ci tulip_start_rxtx(tp); 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci /* 7028c2ecf20Sopenharmony_ci * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this 7038c2ecf20Sopenharmony_ci * call is ever done under the spinlock 7048c2ecf20Sopenharmony_ci */ 7058c2ecf20Sopenharmony_ci if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { 7068c2ecf20Sopenharmony_ci if (tp->link_change) 7078c2ecf20Sopenharmony_ci (tp->link_change)(dev, csr5); 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci if (csr5 & SystemError) { 7108c2ecf20Sopenharmony_ci int error = (csr5 >> 23) & 7; 7118c2ecf20Sopenharmony_ci /* oops, we hit a PCI error. The code produced corresponds 7128c2ecf20Sopenharmony_ci * to the reason: 7138c2ecf20Sopenharmony_ci * 0 - parity error 7148c2ecf20Sopenharmony_ci * 1 - master abort 7158c2ecf20Sopenharmony_ci * 2 - target abort 7168c2ecf20Sopenharmony_ci * Note that on parity error, we should do a software reset 7178c2ecf20Sopenharmony_ci * of the chip to get it back into a sane state (according 7188c2ecf20Sopenharmony_ci * to the 21142/3 docs that is). 7198c2ecf20Sopenharmony_ci * -- rmk 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_ci dev_err(&dev->dev, 7228c2ecf20Sopenharmony_ci "(%lu) System Error occurred (%d)\n", 7238c2ecf20Sopenharmony_ci tp->nir, error); 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci /* Clear all error sources, included undocumented ones! */ 7268c2ecf20Sopenharmony_ci iowrite32(0x0800f7ba, ioaddr + CSR5); 7278c2ecf20Sopenharmony_ci oi++; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci if (csr5 & TimerInt) { 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (tulip_debug > 2) 7328c2ecf20Sopenharmony_ci dev_err(&dev->dev, 7338c2ecf20Sopenharmony_ci "Re-enabling interrupts, %08x\n", 7348c2ecf20Sopenharmony_ci csr5); 7358c2ecf20Sopenharmony_ci iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); 7368c2ecf20Sopenharmony_ci tp->ttimer = 0; 7378c2ecf20Sopenharmony_ci oi++; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci if (tx > maxtx || rx > maxrx || oi > maxoi) { 7408c2ecf20Sopenharmony_ci if (tulip_debug > 1) 7418c2ecf20Sopenharmony_ci dev_warn(&dev->dev, "Too much work during an interrupt, csr5=0x%08x. (%lu) (%d,%d,%d)\n", 7428c2ecf20Sopenharmony_ci csr5, tp->nir, tx, rx, oi); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* Acknowledge all interrupt sources. */ 7458c2ecf20Sopenharmony_ci iowrite32(0x8001ffff, ioaddr + CSR5); 7468c2ecf20Sopenharmony_ci if (tp->flags & HAS_INTR_MITIGATION) { 7478c2ecf20Sopenharmony_ci /* Josip Loncaric at ICASE did extensive experimentation 7488c2ecf20Sopenharmony_ci to develop a good interrupt mitigation setting.*/ 7498c2ecf20Sopenharmony_ci iowrite32(0x8b240000, ioaddr + CSR11); 7508c2ecf20Sopenharmony_ci } else if (tp->chip_id == LC82C168) { 7518c2ecf20Sopenharmony_ci /* the LC82C168 doesn't have a hw timer.*/ 7528c2ecf20Sopenharmony_ci iowrite32(0x00, ioaddr + CSR7); 7538c2ecf20Sopenharmony_ci mod_timer(&tp->timer, RUN_AT(HZ/50)); 7548c2ecf20Sopenharmony_ci } else { 7558c2ecf20Sopenharmony_ci /* Mask all interrupting sources, set timer to 7568c2ecf20Sopenharmony_ci re-enable. */ 7578c2ecf20Sopenharmony_ci iowrite32(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); 7588c2ecf20Sopenharmony_ci iowrite32(0x0012, ioaddr + CSR11); 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci break; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci work_count--; 7648c2ecf20Sopenharmony_ci if (work_count == 0) 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci csr5 = ioread32(ioaddr + CSR5); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci#ifdef CONFIG_TULIP_NAPI 7708c2ecf20Sopenharmony_ci if (rxd) 7718c2ecf20Sopenharmony_ci csr5 &= ~RxPollInt; 7728c2ecf20Sopenharmony_ci } while ((csr5 & (TxNoBuf | 7738c2ecf20Sopenharmony_ci TxDied | 7748c2ecf20Sopenharmony_ci TxIntr | 7758c2ecf20Sopenharmony_ci TimerInt | 7768c2ecf20Sopenharmony_ci /* Abnormal intr. */ 7778c2ecf20Sopenharmony_ci RxDied | 7788c2ecf20Sopenharmony_ci TxFIFOUnderflow | 7798c2ecf20Sopenharmony_ci TxJabber | 7808c2ecf20Sopenharmony_ci TPLnkFail | 7818c2ecf20Sopenharmony_ci SystemError )) != 0); 7828c2ecf20Sopenharmony_ci#else 7838c2ecf20Sopenharmony_ci } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci tulip_refill_rx(dev); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci /* check if the card is in suspend mode */ 7888c2ecf20Sopenharmony_ci entry = tp->dirty_rx % RX_RING_SIZE; 7898c2ecf20Sopenharmony_ci if (tp->rx_buffers[entry].skb == NULL) { 7908c2ecf20Sopenharmony_ci if (tulip_debug > 1) 7918c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 7928c2ecf20Sopenharmony_ci "in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", 7938c2ecf20Sopenharmony_ci tp->nir, tp->cur_rx, tp->ttimer, rx); 7948c2ecf20Sopenharmony_ci if (tp->chip_id == LC82C168) { 7958c2ecf20Sopenharmony_ci iowrite32(0x00, ioaddr + CSR7); 7968c2ecf20Sopenharmony_ci mod_timer(&tp->timer, RUN_AT(HZ/50)); 7978c2ecf20Sopenharmony_ci } else { 7988c2ecf20Sopenharmony_ci if (tp->ttimer == 0 || (ioread32(ioaddr + CSR11) & 0xffff) == 0) { 7998c2ecf20Sopenharmony_ci if (tulip_debug > 1) 8008c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 8018c2ecf20Sopenharmony_ci "in rx suspend mode: (%lu) set timer\n", 8028c2ecf20Sopenharmony_ci tp->nir); 8038c2ecf20Sopenharmony_ci iowrite32(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, 8048c2ecf20Sopenharmony_ci ioaddr + CSR7); 8058c2ecf20Sopenharmony_ci iowrite32(TimerInt, ioaddr + CSR5); 8068c2ecf20Sopenharmony_ci iowrite32(12, ioaddr + CSR11); 8078c2ecf20Sopenharmony_ci tp->ttimer = 1; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci#endif /* CONFIG_TULIP_NAPI */ 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if ((missed = ioread32(ioaddr + CSR8) & 0x1ffff)) { 8148c2ecf20Sopenharmony_ci dev->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (tulip_debug > 4) 8188c2ecf20Sopenharmony_ci netdev_dbg(dev, "exiting interrupt, csr5=%#04x\n", 8198c2ecf20Sopenharmony_ci ioread32(ioaddr + CSR5)); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8228c2ecf20Sopenharmony_ci} 823