📄 farsync.c
字号:
static inline voidfst_cpurelease ( struct fst_card_info *card ){ (void) readb ( card->ctlmem );}/* Clear the cards interrupt flag */static inline voidfst_clear_intr ( struct fst_card_info *card ){ /* Poke the appropriate PLX chip register (same as enabling interrupts) */ outw ( 0x0543, card->pci_conf + 0x4C );}/* Disable card interrupts */static inline voidfst_disable_intr ( struct fst_card_info *card ){ outw ( 0x0000, card->pci_conf + 0x4C );}/* Issue a Mailbox command for a port. * Note we issue them on a fire and forget basis, not expecting to see an * error and not waiting for completion. */static voidfst_issue_cmd ( struct fst_port_info *port, unsigned short cmd ){ struct fst_card_info *card; unsigned short mbval; unsigned long flags; int safety; card = port->card; spin_lock_irqsave ( &card->card_lock, flags ); mbval = FST_RDW ( card, portMailbox[port->index][0]); safety = 0; /* Wait for any previous command to complete */ while ( mbval > NAK ) { spin_unlock_irqrestore ( &card->card_lock, flags ); schedule_timeout ( 1 ); spin_lock_irqsave ( &card->card_lock, flags ); if ( ++safety > 1000 ) { printk_err ("Mailbox safety timeout\n"); break; } mbval = FST_RDW ( card, portMailbox[port->index][0]); } if ( safety > 0 ) { dbg ( DBG_CMD,"Mailbox clear after %d jiffies\n", safety ); } if ( mbval == NAK ) { dbg ( DBG_CMD,"issue_cmd: previous command was NAK'd\n"); } FST_WRW ( card, portMailbox[port->index][0], cmd ); if ( cmd == ABORTTX || cmd == STARTPORT ) { port->txpos = 0; port->txipos = 0; port->txcnt = 0; } spin_unlock_irqrestore ( &card->card_lock, flags );}/* Port output signals control */static inline voidfst_op_raise ( struct fst_port_info *port, unsigned int outputs ){ outputs |= FST_RDL ( port->card, v24OpSts[port->index]); FST_WRL ( port->card, v24OpSts[port->index], outputs ); if ( port->run ) fst_issue_cmd ( port, SETV24O );}static inline voidfst_op_lower ( struct fst_port_info *port, unsigned int outputs ){ outputs = ~outputs & FST_RDL ( port->card, v24OpSts[port->index]); FST_WRL ( port->card, v24OpSts[port->index], outputs ); if ( port->run ) fst_issue_cmd ( port, SETV24O );}/* * Setup port Rx buffers */static voidfst_rx_config ( struct fst_port_info *port ){ int i; int pi; unsigned int offset; unsigned long flags; struct fst_card_info *card; pi = port->index; card = port->card; spin_lock_irqsave ( &card->card_lock, flags ); for ( i = 0 ; i < NUM_RX_BUFFER ; i++ ) { offset = BUF_OFFSET ( rxBuffer[pi][i][0]); FST_WRW ( card, rxDescrRing[pi][i].ladr, (u16) offset ); FST_WRB ( card, rxDescrRing[pi][i].hadr, (u8)( offset >> 16 )); FST_WRW ( card, rxDescrRing[pi][i].bcnt, cnv_bcnt ( LEN_RX_BUFFER )); FST_WRW ( card, rxDescrRing[pi][i].mcnt, 0 ); FST_WRB ( card, rxDescrRing[pi][i].bits, DMA_OWN ); } port->rxpos = 0; spin_unlock_irqrestore ( &card->card_lock, flags );}/* * Setup port Tx buffers */static voidfst_tx_config ( struct fst_port_info *port ){ int i; int pi; unsigned int offset; unsigned long flags; struct fst_card_info *card; pi = port->index; card = port->card; spin_lock_irqsave ( &card->card_lock, flags ); for ( i = 0 ; i < NUM_TX_BUFFER ; i++ ) { offset = BUF_OFFSET ( txBuffer[pi][i][0]); FST_WRW ( card, txDescrRing[pi][i].ladr, (u16) offset ); FST_WRB ( card, txDescrRing[pi][i].hadr, (u8)( offset >> 16 )); FST_WRW ( card, txDescrRing[pi][i].bcnt, 0 ); FST_WRB ( card, txDescrRing[pi][i].bits, 0 ); } port->txpos = 0; port->txipos = 0; port->txcnt = 0; spin_unlock_irqrestore ( &card->card_lock, flags );}/* Control signal change interrupt event */static voidfst_intr_ctlchg ( struct fst_card_info *card, struct fst_port_info *port ){ int signals; signals = FST_RDL ( card, v24DebouncedSts[port->index]); if ( signals & (( port->hwif == X21 ) ? IPSTS_INDICATE : IPSTS_DCD )) { if ( ! netif_carrier_ok ( port->dev )) { dbg ( DBG_INTR,"DCD active\n"); /* Poke sPPP to renegotiate */ if ( port->proto == FST_HDLC || port->proto == FST_PPP ) { sppp_reopen ( port->dev ); } netif_carrier_on ( port->dev ); } } else { if ( netif_carrier_ok ( port->dev )) { dbg ( DBG_INTR,"DCD lost\n"); netif_carrier_off ( port->dev ); } }}/* Rx complete interrupt */static voidfst_intr_rx ( struct fst_card_info *card, struct fst_port_info *port ){ unsigned char dmabits; int pi; int rxp; unsigned short len; struct sk_buff *skb; int i; /* Check we have a buffer to process */ pi = port->index; rxp = port->rxpos; dmabits = FST_RDB ( card, rxDescrRing[pi][rxp].bits ); if ( dmabits & DMA_OWN ) { dbg ( DBG_RX | DBG_INTR,"intr_rx: No buffer port %d pos %d\n", pi, rxp ); return; } /* Get buffer length */ len = FST_RDW ( card, rxDescrRing[pi][rxp].mcnt ); /* Discard the CRC */ len -= 2; /* Check buffer length and for other errors. We insist on one packet * in one buffer. This simplifies things greatly and since we've * allocated 8K it shouldn't be a real world limitation */ dbg ( DBG_RX,"intr_rx: %d,%d: flags %x len %d\n", pi, rxp, dmabits, len ); if ( dmabits != ( RX_STP | RX_ENP ) || len > LEN_RX_BUFFER - 2 ) { port->stats.rx_errors++; /* Update error stats and discard buffer */ if ( dmabits & RX_OFLO ) { port->stats.rx_fifo_errors++; } if ( dmabits & RX_CRC ) { port->stats.rx_crc_errors++; } if ( dmabits & RX_FRAM ) { port->stats.rx_frame_errors++; } if ( dmabits == ( RX_STP | RX_ENP )) { port->stats.rx_length_errors++; } /* Discard buffer descriptors until we see the end of packet * marker */ i = 0; while (( dmabits & ( DMA_OWN | RX_ENP )) == 0 ) { FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN ); if ( ++rxp >= NUM_RX_BUFFER ) rxp = 0; if ( ++i > NUM_RX_BUFFER ) { dbg ( DBG_ASS,"intr_rx: Discarding more bufs" " than we have\n"); break; } dmabits = FST_RDB ( card, rxDescrRing[pi][rxp].bits ); } /* Discard the terminal buffer */ if ( ! ( dmabits & DMA_OWN )) { FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN ); if ( ++rxp >= NUM_RX_BUFFER ) rxp = 0; } port->rxpos = rxp; return; } /* Allocate SKB */ if (( skb = dev_alloc_skb ( len )) == NULL ) { dbg ( DBG_RX,"intr_rx: can't allocate buffer\n"); port->stats.rx_dropped++; /* Return descriptor to card */ FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN ); if ( ++rxp >= NUM_RX_BUFFER ) port->rxpos = 0; else port->rxpos = rxp; return; } memcpy_fromio ( skb_put ( skb, len ), card->mem + BUF_OFFSET ( rxBuffer[pi][rxp][0]), len ); /* Reset buffer descriptor */ FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN ); if ( ++rxp >= NUM_RX_BUFFER ) port->rxpos = 0; else port->rxpos = rxp; /* Update stats */ port->stats.rx_packets++; port->stats.rx_bytes += len; /* Push upstream */ if ( port->proto == FST_HDLC || port->proto == FST_PPP ) { /* Mark for further processing by sPPP module */ skb->protocol = htons ( ETH_P_WAN_PPP ); } else { /* DEC customer specific protocol (since nothing defined for * marking raw data), at least one other driver uses this value * for this purpose. */ skb->protocol = htons ( ETH_P_CUST ); skb->pkt_type = PACKET_HOST; } skb->mac.raw = skb->data; skb->dev = port->dev; netif_rx ( skb ); port->dev->last_rx = jiffies;}/* * The interrupt service routine * Dev_id is our fst_card_info pointer */static voidfst_intr ( int irq, void *dev_id, struct pt_regs *regs ){ struct fst_card_info *card; struct fst_port_info *port; int rdidx; /* Event buffer indices */ int wridx; int event; /* Actual event for processing */ int pi; if (( card = dev_id ) == NULL ) { dbg ( DBG_INTR,"intr: spurious %d\n", irq ); return; } dbg ( DBG_INTR,"intr: %d %p\n", irq, card ); spin_lock ( &card->card_lock ); /* Clear and reprime the interrupt source */ fst_clear_intr ( card ); /* Set the software acknowledge */ FST_WRB ( card, interruptHandshake, 0xEE ); /* Drain the event queue */ rdidx = FST_RDB ( card, interruptEvent.rdindex ); wridx = FST_RDB ( card, interruptEvent.wrindex ); while ( rdidx != wridx ) { event = FST_RDB ( card, interruptEvent.evntbuff[rdidx]); port = &card->ports[event & 0x03]; dbg ( DBG_INTR,"intr: %x\n", event ); switch ( event ) { case CTLA_CHG: case CTLB_CHG: case CTLC_CHG: case CTLD_CHG: if ( port->run && port->dev != NULL ) fst_intr_ctlchg ( card, port ); break; case ABTA_SENT: case ABTB_SENT: case ABTC_SENT: case ABTD_SENT: dbg ( DBG_TX,"Abort complete port %d\n", event & 0x03 ); break; case TXA_UNDF: case TXB_UNDF: case TXC_UNDF: case TXD_UNDF: /* Difficult to see how we'd get this given that we * always load up the entire packet for DMA. */ dbg ( DBG_TX,"Tx underflow port %d\n", event & 0x03 ); port->stats.tx_errors++; port->stats.tx_fifo_errors++; break; case INIT_CPLT: dbg ( DBG_INIT,"Card init OK intr\n"); break; case INIT_FAIL: dbg ( DBG_INIT,"Card init FAILED intr\n"); card->state = FST_IFAILED; break; default: printk_err ("intr: unknown card event code. ignored\n"); break; } /* Bump and wrap the index */ if ( ++rdidx >= MAX_CIRBUFF ) rdidx = 0; } FST_WRB ( card, interruptEvent.rdindex, rdidx ); for ( pi = 0, port = card->ports ; pi < card->nports ; pi++, port++ ) { if ( port->dev == NULL || ! port->run ) continue; /* Check for rx completions */ while ( ! ( FST_RDB ( card, rxDescrRing[pi][port->rxpos].bits ) & DMA_OWN )) { fst_intr_rx ( card, port ); } /* Check for Tx completions */ while ( port->txcnt > 0 && ! ( FST_RDB ( card, txDescrRing[pi][port->txipos].bits ) & DMA_OWN )) { --port->txcnt; if ( ++port->txipos >= NUM_TX_BUFFER ) port->txipos = 0; netif_wake_queue ( port->dev ); } } spin_unlock ( &card->card_lock );}/* Check that the shared memory configuration is one that we can handle
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -