📄 lmc_main.c
字号:
// dev->start = 0; LMC_XMITTER_BUSY(dev); sc->stats.tx_tbusy1++ ; /* stop interrupts */ /* Clear the interrupt mask */ LMC_CSR_WRITE (sc, csr_intr, 0x00000000); /* Stop Tx and Rx on the chip */ csr6 = LMC_CSR_READ (sc, csr_command); csr6 &= ~LMC_DEC_ST; /* Turn off the Transmission bit */ csr6 &= ~LMC_DEC_SR; /* Turn off the Receive bit */ LMC_CSR_WRITE (sc, csr_command, csr6); dev->flags &= ~IFF_RUNNING; sc->stats.rx_missed_errors += LMC_CSR_READ (sc, csr_missed_frames) & 0xffff; /* release the interrupt */ if(sc->got_irq == 1){ free_irq (dev->irq, dev); sc->got_irq = 0; } /* free skbuffs in the Rx queue */ for (i = 0; i < LMC_RXDESCS; i++) { struct sk_buff *skb = sc->lmc_rxq[i]; sc->lmc_rxq[i] = 0; sc->lmc_rxring[i].status = 0; sc->lmc_rxring[i].length = 0; sc->lmc_rxring[i].buffer1 = 0xDEADBEEF; if (skb != NULL) { LMC_SKB_FREE(skb, 1); LMC_DEV_KFREE_SKB (skb); } sc->lmc_rxq[i] = NULL; } for (i = 0; i < LMC_TXDESCS; i++) { if (sc->lmc_txq[i] != NULL) LMC_DEV_KFREE_SKB (sc->lmc_txq[i]); sc->lmc_txq[i] = NULL; } lmc_led_off (sc, LMC_MII16_LED_ALL); LMC_XMITTER_FREE(dev); sc->stats.tx_tbusy0++ ; lmc_trace(dev, "lmc_ifdown out"); MOD_DEC_USE_COUNT; return 0;}/* Interrupt handling routine. This will take an incoming packet, or clean * up after a trasmit. */static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/{ struct net_device *dev = (struct net_device *) dev_instance; lmc_softc_t *sc; u32 csr; int i; s32 stat; unsigned int badtx; u32 firstcsr; int max_work = LMC_RXDESCS; lmc_trace(dev, "lmc_interrupt in"); sc = dev->priv; spin_lock(&sc->lmc_lock); /* * Read the csr to find what interrupts we have (if any) */ csr = LMC_CSR_READ (sc, csr_status); /* * Make sure this is our interrupt */ if ( ! (csr & sc->lmc_intrmask)) { goto lmc_int_fail_out; } firstcsr = csr; /* always go through this loop at least once */ while (csr & sc->lmc_intrmask) { /* * Clear interrupt bits, we handle all case below */ LMC_CSR_WRITE (sc, csr_status, csr); /* * One of * - Transmit process timed out CSR5<1> * - Transmit jabber timeout CSR5<3> * - Transmit underflow CSR5<5> * - Transmit Receiver buffer unavailable CSR5<7> * - Receive process stopped CSR5<8> * - Receive watchdog timeout CSR5<9> * - Early transmit interrupt CSR5<10> * * Is this really right? Should we do a running reset for jabber? * (being a WAN card and all) */ if (csr & TULIP_STS_ABNRMLINTR){ lmc_running_reset (dev); break; } if (csr & TULIP_STS_RXINTR){ lmc_trace(dev, "rx interrupt"); lmc_rx (dev); } if (csr & (TULIP_STS_TXINTR | TULIP_STS_TXNOBUF | TULIP_STS_TXSTOPPED)) { int n_compl = 0 ; /* reset the transmit timeout detection flag -baz */ sc->stats.tx_NoCompleteCnt = 0; badtx = sc->lmc_taint_tx; i = badtx % LMC_TXDESCS; while ((badtx < sc->lmc_next_tx)) { stat = sc->lmc_txring[i].status; LMC_EVENT_LOG (LMC_EVENT_XMTINT, stat, sc->lmc_txring[i].length); /* * If bit 31 is 1 the tulip owns it break out of the loop */ if (stat & 0x80000000) break; n_compl++ ; /* i.e., have an empty slot in ring */ /* * If we have no skbuff or have cleared it * Already continue to the next buffer */ if (sc->lmc_txq[i] == NULL) continue; /* * Check the total error summary to look for any errors */ if (stat & 0x8000) { sc->stats.tx_errors++; if (stat & 0x4104) sc->stats.tx_aborted_errors++; if (stat & 0x0C00) sc->stats.tx_carrier_errors++; if (stat & 0x0200) sc->stats.tx_window_errors++; if (stat & 0x0002) sc->stats.tx_fifo_errors++; } else { #if LINUX_VERSION_CODE >= 0x20200 sc->stats.tx_bytes += sc->lmc_txring[i].length & 0x7ff;#endif sc->stats.tx_packets++; } // LMC_DEV_KFREE_SKB (sc->lmc_txq[i]); dev_kfree_skb_irq(sc->lmc_txq[i]); sc->lmc_txq[i] = 0; badtx++; i = badtx % LMC_TXDESCS; } if (sc->lmc_next_tx - badtx > LMC_TXDESCS) { printk ("%s: out of sync pointer\n", dev->name); badtx += LMC_TXDESCS; } LMC_EVENT_LOG(LMC_EVENT_TBUSY0, n_compl, 0); sc->lmc_txfull = 0; LMC_XMITTER_FREE(dev); sc->stats.tx_tbusy0++ ;#if LINUX_VERSION_CODE < 0x20363 mark_bh (NET_BH); /* Tell Linux to give me more packets */#endif#ifdef DEBUG sc->stats.dirtyTx = badtx; sc->stats.lmc_next_tx = sc->lmc_next_tx; sc->stats.lmc_txfull = sc->lmc_txfull;#if LINUX_VERSION_CODE < 0x20363 sc->stats.tbusy = dev->tbusy;#endif#endif sc->lmc_taint_tx = badtx; /* * Why was there a break here??? */ } /* end handle transmit interrupt */ if (csr & TULIP_STS_SYSERROR) { u32 error; printk (KERN_WARNING "%s: system bus error csr: %#8.8x\n", dev->name, csr); error = csr>>23 & 0x7; switch(error){ case 0x000: printk(KERN_WARNING "%s: Parity Fault (bad)\n", dev->name); break; case 0x001: printk(KERN_WARNING "%s: Master Abort (naughty)\n", dev->name); break; case 0x010: printk(KERN_WARNING "%s: Target Abort (not so naughty)\n", dev->name); break; default: printk(KERN_WARNING "%s: This bus error code was supposed to be reserved!\n", dev->name); } lmc_dec_reset (sc); lmc_reset (sc); LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); LMC_EVENT_LOG(LMC_EVENT_RESET2, lmc_mii_readreg (sc, 0, 16), lmc_mii_readreg (sc, 0, 17)); } if(max_work-- <= 0) break; /* * Get current csr status to make sure * we've cleared all interrupts */ csr = LMC_CSR_READ (sc, csr_status); } /* end interrupt loop */ LMC_EVENT_LOG(LMC_EVENT_INT, firstcsr, csr);lmc_int_fail_out: spin_unlock(&sc->lmc_lock); lmc_trace(dev, "lmc_interrupt out");}static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/{ lmc_softc_t *sc; u32 flag; int entry; int ret = 0; LMC_SPIN_FLAGS; lmc_trace(dev, "lmc_start_xmit in"); sc = dev->priv; spin_lock_irqsave(&sc->lmc_lock, flags); /* * If the transmitter is busy * this must be the 5 second polling * from the kernel which called us. * Poke the chip and try to get it running * */#if LINUX_VERSION_CODE < 0x20363 if(dev->tbusy != 0){ u32 csr6; printk("%s: Xmitter busy|\n", dev->name); sc->stats.tx_tbusy_calls++ ; if (jiffies - dev->trans_start < TX_TIMEOUT) { ret = 1; goto lmc_start_xmit_bug_out; } /* * Chip seems to have locked up * Reset it * This whips out all our decriptor * table and starts from scartch */ LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO, LMC_CSR_READ (sc, csr_status), sc->stats.tx_ProcTimeout); lmc_running_reset (dev); LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); LMC_EVENT_LOG(LMC_EVENT_RESET2, lmc_mii_readreg (sc, 0, 16), lmc_mii_readreg (sc, 0, 17)); /* restart the tx processes */ csr6 = LMC_CSR_READ (sc, csr_command); LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002); LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002); /* immediate transmit */ LMC_CSR_WRITE (sc, csr_txpoll, 0); sc->stats.tx_errors++; sc->stats.tx_ProcTimeout++; /* -baz */ dev->trans_start = jiffies; ret = 1; goto lmc_start_xmit_bug_out; }#endif /* normal path, tbusy known to be zero */ entry = sc->lmc_next_tx % LMC_TXDESCS; sc->lmc_txq[entry] = skb; sc->lmc_txring[entry].buffer1 = virt_to_bus (skb->data); LMC_CONSOLE_LOG("xmit", skb->data, skb->len);#ifndef GCOM /* If the queue is less than half full, don't interrupt */ if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS / 2) { /* Do not interrupt on completion of this packet */ flag = 0x60000000; LMC_XMITTER_FREE(dev); } else if (sc->lmc_next_tx - sc->lmc_taint_tx == LMC_TXDESCS / 2) { /* This generates an interrupt on completion of this packet */ flag = 0xe0000000; LMC_XMITTER_FREE(dev); } else if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS - 1) { /* Do not interrupt on completion of this packet */ flag = 0x60000000; LMC_XMITTER_FREE(dev); } else { /* This generates an interrupt on completion of this packet */ flag = 0xe0000000; sc->lmc_txfull = 1; LMC_XMITTER_BUSY(dev); }#else flag = LMC_TDES_INTERRUPT_ON_COMPLETION; if (sc->lmc_next_tx - sc->lmc_taint_tx >= LMC_TXDESCS - 1) { /* ring full, go busy */ sc->lmc_txfull = 1; LMC_XMITTER_BUSY(dev); sc->stats.tx_tbusy1++ ; LMC_EVENT_LOG(LMC_EVENT_TBUSY1, entry, 0); }#endif if (entry == LMC_TXDESCS - 1) /* last descriptor in ring */ flag |= LMC_TDES_END_OF_RING; /* flag as such for Tulip */ /* don't pad small packets either */ flag = sc->lmc_txring[entry].length = (skb->len) | flag | sc->TxDescriptControlInit; /* set the transmit timeout flag to be checked in * the watchdog timer handler. -baz */ sc->stats.tx_NoCompleteCnt++; sc->lmc_next_tx++; /* give ownership to the chip */ LMC_EVENT_LOG(LMC_EVENT_XMT, flag, entry); sc->lmc_txring[entry].status = 0x80000000; /* send now! */ LMC_CSR_WRITE (sc, csr_txpoll, 0); dev->trans_start = jiffies;#if LINUX_VERSION_CODE < 0x20363lmc_start_xmit_bug_out:#endif spin_unlock_irqrestore(&sc->lmc_lock, flags); lmc_trace(dev, "lmc_start_xmit_out"); return ret;}static int lmc_rx (struct net_device *dev) /*fold00*/{ lmc_softc_t *sc; int i; int rx_work_limit = LMC_RXDESCS; unsigned int next_rx; int rxIntLoopCnt; /* debug -baz */ int localLengthErrCnt = 0; long stat; struct sk_buff *skb, *nsb; u16 len; lmc_trace(dev, "lmc_rx in"); sc = dev->priv; lmc_led_on(sc, LMC_DS3_LED3); rxIntLoopCnt = 0; /* debug -baz */ i = sc->lmc_next_rx % LMC_RXDESCS; next_rx = sc->lmc_next_rx; while (((stat = sc->lmc_rxring[i].status) & LMC_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4) { rxIntLoopCnt++; /* debug -baz */ len = ((stat & LMC_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER); if ((stat & 0x0300) != 0x0300) { /* Check first segment and last segment */ if ((stat & 0x0000ffff) != 0x7fff) { /* Oversized frame */ sc->stats.rx_length_errors++; goto skip_packet; } } if(stat & 0x00000008){ /* Catch a dribbling bit error */ sc->stats.rx_errors++; sc->stats.rx_frame_errors++; goto skip_packet; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -