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