📄 interrupt.c
字号:
dev->name, status); tp->stats.rx_errors++; /* end of a packet.*/ if (status & 0x0890) tp->stats.rx_length_errors++; if (status & 0x0004) tp->stats.rx_frame_errors++; if (status & 0x0002) tp->stats.rx_crc_errors++; if (status & 0x0001) tp->stats.rx_fifo_errors++; } } else { /* Omit the four octet CRC from the length. */ short pkt_len = ((status >> 16) & 0x7ff) - 4; struct sk_buff *skb;#ifndef final_version if (pkt_len > 1518) { printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", dev->name, pkt_len, pkt_len); pkt_len = 1518; tp->stats.rx_length_errors++; }#endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ if (pkt_len < tulip_rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(tp->pdev, tp->rx_buffers[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE);#if ! defined(__alpha__) eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data, pkt_len, 0); skb_put(skb, pkt_len);#else memcpy(skb_put(skb, pkt_len), tp->rx_buffers[entry].skb->data, pkt_len);#endif pci_dma_sync_single_for_device(tp->pdev, tp->rx_buffers[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); } else { /* Pass up the skb already on the Rx ring. */ char *temp = skb_put(skb = tp->rx_buffers[entry].skb, pkt_len);#ifndef final_version if (tp->rx_buffers[entry].mapping != le32_to_cpu(tp->rx_ring[entry].buffer1)) { printk(KERN_ERR "%s: Internal fault: The skbuff addresses " "do not match in tulip_rx: %08x vs. %Lx %p / %p.\n", dev->name, le32_to_cpu(tp->rx_ring[entry].buffer1), (long long)tp->rx_buffers[entry].mapping, skb->head, temp); }#endif pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); tp->rx_buffers[entry].skb = NULL; tp->rx_buffers[entry].mapping = 0; } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; } received++; entry = (++tp->cur_rx) % RX_RING_SIZE; } return received;}#endif /* CONFIG_TULIP_NAPI */static inline unsigned int phy_interrupt (struct net_device *dev){#ifdef __hppa__ struct tulip_private *tp = netdev_priv(dev); int csr12 = ioread32(tp->base_addr + CSR12) & 0xff; if (csr12 != tp->csr12_shadow) { /* ack interrupt */ iowrite32(csr12 | 0x02, tp->base_addr + CSR12); tp->csr12_shadow = csr12; /* do link change stuff */ spin_lock(&tp->lock); tulip_check_duplex(dev); spin_unlock(&tp->lock); /* clear irq ack bit */ iowrite32(csr12 & ~0x02, tp->base_addr + CSR12); return 1; }#endif return 0;}/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ struct net_device *dev = (struct net_device *)dev_instance; struct tulip_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->base_addr; int csr5; int missed; int rx = 0; int tx = 0; int oi = 0; int maxrx = RX_RING_SIZE; int maxtx = TX_RING_SIZE; int maxoi = TX_RING_SIZE;#ifdef CONFIG_TULIP_NAPI int rxd = 0;#else int entry;#endif unsigned int work_count = tulip_max_interrupt_work; unsigned int handled = 0; /* Let's see whether the interrupt really is for us */ csr5 = ioread32(ioaddr + CSR5); if (tp->flags & HAS_PHY_IRQ) handled = phy_interrupt (dev); if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) return IRQ_RETVAL(handled); tp->nir++; do {#ifdef CONFIG_TULIP_NAPI if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { rxd++; /* Mask RX intrs and add the device to poll list. */ iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); netif_rx_schedule(dev); if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) break; } /* Acknowledge the interrupt sources we handle here ASAP the poll function does Rx and RxNoBuf acking */ iowrite32(csr5 & 0x0001ff3f, ioaddr + CSR5);#else /* Acknowledge all of the current interrupt sources ASAP. */ iowrite32(csr5 & 0x0001ffff, ioaddr + CSR5); if (csr5 & (RxIntr | RxNoBuf)) { rx += tulip_rx(dev); tulip_refill_rx(dev); }#endif /* CONFIG_TULIP_NAPI */ if (tulip_debug > 4) printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", dev->name, csr5, ioread32(ioaddr + CSR5)); if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { unsigned int dirty_tx; spin_lock(&tp->lock); for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; dirty_tx++) { int entry = dirty_tx % TX_RING_SIZE; int status = le32_to_cpu(tp->tx_ring[entry].status); if (status < 0) break; /* It still has not been Txed */ /* Check for Rx filter setup frames. */ if (tp->tx_buffers[entry].skb == NULL) { /* test because dummy frames not mapped */ if (tp->tx_buffers[entry].mapping) pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, sizeof(tp->setup_frame), PCI_DMA_TODEVICE); continue; } if (status & 0x8000) { /* There was an major error, log it. */#ifndef final_version if (tulip_debug > 1) printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", dev->name, status);#endif tp->stats.tx_errors++; if (status & 0x4104) tp->stats.tx_aborted_errors++; if (status & 0x0C00) tp->stats.tx_carrier_errors++; if (status & 0x0200) tp->stats.tx_window_errors++; if (status & 0x0002) tp->stats.tx_fifo_errors++; if ((status & 0x0080) && tp->full_duplex == 0) tp->stats.tx_heartbeat_errors++; } else { tp->stats.tx_bytes += tp->tx_buffers[entry].skb->len; tp->stats.collisions += (status >> 3) & 15; tp->stats.tx_packets++; } pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, tp->tx_buffers[entry].skb->len, PCI_DMA_TODEVICE); /* Free the original skb. */ dev_kfree_skb_irq(tp->tx_buffers[entry].skb); tp->tx_buffers[entry].skb = NULL; tp->tx_buffers[entry].mapping = 0; tx++; }#ifndef final_version if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d.\n", dev->name, dirty_tx, tp->cur_tx); dirty_tx += TX_RING_SIZE; }#endif if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) netif_wake_queue(dev); tp->dirty_tx = dirty_tx; if (csr5 & TxDied) { if (tulip_debug > 2) printk(KERN_WARNING "%s: The transmitter stopped." " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", dev->name, csr5, ioread32(ioaddr + CSR6), tp->csr6); tulip_restart_rxtx(tp); } spin_unlock(&tp->lock); } /* Log errors. */ if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ if (csr5 == 0xffffffff) break; if (csr5 & TxJabber) tp->stats.tx_errors++; if (csr5 & TxFIFOUnderflow) { if ((tp->csr6 & 0xC000) != 0xC000) tp->csr6 += 0x4000; /* Bump up the Tx threshold */ else tp->csr6 |= 0x00200000; /* Store-n-forward. */ /* Restart the transmit process. */ tulip_restart_rxtx(tp); iowrite32(0, ioaddr + CSR1); } if (csr5 & (RxDied | RxNoBuf)) { if (tp->flags & COMET_MAC_ADDR) { iowrite32(tp->mc_filter[0], ioaddr + 0xAC); iowrite32(tp->mc_filter[1], ioaddr + 0xB0); } } if (csr5 & RxDied) { /* Missed a Rx frame. */ tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff; tp->stats.rx_errors++; tulip_start_rxtx(tp); } /* * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this * call is ever done under the spinlock */ if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { if (tp->link_change) (tp->link_change)(dev, csr5); } if (csr5 & SytemError) { int error = (csr5 >> 23) & 7; /* oops, we hit a PCI error. The code produced corresponds * to the reason: * 0 - parity error * 1 - master abort * 2 - target abort * Note that on parity error, we should do a software reset * of the chip to get it back into a sane state (according * to the 21142/3 docs that is). * -- rmk */ printk(KERN_ERR "%s: (%lu) System Error occurred (%d)\n", dev->name, tp->nir, error); } /* Clear all error sources, included undocumented ones! */ iowrite32(0x0800f7ba, ioaddr + CSR5); oi++; } if (csr5 & TimerInt) { if (tulip_debug > 2) printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", dev->name, csr5); iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); tp->ttimer = 0; oi++; } if (tx > maxtx || rx > maxrx || oi > maxoi) { if (tulip_debug > 1) printk(KERN_WARNING "%s: Too much work during an interrupt, " "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi); /* Acknowledge all interrupt sources. */ iowrite32(0x8001ffff, ioaddr + CSR5); if (tp->flags & HAS_INTR_MITIGATION) { /* Josip Loncaric at ICASE did extensive experimentation to develop a good interrupt mitigation setting.*/ iowrite32(0x8b240000, ioaddr + CSR11); } else if (tp->chip_id == LC82C168) { /* the LC82C168 doesn't have a hw timer.*/ iowrite32(0x00, ioaddr + CSR7); mod_timer(&tp->timer, RUN_AT(HZ/50)); } else { /* Mask all interrupting sources, set timer to re-enable. */ iowrite32(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); iowrite32(0x0012, ioaddr + CSR11); } break; } work_count--; if (work_count == 0) break; csr5 = ioread32(ioaddr + CSR5);#ifdef CONFIG_TULIP_NAPI if (rxd) csr5 &= ~RxPollInt; } while ((csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt | /* Abnormal intr. */ RxDied | TxFIFOUnderflow | TxJabber | TPLnkFail | SytemError )) != 0);#else } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); tulip_refill_rx(dev); /* check if the card is in suspend mode */ entry = tp->dirty_rx % RX_RING_SIZE; if (tp->rx_buffers[entry].skb == NULL) { if (tulip_debug > 1) printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); if (tp->chip_id == LC82C168) { iowrite32(0x00, ioaddr + CSR7); mod_timer(&tp->timer, RUN_AT(HZ/50)); } else { if (tp->ttimer == 0 || (ioread32(ioaddr + CSR11) & 0xffff) == 0) { if (tulip_debug > 1) printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); iowrite32(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, ioaddr + CSR7); iowrite32(TimerInt, ioaddr + CSR5); iowrite32(12, ioaddr + CSR11); tp->ttimer = 1; } } }#endif /* CONFIG_TULIP_NAPI */ if ((missed = ioread32(ioaddr + CSR8) & 0x1ffff)) { tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; } if (tulip_debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", dev->name, ioread32(ioaddr + CSR5)); return IRQ_HANDLED;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -