📄 pc300_drv.c
字号:
cpc_writeb(card->hw.scabase + DSR_TX(ch), DSR_DE); if (card->hw.type == PC300_TE) { cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) | (CPLD_REG2_FALC_LED1 << (2 * ch))); } CPC_UNLOCK(card, flags); dev_kfree_skb(skb); return 0;}void cpc_net_rx(hdlc_device * hdlc){ struct net_device *dev = hdlc_to_dev(hdlc); pc300dev_t *d = (pc300dev_t *) dev->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; struct net_device_stats *stats = &d->hdlc->stats; int ch = chan->channel;#ifdef PC300_DEBUG_RX int i;#endif int rxb; struct sk_buff *skb; while (1) { if ((rxb = dma_get_rx_frame_size(card, ch)) == -1) return; if (!netif_carrier_ok(dev)) { /* DCD must be OFF: drop packet */ printk("%s : DCD is OFF - drop %d rx bytes\n", dev->name, rxb); skb = NULL; } else { if (rxb > (dev->mtu + 40)) { /* add headers */ printk("%s : MTU exceeded %d\n", dev->name, rxb); skb = NULL; } else { skb = dev_alloc_skb(rxb); if (skb == NULL) { printk("%s: Memory squeeze!!\n", dev->name); return; } skb->dev = dev; } } if (((rxb = dma_buf_read(card, ch, skb)) <= 0) || (skb == NULL)) {#ifdef PC300_DEBUG_RX printk("%s: rxb = %x\n", dev->name, rxb);#endif if ((skb == NULL) && (rxb > 0)) { /* rxb > dev->mtu */ stats->rx_errors++; stats->rx_length_errors++; continue; } if (rxb < 0) { /* Invalid frame */ rxb = -rxb; if (rxb & DST_OVR) { stats->rx_errors++; stats->rx_fifo_errors++; } if (rxb & DST_CRC) { stats->rx_errors++; stats->rx_crc_errors++; } if (rxb & (DST_RBIT | DST_SHRT | DST_ABT)) { stats->rx_errors++; stats->rx_frame_errors++; } } if (skb) { dev_kfree_skb_irq(skb); } continue; } stats->rx_bytes += rxb;#ifdef PC300_DEBUG_RX printk("%s R:", dev->name); for (i = 0; i < skb->len; i++) printk(" %02x", *(skb->data + i)); printk("\n");#endif if (d->trace_on) { cpc_trace(dev, skb, 'R'); } stats->rx_packets++; skb->mac.raw = skb->data; skb->protocol = hdlc_type_trans(skb, dev); netif_rx(skb); }}/************************************//*** PC300 Interrupt Routines ***//************************************/static void sca_tx_intr(pc300dev_t *dev){ pc300ch_t *chan = (pc300ch_t *)dev->chan; pc300_t *card = (pc300_t *)chan->card; int ch = chan->channel; volatile pcsca_bd_t * ptdescr; struct net_device_stats *stats = &dev->hdlc->stats; /* Clean up descriptors from previous transmission */ ptdescr = (pcsca_bd_t *)(card->hw.rambase + TX_BD_ADDR(ch,chan->tx_first_bd)); while ((cpc_readl(card->hw.scabase + DTX_REG(CDAL,ch)) != TX_BD_ADDR(ch,chan->tx_first_bd)) && (cpc_readb(&ptdescr->status) & DST_OSB)) { stats->tx_packets++; stats->tx_bytes += cpc_readw(&ptdescr->len); cpc_writeb(&ptdescr->status, DST_OSB); cpc_writew(&ptdescr->len, 0); chan->nfree_tx_bd++; chan->tx_first_bd = (chan->tx_first_bd + 1) & (N_DMA_TX_BUF - 1); ptdescr = (pcsca_bd_t *)(card->hw.rambase + TX_BD_ADDR(ch,chan->tx_first_bd)); }#ifdef CONFIG_PC300_MLPPP if (chan->conf.proto == PC300_PROTO_MLPPP) { cpc_tty_trigger_poll(dev); } else {#endif /* Tell the upper layer we are ready to transmit more packets */ netif_wake_queue((struct net_device*)dev->hdlc);#ifdef CONFIG_PC300_MLPPP }#endif}static void sca_intr(pc300_t * card){ uclong scabase = card->hw.scabase; volatile uclong status; int ch; int intr_count = 0; unsigned char dsr_rx; while ((status = cpc_readl(scabase + ISR0)) != 0) { for (ch = 0; ch < card->hw.nchan; ch++) { pc300ch_t *chan = &card->chan[ch]; pc300dev_t *d = &chan->d; hdlc_device *hdlc = d->hdlc; struct net_device *dev = hdlc_to_dev(hdlc); spin_lock(&card->card_lock); /**** Reception ****/ if (status & IR0_DRX((IR0_DMIA | IR0_DMIB), ch)) { ucchar drx_stat = cpc_readb(scabase + DSR_RX(ch)); /* Clear RX interrupts */ cpc_writeb(scabase + DSR_RX(ch), drx_stat | DSR_DWE);#ifdef PC300_DEBUG_INTR printk ("sca_intr: RX intr chan[%d] (st=0x%08lx, dsr=0x%02x)\n", ch, status, drx_stat);#endif if (status & IR0_DRX(IR0_DMIA, ch)) { if (drx_stat & DSR_BOF) {#ifdef CONFIG_PC300_MLPPP if (chan->conf.proto == PC300_PROTO_MLPPP) { /* verify if driver is TTY */ if ((cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) { rx_dma_stop(card, ch); } cpc_tty_receive(d); rx_dma_start(card, ch); } else #endif { if ((cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) { rx_dma_stop(card, ch); } cpc_net_rx(hdlc); /* Discard invalid frames */ hdlc->stats.rx_errors++; hdlc->stats.rx_over_errors++; chan->rx_first_bd = 0; chan->rx_last_bd = N_DMA_RX_BUF - 1; rx_dma_start(card, ch); } } } if (status & IR0_DRX(IR0_DMIB, ch)) { if (drx_stat & DSR_EOM) { if (card->hw.type == PC300_TE) { cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, cpc_readb (card->hw.falcbase + card->hw.cpld_reg2) | (CPLD_REG2_FALC_LED1 << (2 * ch))); }#ifdef CONFIG_PC300_MLPPP if (chan->conf.proto == PC300_PROTO_MLPPP) { /* verify if driver is TTY */ cpc_tty_receive(d); } else { cpc_net_rx(hdlc); }#else cpc_net_rx(hdlc);#endif if (card->hw.type == PC300_TE) { cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, cpc_readb (card->hw.falcbase + card->hw.cpld_reg2) & ~ (CPLD_REG2_FALC_LED1 << (2 * ch))); } } } if (!(dsr_rx = cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {#ifdef PC300_DEBUG_INTR printk("%s: RX intr chan[%d] (st=0x%08lx, dsr=0x%02x, dsr2=0x%02x)\n", dev->name, ch, status, drx_stat, dsr_rx);#endif cpc_writeb(scabase + DSR_RX(ch), (dsr_rx | DSR_DE) & 0xfe); } } /**** Transmission ****/ if (status & IR0_DTX((IR0_EFT | IR0_DMIA | IR0_DMIB), ch)) { ucchar dtx_stat = cpc_readb(scabase + DSR_TX(ch)); /* Clear TX interrupts */ cpc_writeb(scabase + DSR_TX(ch), dtx_stat | DSR_DWE);#ifdef PC300_DEBUG_INTR printk ("sca_intr: TX intr chan[%d] (st=0x%08lx, dsr=0x%02x)\n", ch, status, dtx_stat);#endif if (status & IR0_DTX(IR0_EFT, ch)) { if (dtx_stat & DSR_UDRF) { if (cpc_readb (scabase + M_REG(TBN, ch)) != 0) { cpc_writeb(scabase + M_REG(CMD,ch), CMD_TX_BUF_CLR); } if (card->hw.type == PC300_TE) { cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, cpc_readb (card->hw.falcbase + card->hw.cpld_reg2) & ~ (CPLD_REG2_FALC_LED1 << (2 * ch))); } hdlc->stats.tx_errors++; hdlc->stats.tx_fifo_errors++; sca_tx_intr(d); } } if (status & IR0_DTX(IR0_DMIA, ch)) { if (dtx_stat & DSR_BOF) { } } if (status & IR0_DTX(IR0_DMIB, ch)) { if (dtx_stat & DSR_EOM) { if (card->hw.type == PC300_TE) { cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, cpc_readb (card->hw.falcbase + card->hw.cpld_reg2) & ~ (CPLD_REG2_FALC_LED1 << (2 * ch))); } sca_tx_intr(d); } } } /**** MSCI ****/ if (status & IR0_M(IR0_RXINTA, ch)) { ucchar st1 = cpc_readb(scabase + M_REG(ST1, ch)); /* Clear MSCI interrupts */ cpc_writeb(scabase + M_REG(ST1, ch), st1);#ifdef PC300_DEBUG_INTR printk("sca_intr: MSCI intr chan[%d] (st=0x%08lx, st1=0x%02x)\n", ch, status, st1);#endif if (st1 & ST1_CDCD) { /* DCD changed */ if (cpc_readb(scabase + M_REG(ST3, ch)) & ST3_DCD) { printk ("%s: DCD is OFF. Going administrative down.\n", dev->name);#ifdef CONFIG_PC300_MLPPP if (chan->conf.proto != PC300_PROTO_MLPPP) { netif_carrier_off(dev); }#else netif_carrier_off(dev);#endif card->chan[ch].d.line_off++; } else { /* DCD = 1 */ printk ("%s: DCD is ON. Going administrative up.\n", dev->name);#ifdef CONFIG_PC300_MLPPP if (chan->conf.proto != PC300_PROTO_MLPPP) /* verify if driver is not TTY */#endif netif_carrier_on(dev); card->chan[ch].d.line_on++; } } } spin_unlock(&card->card_lock); } if (++intr_count == 10) /* Too much work at this board. Force exit */ break; }}static void falc_t1_loop_detection(pc300_t * card, int ch, ucchar frs1){ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; uclong falcbase = card->hw.falcbase; if (((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_XPRBS) == 0) && !pfalc->loop_gen) { if (frs1 & FRS1_LLBDD) { // A Line Loop Back Deactivation signal detected if (pfalc->loop_active) { falc_remote_loop(card, ch, 0); } } else { if ((frs1 & FRS1_LLBAD) && ((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_EPRM) == 0)) { // A Line Loop Back Activation signal detected if (!pfalc->loop_active) { falc_remote_loop(card, ch, 1); } } } }}static void falc_e1_loop_detection(pc300_t * card, int ch, ucchar rsp){ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; uclong falcbase = card->hw.falcbase; if (((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_XPRBS) == 0) && !pfalc->loop_gen) { if (rsp & RSP_LLBDD) { // A Line Loop Back Deactivation signal detected if (pfalc->loop_active) { falc_remote_loop(card, ch, 0); } } else { if ((rsp & RSP_LLBAD) && ((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_EPRM) == 0)) { // A Line Loop Back Activation signal detected if (!pfalc->loop_active) { falc_remote_loop(card, ch, 1); } } } }}static void falc_t1_intr(pc300_t * card, int ch){ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; uclong falcbase = card->hw.falcbase; ucchar isr0, isr3, gis; ucchar dummy; while ((gis = cpc_readb(falcbase + F_REG(GIS, ch))) != 0) { if (gis & GIS_ISR0) { isr0 = cpc_readb(falcbase + F_REG(FISR0, ch)); if (isr0 & FISR0_PDEN) { /* Read the bit to clear the situation */ if (cpc_readb(falcbase + F_REG(FRS1, ch)) & FRS1_PDEN) { pfalc->pden++; } } } if (gis & GIS_ISR1) { dummy = cpc_readb(falcbase + F_REG(FISR1, ch)); } if (gis & GIS_ISR2) { dummy = cpc_readb(falcbase + F_REG(FISR2, ch)); } if (gis & GIS_ISR3) { isr3 = cpc_readb(falcbase + F_REG(FISR3, ch)); if (isr3 & FISR3_SEC) { pfalc->sec++; falc_update_stats(card, ch); falc_check_status(card, ch, cpc_readb(falcbase + F_REG(FRS0, ch))); } if (isr3 & FISR3_ES) { pfalc->es++; } if (isr3 & FISR3_LLBSC) { falc_t1_loop_detection(card, ch, cpc_readb(falcbase + F_REG(FRS1, ch))); } } }}static void falc_e1_intr(pc300_t * card, int ch){ pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; falc_t *pfalc = (falc_t *) & chan->falc; uclong falcbase = ca
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -