📄 farsync.c
字号:
};MODULE_DEVICE_TABLE ( pci, fst_pci_dev_id );/* Card control functions * ====================== *//* Place the processor in reset state * * Used to be a simple write to card control space but a glitch in the latest * AMD Am186CH processor means that we now have to do it by asserting and de- * asserting the PLX chip PCI Adapter Software Reset. Bit 30 in CNTRL register * at offset 0x50. */static inline voidfst_cpureset ( struct fst_card_info *card ){ unsigned int regval; regval = inl ( card->pci_conf + 0x50 ); outl ( regval | 0x40000000, card->pci_conf + 0x50 ); outl ( regval & ~0x40000000, card->pci_conf + 0x50 );}/* Release the processor from reset */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_to_dev ( port ))) { dbg ( DBG_INTR,"DCD active\n"); netif_carrier_on ( port_to_dev ( port )); } } else { if ( netif_carrier_ok ( port_to_dev ( port ))) { dbg ( DBG_INTR,"DCD lost\n"); netif_carrier_off ( port_to_dev ( port )); } }}/* 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->hdlc.stats.rx_errors++; /* Update error stats and discard buffer */ if ( dmabits & RX_OFLO ) { port->hdlc.stats.rx_fifo_errors++; } if ( dmabits & RX_CRC ) { port->hdlc.stats.rx_crc_errors++; } if ( dmabits & RX_FRAM ) { port->hdlc.stats.rx_frame_errors++; } if ( dmabits == ( RX_STP | RX_ENP )) { port->hdlc.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->hdlc.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->hdlc.stats.rx_packets++; port->hdlc.stats.rx_bytes += len; /* Push upstream */ skb->mac.raw = skb->data; skb->dev = hdlc_to_dev ( &port->hdlc ); skb->protocol = htons ( ETH_P_HDLC ); netif_rx ( skb ); port_to_dev ( port )->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 ) 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->hdlc.stats.tx_errors++; port->hdlc.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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -