interrupt.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:17k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2. drivers/net/tulip/interrupt.c
  3. Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
  4. Copyright 2000,2001  The Linux Kernel Team
  5. Written/copyright 1994-2001 by Donald Becker.
  6. This software may be used and distributed according to the terms
  7. of the GNU General Public License, incorporated herein by reference.
  8. Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
  9. for more information on this driver, or visit the project
  10. Web page at http://sourceforge.net/projects/tulip/
  11. */
  12. #include "tulip.h"
  13. #include <linux/config.h>
  14. #include <linux/etherdevice.h>
  15. #include <linux/pci.h>
  16. int tulip_rx_copybreak;
  17. unsigned int tulip_max_interrupt_work;
  18. #ifdef CONFIG_NET_HW_FLOWCONTROL
  19. #define MIT_SIZE 15
  20. unsigned int mit_table[MIT_SIZE+1] =
  21. {
  22.         /*  CRS11 21143 hardware Mitigation Control Interrupt
  23.             We use only RX mitigation we other techniques for
  24.             TX intr. mitigation.
  25.            31    Cycle Size (timer control)
  26.            30:27 TX timer in 16 * Cycle size
  27.            26:24 TX No pkts before Int.
  28.            23:20 RX timer in Cycle size
  29.            19:17 RX No pkts before Int.
  30.            16       Continues Mode (CM)
  31.         */
  32.         0x0,             /* IM disabled */
  33.         0x80150000,      /* RX time = 1, RX pkts = 2, CM = 1 */
  34.         0x80150000,
  35.         0x80270000,
  36.         0x80370000,
  37.         0x80490000,
  38.         0x80590000,
  39.         0x80690000,
  40.         0x807B0000,
  41.         0x808B0000,
  42.         0x809D0000,
  43.         0x80AD0000,
  44.         0x80BD0000,
  45.         0x80CF0000,
  46.         0x80DF0000,
  47. //       0x80FF0000      /* RX time = 16, RX pkts = 7, CM = 1 */
  48.         0x80F10000      /* RX time = 16, RX pkts = 0, CM = 1 */
  49. };
  50. #endif
  51. int tulip_refill_rx(struct net_device *dev)
  52. {
  53. struct tulip_private *tp = (struct tulip_private *)dev->priv;
  54. int entry;
  55. int refilled = 0;
  56. /* Refill the Rx ring buffers. */
  57. for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
  58. entry = tp->dirty_rx % RX_RING_SIZE;
  59. if (tp->rx_buffers[entry].skb == NULL) {
  60. struct sk_buff *skb;
  61. dma_addr_t mapping;
  62. skb = tp->rx_buffers[entry].skb = dev_alloc_skb(PKT_BUF_SZ);
  63. if (skb == NULL)
  64. break;
  65. mapping = pci_map_single(tp->pdev, skb->tail, PKT_BUF_SZ,
  66.  PCI_DMA_FROMDEVICE);
  67. tp->rx_buffers[entry].mapping = mapping;
  68. skb->dev = dev; /* Mark as being used by this device. */
  69. tp->rx_ring[entry].buffer1 = cpu_to_le32(mapping);
  70. refilled++;
  71. }
  72. tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
  73. }
  74. if(tp->chip_id == LC82C168) {
  75. if(((inl(dev->base_addr + CSR5)>>17)&0x07) == 4) {
  76. /* Rx stopped due to out of buffers,
  77.  * restart it
  78.  */
  79. outl(0x01, dev->base_addr + CSR2);
  80. }
  81. }
  82. return refilled;
  83. }
  84. static int tulip_rx(struct net_device *dev)
  85. {
  86. struct tulip_private *tp = (struct tulip_private *)dev->priv;
  87. int entry = tp->cur_rx % RX_RING_SIZE;
  88. int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
  89. int received = 0;
  90. #ifdef CONFIG_NET_HW_FLOWCONTROL
  91.         int drop = 0, mit_sel = 0;
  92. /* that one buffer is needed for mit activation; or might be a
  93.    bug in the ring buffer code; check later -- JHS*/
  94.         if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--;
  95. #endif
  96. if (tulip_debug > 4)
  97. printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.n", entry,
  98.    tp->rx_ring[entry].status);
  99. /* If we own the next entry, it is a new packet. Send it up. */
  100. while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
  101. s32 status = le32_to_cpu(tp->rx_ring[entry].status);
  102. if (tulip_debug > 5)
  103. printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.n",
  104.    dev->name, entry, status);
  105. if (--rx_work_limit < 0)
  106. break;
  107. if ((status & 0x38008300) != 0x0300) {
  108. if ((status & 0x38000300) != 0x0300) {
  109. /* Ingore earlier buffers. */
  110. if ((status & 0xffff) != 0x7fff) {
  111. if (tulip_debug > 1)
  112. printk(KERN_WARNING "%s: Oversized Ethernet frame "
  113.    "spanned multiple buffers, status %8.8x!n",
  114.    dev->name, status);
  115. tp->stats.rx_length_errors++;
  116. }
  117. } else if (status & RxDescFatalErr) {
  118. /* There was a fatal error. */
  119. if (tulip_debug > 2)
  120. printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.n",
  121.    dev->name, status);
  122. tp->stats.rx_errors++; /* end of a packet.*/
  123. if (status & 0x0890) tp->stats.rx_length_errors++;
  124. if (status & 0x0004) tp->stats.rx_frame_errors++;
  125. if (status & 0x0002) tp->stats.rx_crc_errors++;
  126. if (status & 0x0001) tp->stats.rx_fifo_errors++;
  127. }
  128. } else {
  129. /* Omit the four octet CRC from the length. */
  130. short pkt_len = ((status >> 16) & 0x7ff) - 4;
  131. struct sk_buff *skb;
  132. #ifndef final_version
  133. if (pkt_len > 1518) {
  134. printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).n",
  135.    dev->name, pkt_len, pkt_len);
  136. pkt_len = 1518;
  137. tp->stats.rx_length_errors++;
  138. }
  139. #endif
  140. #ifdef CONFIG_NET_HW_FLOWCONTROL
  141.                         drop = atomic_read(&netdev_dropping);
  142.                         if (drop)
  143.                                 goto throttle;
  144. #endif
  145. /* Check if the packet is long enough to accept without copying
  146.    to a minimally-sized skbuff. */
  147. if (pkt_len < tulip_rx_copybreak
  148. && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
  149. skb->dev = dev;
  150. skb_reserve(skb, 2); /* 16 byte align the IP header */
  151. pci_dma_sync_single(tp->pdev,
  152.     tp->rx_buffers[entry].mapping,
  153.     pkt_len, PCI_DMA_FROMDEVICE);
  154. #if ! defined(__alpha__)
  155. eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail,
  156.  pkt_len, 0);
  157. skb_put(skb, pkt_len);
  158. #else
  159. memcpy(skb_put(skb, pkt_len),
  160.        tp->rx_buffers[entry].skb->tail,
  161.        pkt_len);
  162. #endif
  163. } else {  /* Pass up the skb already on the Rx ring. */
  164. char *temp = skb_put(skb = tp->rx_buffers[entry].skb,
  165.      pkt_len);
  166. #ifndef final_version
  167. if (tp->rx_buffers[entry].mapping !=
  168.     le32_to_cpu(tp->rx_ring[entry].buffer1)) {
  169. printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
  170.        "do not match in tulip_rx: %08x vs. %08x %p / %p.n",
  171.        dev->name,
  172.        le32_to_cpu(tp->rx_ring[entry].buffer1),
  173.        tp->rx_buffers[entry].mapping,
  174.        skb->head, temp);
  175. }
  176. #endif
  177. pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping,
  178.  PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
  179. tp->rx_buffers[entry].skb = NULL;
  180. tp->rx_buffers[entry].mapping = 0;
  181. }
  182. skb->protocol = eth_type_trans(skb, dev);
  183. #ifdef CONFIG_NET_HW_FLOWCONTROL
  184.                         mit_sel =
  185. #endif
  186. netif_rx(skb);
  187. #ifdef CONFIG_NET_HW_FLOWCONTROL
  188.                         switch (mit_sel) {
  189.                         case NET_RX_SUCCESS:
  190.                         case NET_RX_CN_LOW:
  191.                         case NET_RX_CN_MOD:
  192.                                 break;
  193.                         case NET_RX_CN_HIGH:
  194.                                 rx_work_limit -= NET_RX_CN_HIGH; /* additional*/
  195.                                 break;
  196.                         case NET_RX_DROP:
  197.                                 rx_work_limit = -1;
  198.                                 break;
  199.                         default:
  200.                                 printk("unknown feedback return code %dn", mit_sel);
  201.                                 break;
  202.                         }
  203.                         drop = atomic_read(&netdev_dropping);
  204.                         if (drop) {
  205. throttle:
  206.                                 rx_work_limit = -1;
  207.                                 mit_sel = NET_RX_DROP;
  208.                                 if (tp->fc_bit) {
  209.                                         long ioaddr = dev->base_addr;
  210.                                         /* disable Rx & RxNoBuf ints. */
  211.                                         outl(tulip_tbl[tp->chip_id].valid_intrs&RX_A_NBF_STOP, ioaddr + CSR7);
  212.                                         set_bit(tp->fc_bit, &netdev_fc_xoff);
  213.                                 }
  214.                         }
  215. #endif
  216. dev->last_rx = jiffies;
  217. tp->stats.rx_packets++;
  218. tp->stats.rx_bytes += pkt_len;
  219. }
  220. received++;
  221. entry = (++tp->cur_rx) % RX_RING_SIZE;
  222. }
  223. #ifdef CONFIG_NET_HW_FLOWCONTROL
  224.         /* We use this simplistic scheme for IM. It's proven by
  225.            real life installations. We can have IM enabled
  226.            continuesly but this would cause unnecessary latency.
  227.            Unfortunely we can't use all the NET_RX_* feedback here.
  228.            This would turn on IM for devices that is not contributing
  229.            to backlog congestion with unnecessary latency.
  230.            We monitor the the device RX-ring and have:
  231.            HW Interrupt Mitigation either ON or OFF.
  232.            ON:  More then 1 pkt received (per intr.) OR we are dropping
  233.            OFF: Only 1 pkt received
  234.            Note. We only use min and max (0, 15) settings from mit_table */
  235.         if( tp->flags &  HAS_INTR_MITIGATION) {
  236.                 if((received > 1 || mit_sel == NET_RX_DROP)
  237.                    && tp->mit_sel != 15 ) {
  238.                         tp->mit_sel = 15;
  239.                         tp->mit_change = 1; /* Force IM change */
  240.                 }
  241.                 if((received <= 1 && mit_sel != NET_RX_DROP) && tp->mit_sel != 0 ) {
  242.                         tp->mit_sel = 0;
  243.                         tp->mit_change = 1; /* Force IM change */
  244.                 }
  245.         }
  246.         return RX_RING_SIZE+1; /* maxrx+1 */
  247. #else
  248. return received;
  249. #endif
  250. }
  251. /* The interrupt handler does all of the Rx thread work and cleans up
  252.    after the Tx thread. */
  253. void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
  254. {
  255. struct net_device *dev = (struct net_device *)dev_instance;
  256. struct tulip_private *tp = (struct tulip_private *)dev->priv;
  257. long ioaddr = dev->base_addr;
  258. int csr5;
  259. int entry;
  260. int missed;
  261. int rx = 0;
  262. int tx = 0;
  263. int oi = 0;
  264. int maxrx = RX_RING_SIZE;
  265. int maxtx = TX_RING_SIZE;
  266. int maxoi = TX_RING_SIZE;
  267. unsigned int work_count = tulip_max_interrupt_work;
  268. /* Let's see whether the interrupt really is for us */
  269. csr5 = inl(ioaddr + CSR5);
  270. if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
  271. return;
  272. tp->nir++;
  273. do {
  274. /* Acknowledge all of the current interrupt sources ASAP. */
  275. outl(csr5 & 0x0001ffff, ioaddr + CSR5);
  276. if (tulip_debug > 4)
  277. printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.n",
  278.    dev->name, csr5, inl(dev->base_addr + CSR5));
  279. if (csr5 & (RxIntr | RxNoBuf)) {
  280. #ifdef CONFIG_NET_HW_FLOWCONTROL
  281.                         if ((!tp->fc_bit) ||
  282.     (!test_bit(tp->fc_bit, &netdev_fc_xoff)))
  283. #endif
  284. rx += tulip_rx(dev);
  285. tulip_refill_rx(dev);
  286. }
  287. if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
  288. unsigned int dirty_tx;
  289. spin_lock(&tp->lock);
  290. for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
  291.  dirty_tx++) {
  292. int entry = dirty_tx % TX_RING_SIZE;
  293. int status = le32_to_cpu(tp->tx_ring[entry].status);
  294. if (status < 0)
  295. break; /* It still has not been Txed */
  296. /* Check for Rx filter setup frames. */
  297. if (tp->tx_buffers[entry].skb == NULL) {
  298. /* test because dummy frames not mapped */
  299. if (tp->tx_buffers[entry].mapping)
  300. pci_unmap_single(tp->pdev,
  301.  tp->tx_buffers[entry].mapping,
  302.  sizeof(tp->setup_frame),
  303.  PCI_DMA_TODEVICE);
  304. continue;
  305. }
  306. if (status & 0x8000) {
  307. /* There was an major error, log it. */
  308. #ifndef final_version
  309. if (tulip_debug > 1)
  310. printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.n",
  311.    dev->name, status);
  312. #endif
  313. tp->stats.tx_errors++;
  314. if (status & 0x4104) tp->stats.tx_aborted_errors++;
  315. if (status & 0x0C00) tp->stats.tx_carrier_errors++;
  316. if (status & 0x0200) tp->stats.tx_window_errors++;
  317. if (status & 0x0002) tp->stats.tx_fifo_errors++;
  318. if ((status & 0x0080) && tp->full_duplex == 0)
  319. tp->stats.tx_heartbeat_errors++;
  320. } else {
  321. tp->stats.tx_bytes +=
  322. tp->tx_buffers[entry].skb->len;
  323. tp->stats.collisions += (status >> 3) & 15;
  324. tp->stats.tx_packets++;
  325. }
  326. pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping,
  327.  tp->tx_buffers[entry].skb->len,
  328.  PCI_DMA_TODEVICE);
  329. /* Free the original skb. */
  330. dev_kfree_skb_irq(tp->tx_buffers[entry].skb);
  331. tp->tx_buffers[entry].skb = NULL;
  332. tp->tx_buffers[entry].mapping = 0;
  333. tx++;
  334. }
  335. #ifndef final_version
  336. if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
  337. printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d.n",
  338.    dev->name, dirty_tx, tp->cur_tx);
  339. dirty_tx += TX_RING_SIZE;
  340. }
  341. #endif
  342. if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2)
  343. netif_wake_queue(dev);
  344. tp->dirty_tx = dirty_tx;
  345. if (csr5 & TxDied) {
  346. if (tulip_debug > 2)
  347. printk(KERN_WARNING "%s: The transmitter stopped."
  348.    "  CSR5 is %x, CSR6 %x, new CSR6 %x.n",
  349.    dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
  350. tulip_restart_rxtx(tp);
  351. }
  352. spin_unlock(&tp->lock);
  353. }
  354. /* Log errors. */
  355. if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
  356. if (csr5 == 0xffffffff)
  357. break;
  358. if (csr5 & TxJabber) tp->stats.tx_errors++;
  359. if (csr5 & TxFIFOUnderflow) {
  360. if ((tp->csr6 & 0xC000) != 0xC000)
  361. tp->csr6 += 0x4000; /* Bump up the Tx threshold */
  362. else
  363. tp->csr6 |= 0x00200000;  /* Store-n-forward. */
  364. /* Restart the transmit process. */
  365. tulip_restart_rxtx(tp);
  366. outl(0, ioaddr + CSR1);
  367. }
  368. if (csr5 & (RxDied | RxNoBuf)) {
  369. if (tp->flags & COMET_MAC_ADDR) {
  370. outl(tp->mc_filter[0], ioaddr + 0xAC);
  371. outl(tp->mc_filter[1], ioaddr + 0xB0);
  372. }
  373. }
  374. if (csr5 & RxDied) { /* Missed a Rx frame. */
  375.                                 tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
  376. #ifdef CONFIG_NET_HW_FLOWCONTROL
  377. if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) {
  378. tp->stats.rx_errors++;
  379. tulip_start_rxtx(tp);
  380. }
  381. #else
  382. tp->stats.rx_errors++;
  383. tulip_start_rxtx(tp);
  384. #endif
  385. }
  386. /*
  387.  * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this
  388.  * call is ever done under the spinlock
  389.  */
  390. if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
  391. if (tp->link_change)
  392. (tp->link_change)(dev, csr5);
  393. }
  394. if (csr5 & SytemError) {
  395. int error = (csr5 >> 23) & 7;
  396. /* oops, we hit a PCI error.  The code produced corresponds
  397.  * to the reason:
  398.  *  0 - parity error
  399.  *  1 - master abort
  400.  *  2 - target abort
  401.  * Note that on parity error, we should do a software reset
  402.  * of the chip to get it back into a sane state (according
  403.  * to the 21142/3 docs that is).
  404.  *   -- rmk
  405.  */
  406. printk(KERN_ERR "%s: (%lu) System Error occured (%d)n",
  407. dev->name, tp->nir, error);
  408. }
  409. /* Clear all error sources, included undocumented ones! */
  410. outl(0x0800f7ba, ioaddr + CSR5);
  411. oi++;
  412. }
  413. if (csr5 & TimerInt) {
  414. if (tulip_debug > 2)
  415. printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.n",
  416.    dev->name, csr5);
  417. #ifdef CONFIG_NET_HW_FLOWCONTROL
  418.                         if (tp->fc_bit && (test_bit(tp->fc_bit, &netdev_fc_xoff)))
  419.                           if (net_ratelimit()) printk("BUG!! enabling interupt when FC off (timerintr.) n");
  420. #endif
  421. outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
  422. tp->ttimer = 0;
  423. oi++;
  424. }
  425. if (tx > maxtx || rx > maxrx || oi > maxoi) {
  426. if (tulip_debug > 1)
  427. printk(KERN_WARNING "%s: Too much work during an interrupt, "
  428.    "csr5=0x%8.8x. (%lu) (%d,%d,%d)n", dev->name, csr5, tp->nir, tx, rx, oi);
  429.                        /* Acknowledge all interrupt sources. */
  430.                         outl(0x8001ffff, ioaddr + CSR5);
  431.                         if (tp->flags & HAS_INTR_MITIGATION) {
  432. #ifdef CONFIG_NET_HW_FLOWCONTROL
  433.                                 if(tp->mit_change) {
  434.                                         outl(mit_table[tp->mit_sel], ioaddr + CSR11);
  435.                                         tp->mit_change = 0;
  436.                                 }
  437. #else
  438.                      /* Josip Loncaric at ICASE did extensive experimentation
  439. to develop a good interrupt mitigation setting.*/
  440.                                 outl(0x8b240000, ioaddr + CSR11);
  441. #endif
  442.                         } else if (tp->chip_id == LC82C168) {
  443. /* the LC82C168 doesn't have a hw timer.*/
  444. outl(0x00, ioaddr + CSR7);
  445. mod_timer(&tp->timer, RUN_AT(HZ/50));
  446. } else {
  447.                           /* Mask all interrupting sources, set timer to
  448. re-enable. */
  449. #ifndef CONFIG_NET_HW_FLOWCONTROL
  450.                                 outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7);
  451.                                 outl(0x0012, ioaddr + CSR11);
  452. #endif
  453.                         }
  454. break;
  455. }
  456. work_count--;
  457. if (work_count == 0)
  458. break;
  459. csr5 = inl(ioaddr + CSR5);
  460. } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0);
  461. tulip_refill_rx(dev);
  462. /* check if the card is in suspend mode */
  463. entry = tp->dirty_rx % RX_RING_SIZE;
  464. if (tp->rx_buffers[entry].skb == NULL) {
  465. if (tulip_debug > 1)
  466. printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend moden", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
  467. if (tp->chip_id == LC82C168) {
  468. outl(0x00, ioaddr + CSR7);
  469. mod_timer(&tp->timer, RUN_AT(HZ/50));
  470. } else {
  471. if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
  472. if (tulip_debug > 1)
  473. printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timern", dev->name, tp->nir);
  474. outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
  475. ioaddr + CSR7);
  476. outl(TimerInt, ioaddr + CSR5);
  477. outl(12, ioaddr + CSR11);
  478. tp->ttimer = 1;
  479. }
  480. }
  481. }
  482. if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
  483. tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
  484. }
  485. if (tulip_debug > 4)
  486. printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.n",
  487.    dev->name, inl(ioaddr + CSR5));
  488. }