⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 farsync.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 *      physical offsets so we have to convert. The only saving grace is that *      this should all collapse back to a simple indirection eventually. */#define WIN_OFFSET(X)   ((long)&(((struct fst_shared *)SMC_BASE)->X))#define FST_RDB(C,E)    readb ((C)->mem + WIN_OFFSET(E))#define FST_RDW(C,E)    readw ((C)->mem + WIN_OFFSET(E))#define FST_RDL(C,E)    readl ((C)->mem + WIN_OFFSET(E))#define FST_WRB(C,E,B)  writeb ((B), (C)->mem + WIN_OFFSET(E))#define FST_WRW(C,E,W)  writew ((W), (C)->mem + WIN_OFFSET(E))#define FST_WRL(C,E,L)  writel ((L), (C)->mem + WIN_OFFSET(E))/* *      Debug support */#if FST_DEBUGstatic int fst_debug_mask = { FST_DEBUG };/* Most common debug activity is to print something if the corresponding bit * is set in the debug mask. Note: this uses a non-ANSI extension in GCC to * support variable numbers of macro parameters. The inverted if prevents us * eating someone else's else clause. */#define dbg(F,fmt,A...) if ( ! ( fst_debug_mask & (F))) \                                ; \                        else \                                printk ( KERN_DEBUG FST_NAME ": " fmt, ## A )#else#define dbg(X...)		/* NOP */#endif/*      Printing short cuts */#define printk_err(fmt,A...)    printk ( KERN_ERR     FST_NAME ": " fmt, ## A )#define printk_warn(fmt,A...)   printk ( KERN_WARNING FST_NAME ": " fmt, ## A )#define printk_info(fmt,A...)   printk ( KERN_INFO    FST_NAME ": " fmt, ## A )/* *      PCI ID lookup table */static struct pci_device_id fst_pci_dev_id[] __devinitdata = {	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2P, PCI_ANY_ID, 	 PCI_ANY_ID, 0, 0, FST_TYPE_T2P},	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T4P, PCI_ANY_ID, 	 PCI_ANY_ID, 0, 0, FST_TYPE_T4P},	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T1U, PCI_ANY_ID, 	 PCI_ANY_ID, 0, 0, FST_TYPE_T1U},	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2U, PCI_ANY_ID, 	 PCI_ANY_ID, 0, 0, FST_TYPE_T2U},	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T4U, PCI_ANY_ID, 	 PCI_ANY_ID, 0, 0, FST_TYPE_T4U},	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_TE1, PCI_ANY_ID, 	 PCI_ANY_ID, 0, 0, FST_TYPE_TE1},	{PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_TE1C, PCI_ANY_ID, 	 PCI_ANY_ID, 0, 0, FST_TYPE_TE1},	{0,}			/* End */};MODULE_DEVICE_TABLE(pci, fst_pci_dev_id);/* *      Device Driver Work Queues * *      So that we don't spend too much time processing events in the  *      Interrupt Service routine, we will declare a work queue per Card  *      and make the ISR schedule a task in the queue for later execution. *      In the 2.4 Kernel we used to use the immediate queue for BH's *      Now that they are gone, tasklets seem to be much better than work  *      queues. */static void do_bottom_half_tx(struct fst_card_info *card);static void do_bottom_half_rx(struct fst_card_info *card);static void fst_process_tx_work_q(unsigned long work_q);static void fst_process_int_work_q(unsigned long work_q);DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0);DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0);struct fst_card_info *fst_card_array[FST_MAX_CARDS];spinlock_t fst_work_q_lock;u64 fst_work_txq;u64 fst_work_intq;static voidfst_q_work_item(u64 * queue, int card_index){	unsigned long flags;	u64 mask;	/*	 * Grab the queue exclusively	 */	spin_lock_irqsave(&fst_work_q_lock, flags);	/*	 * Making an entry in the queue is simply a matter of setting	 * a bit for the card indicating that there is work to do in the	 * bottom half for the card.  Note the limitation of 64 cards.	 * That ought to be enough	 */	mask = 1 << card_index;	*queue |= mask;	spin_unlock_irqrestore(&fst_work_q_lock, flags);}static voidfst_process_tx_work_q(unsigned long /*void **/work_q){	unsigned long flags;	u64 work_txq;	int i;	/*	 * Grab the queue exclusively	 */	dbg(DBG_TX, "fst_process_tx_work_q\n");	spin_lock_irqsave(&fst_work_q_lock, flags);	work_txq = fst_work_txq;	fst_work_txq = 0;	spin_unlock_irqrestore(&fst_work_q_lock, flags);	/*	 * Call the bottom half for each card with work waiting	 */	for (i = 0; i < FST_MAX_CARDS; i++) {		if (work_txq & 0x01) {			if (fst_card_array[i] != NULL) {				dbg(DBG_TX, "Calling tx bh for card %d\n", i);				do_bottom_half_tx(fst_card_array[i]);			}		}		work_txq = work_txq >> 1;	}}static voidfst_process_int_work_q(unsigned long /*void **/work_q){	unsigned long flags;	u64 work_intq;	int i;	/*	 * Grab the queue exclusively	 */	dbg(DBG_INTR, "fst_process_int_work_q\n");	spin_lock_irqsave(&fst_work_q_lock, flags);	work_intq = fst_work_intq;	fst_work_intq = 0;	spin_unlock_irqrestore(&fst_work_q_lock, flags);	/*	 * Call the bottom half for each card with work waiting	 */	for (i = 0; i < FST_MAX_CARDS; i++) {		if (work_intq & 0x01) {			if (fst_card_array[i] != NULL) {				dbg(DBG_INTR,				    "Calling rx & tx bh for card %d\n", i);				do_bottom_half_rx(fst_card_array[i]);				do_bottom_half_tx(fst_card_array[i]);			}		}		work_intq = work_intq >> 1;	}}/*      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 9052_CNTRL.  Note the updates for the TXU. */static inline voidfst_cpureset(struct fst_card_info *card){	unsigned char interrupt_line_register;	unsigned long j = jiffies + 1;	unsigned int regval;	if (card->family == FST_FAMILY_TXU) {		if (pci_read_config_byte		    (card->device, PCI_INTERRUPT_LINE, &interrupt_line_register)) {			dbg(DBG_ASS,			    "Error in reading interrupt line register\n");		}		/*		 * Assert PLX software reset and Am186 hardware reset		 * and then deassert the PLX software reset but 186 still in reset		 */		outw(0x440f, card->pci_conf + CNTRL_9054 + 2);		outw(0x040f, card->pci_conf + CNTRL_9054 + 2);		/*		 * We are delaying here to allow the 9054 to reset itself		 */		j = jiffies + 1;		while (jiffies < j)			/* Do nothing */ ;		outw(0x240f, card->pci_conf + CNTRL_9054 + 2);		/*		 * We are delaying here to allow the 9054 to reload its eeprom		 */		j = jiffies + 1;		while (jiffies < j)			/* Do nothing */ ;		outw(0x040f, card->pci_conf + CNTRL_9054 + 2);		if (pci_write_config_byte		    (card->device, PCI_INTERRUPT_LINE, interrupt_line_register)) {			dbg(DBG_ASS,			    "Error in writing interrupt line register\n");		}	} else {		regval = inl(card->pci_conf + CNTRL_9052);		outl(regval | 0x40000000, card->pci_conf + CNTRL_9052);		outl(regval & ~0x40000000, card->pci_conf + CNTRL_9052);	}}/*      Release the processor from reset */static inline voidfst_cpurelease(struct fst_card_info *card){	if (card->family == FST_FAMILY_TXU) {		/*		 * Force posted writes to complete		 */		(void) readb(card->mem);		/*		 * Release LRESET DO = 1		 * Then release Local Hold, DO = 1		 */		outw(0x040e, card->pci_conf + CNTRL_9054 + 2);		outw(0x040f, card->pci_conf + CNTRL_9054 + 2);	} else {		(void) readb(card->ctlmem);	}}/*      Clear the cards interrupt flag */static inline voidfst_clear_intr(struct fst_card_info *card){	if (card->family == FST_FAMILY_TXU) {		(void) readb(card->ctlmem);	} else {		/* Poke the appropriate PLX chip register (same as enabling interrupts)		 */		outw(0x0543, card->pci_conf + INTCSR_9052);	}}/*      Enable card interrupts */static inline voidfst_enable_intr(struct fst_card_info *card){	if (card->family == FST_FAMILY_TXU) {		outl(0x0f0c0900, card->pci_conf + INTCSR_9054);	} else {		outw(0x0543, card->pci_conf + INTCSR_9052);	}}/*      Disable card interrupts */static inline voidfst_disable_intr(struct fst_card_info *card){	if (card->family == FST_FAMILY_TXU) {		outl(0x00000000, card->pci_conf + INTCSR_9054);	} else {		outw(0x0000, card->pci_conf + INTCSR_9052);	}}/*      Process the result of trying to pass a recieved frame up the stack */static voidfst_process_rx_status(int rx_status, char *name){	switch (rx_status) {	case NET_RX_SUCCESS:		{			/*			 * Nothing to do here			 */			break;		}	case NET_RX_CN_LOW:		{			dbg(DBG_ASS, "%s: Receive Low Congestion\n", name);			break;		}	case NET_RX_CN_MOD:		{			dbg(DBG_ASS, "%s: Receive Moderate Congestion\n", name);			break;		}	case NET_RX_CN_HIGH:		{			dbg(DBG_ASS, "%s: Receive High Congestion\n", name);			break;		}	case NET_RX_DROP:		{			dbg(DBG_ASS, "%s: Received packet dropped\n", name);			break;		}	}}/*      Initilaise DMA for PLX 9054 */static inline voidfst_init_dma(struct fst_card_info *card){	/*	 * This is only required for the PLX 9054	 */	if (card->family == FST_FAMILY_TXU) {	        pci_set_master(card->device);		outl(0x00020441, card->pci_conf + DMAMODE0);		outl(0x00020441, card->pci_conf + DMAMODE1);		outl(0x0, card->pci_conf + DMATHR);	}}/*      Tx dma complete interrupt */static voidfst_tx_dma_complete(struct fst_card_info *card, struct fst_port_info *port,		    int len, int txpos){	struct net_device *dev = port_to_dev(port);	struct net_device_stats *stats = hdlc_stats(dev);	/*	 * Everything is now set, just tell the card to go	 */	dbg(DBG_TX, "fst_tx_dma_complete\n");	FST_WRB(card, txDescrRing[port->index][txpos].bits,		DMA_OWN | TX_STP | TX_ENP);	stats->tx_packets++;	stats->tx_bytes += len;	dev->trans_start = jiffies;}/*      Rx dma complete interrupt */static voidfst_rx_dma_complete(struct fst_card_info *card, struct fst_port_info *port,		    int len, struct sk_buff *skb, int rxp){	struct net_device *dev = port_to_dev(port);	struct net_device_stats *stats = hdlc_stats(dev);	int pi;	int rx_status;	dbg(DBG_TX, "fst_rx_dma_complete\n");	pi = port->index;	memcpy(skb_put(skb, len), card->rx_dma_handle_host, len);	/* Reset buffer descriptor */	FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);	/* Update stats */	stats->rx_packets++;	stats->rx_bytes += len;	/* Push upstream */	dbg(DBG_RX, "Pushing the frame up the stack\n");	skb->mac.raw = skb->data;	skb->dev = dev;	if (port->mode == FST_RAW) {		/*		 * Mark it for our own raw sockets interface		 */		skb->protocol = htons(ETH_P_CUST);		skb->pkt_type = PACKET_HOST;	} else {		skb->protocol = hdlc_type_trans(skb, skb->dev);	}	rx_status = netif_rx(skb);	fst_process_rx_status(rx_status, port_to_dev(port)->name);	if (rx_status == NET_RX_DROP)		stats->rx_dropped++;	dev->last_rx = jiffies;}/* *      Receive a frame through the DMA */static inline voidfst_rx_dma(struct fst_card_info *card, unsigned char *skb,	   unsigned char *mem, int len){	/*	 * This routine will setup the DMA and start it	 */	dbg(DBG_RX, "In fst_rx_dma %p %p %d\n", skb, mem, len);	if (card->dmarx_in_progress) {		dbg(DBG_ASS, "In fst_rx_dma while dma in progress\n");	}	outl((unsigned long) skb, card->pci_conf + DMAPADR0);	/* Copy to here */	outl((unsigned long) mem, card->pci_conf + DMALADR0);	/* from here */	outl(len, card->pci_conf + DMASIZ0);	/* for this length */	outl(0x00000000c, card->pci_conf + DMADPR0);	/* In this direction */	/*	 * We use the dmarx_in_progress flag to flag the channel as busy	 */	card->dmarx_in_progress = 1;	outb(0x03, card->pci_conf + DMACSR0);	/* Start the transfer */}/* *      Send a frame through the DMA */static inline voidfst_tx_dma(struct fst_card_info *card, unsigned char *skb,	   unsigned char *mem, int len){	/*	 * This routine will setup the DMA and start it.	 */	dbg(DBG_TX, "In fst_tx_dma %p %p %d\n", skb, mem, len);	if (card->dmatx_in_progress) {		dbg(DBG_ASS, "In fst_tx_dma while dma in progress\n");	}	outl((unsigned long) skb, card->pci_conf + DMAPADR1);	/* Copy from here */	outl((unsigned long) mem, card->pci_conf + DMALADR1);	/* to here */	outl(len, card->pci_conf + DMASIZ1);	/* for this length */	outl(0x000000004, card->pci_conf + DMADPR1);	/* In this direction */	/*	 * We use the dmatx_in_progress to flag the channel as busy	 */	card->dmatx_in_progress = 1;	outb(0x03, card->pci_conf + DMACSR1);	/* Start the transfer */}/*      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) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -