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

📄 tms380tr.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  tms380tr.c: A network driver library for Texas Instruments TMS380-based *              Token Ring Adapters. * *  Originally sktr.c: Written 1997 by Christoph Goos * *  A fine result of the Linux Systems Network Architecture Project. *  http://www.linux-sna.org * *  This software may be used and distributed according to the terms *  of the GNU General Public License, incorporated herein by reference. * *  The following modules are currently available for card support: *	- tmspci (Generic PCI card support) *	- abyss (Madge PCI support) *      - tmsisa (SysKonnect TR4/16 ISA) * *  Sources: *  	- The hardware related parts of this driver are take from *  	  the SysKonnect Token Ring driver for Windows NT. *  	- I used the IBM Token Ring driver 'ibmtr.c' as a base for this *  	  driver, as well as the 'skeleton.c' driver by Donald Becker. *  	- Also various other drivers in the linux source tree were taken *  	  as samples for some tasks. *      - TI TMS380 Second-Generation Token Ring User's Guide *  	- TI datasheets for respective chips *  	- David Hein at Texas Instruments  *  	- Various Madge employees * *  Maintainer(s): *    JS	Jay Schulist		jschlst@samba.org *    CG	Christoph Goos		cgoos@syskonnect.de *    AF	Adam Fritzler		mid@auk.cx *    MLP       Mike Phillips           phillim@amtrak.com *    JF	Jochen Friedrich	jochen@scram.de *      *  Modification History: *	29-Aug-97	CG	Created *	04-Apr-98	CG	Fixed problems caused by tok_timer_check *	10-Apr-98	CG	Fixed lockups at cable disconnection *	27-May-98	JS	Formated to Linux Kernel Format *	31-May-98	JS	Hacked in PCI support *	16-Jun-98	JS	Modulized for multiple cards with one driver *	   Sep-99	AF	Renamed to tms380tr (supports more than SK's) *      23-Sep-99	AF      Added Compaq and Thomas-Conrad PCI support *				Fixed a bug causing double copies on PCI *				Fixed for new multicast stuff (2.2/2.3) *	25-Sep-99	AF	Uped TPL_NUM from 3 to 9 *				Removed extraneous 'No free TPL' *	22-Dec-99	AF	Added Madge PCI Mk2 support and generalized *				parts of the initilization procedure. *	30-Dec-99	AF	Turned tms380tr into a library ala 8390. *				Madge support is provided in the abyss module *				Generic PCI support is in the tmspci module. *	30-Nov-00	JF	Updated PCI code to support IO MMU via *				pci_map_static(). Alpha uses this MMU for ISA *				as well. *      14-Jan-01	JF	Fix DMA on ifdown/ifup sequences. Some  *      			cleanup. *	13-Jan-02	JF	Add spinlock to fix race condition. *	09-Nov-02	JF	Fixed printks to not SPAM the console during *				normal operation. *	30-Dec-02	JF	Removed incorrect __init from  *				tms380tr_init_card. *	22-Jul-05	JF	Converted to dma-mapping. *      			 *  To do: *    1. Multi/Broadcast packet handling (this may have fixed itself) *    2. Write a sktrisa module that includes the old ISA support (done) *    3. Allow modules to load their own microcode *    4. Speed up the BUD process -- freezing the kernel for 3+sec is *         quite unacceptable. *    5. Still a few remaining stalls when the cable is unplugged. */#ifdef MODULEstatic const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, Adam Fritzler\n";#endif#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/time.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/dma-mapping.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/trdevice.h>#include <linux/firmware.h>#include <linux/bitops.h>#include <asm/system.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/irq.h>#include <asm/uaccess.h>#include "tms380tr.h"		/* Our Stuff *//* Use 0 for production, 1 for verification, 2 for debug, and * 3 for very verbose debug. */#ifndef TMS380TR_DEBUG#define TMS380TR_DEBUG 0#endifstatic unsigned int tms380tr_debug = TMS380TR_DEBUG;/* Index to functions, as function prototypes. * Alphabetical by function name. *//* "A" *//* "B" */static int      tms380tr_bringup_diags(struct net_device *dev);/* "C" */static void	tms380tr_cancel_tx_queue(struct net_local* tp);static int 	tms380tr_chipset_init(struct net_device *dev);static void 	tms380tr_chk_irq(struct net_device *dev);static void 	tms380tr_chk_outstanding_cmds(struct net_device *dev);static void 	tms380tr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr);static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqType);int	 	tms380tr_close(struct net_device *dev);static void 	tms380tr_cmd_status_irq(struct net_device *dev);/* "D" */static void 	tms380tr_disable_interrupts(struct net_device *dev);#if TMS380TR_DEBUG > 0static void 	tms380tr_dump(unsigned char *Data, int length);#endif/* "E" */static void 	tms380tr_enable_interrupts(struct net_device *dev);static void 	tms380tr_exec_cmd(struct net_device *dev, unsigned short Command);static void 	tms380tr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue);/* "F" *//* "G" */static struct net_device_stats *tms380tr_get_stats(struct net_device *dev);/* "H" */static int 	tms380tr_hardware_send_packet(struct sk_buff *skb,			struct net_device *dev);/* "I" */static int 	tms380tr_init_adapter(struct net_device *dev);static void 	tms380tr_init_ipb(struct net_local *tp);static void 	tms380tr_init_net_local(struct net_device *dev);static void 	tms380tr_init_opb(struct net_device *dev);/* "M" *//* "O" */int		tms380tr_open(struct net_device *dev);static void	tms380tr_open_adapter(struct net_device *dev);/* "P" *//* "R" */static void 	tms380tr_rcv_status_irq(struct net_device *dev);static int 	tms380tr_read_ptr(struct net_device *dev);static void 	tms380tr_read_ram(struct net_device *dev, unsigned char *Data,			unsigned short Address, int Length);static int 	tms380tr_reset_adapter(struct net_device *dev);static void 	tms380tr_reset_interrupt(struct net_device *dev);static void 	tms380tr_ring_status_irq(struct net_device *dev);/* "S" */static int 	tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev);static void 	tms380tr_set_multicast_list(struct net_device *dev);static int	tms380tr_set_mac_address(struct net_device *dev, void *addr);/* "T" */static void 	tms380tr_timer_chk(unsigned long data);static void 	tms380tr_timer_end_wait(unsigned long data);static void 	tms380tr_tx_status_irq(struct net_device *dev);/* "U" */static void 	tms380tr_update_rcv_stats(struct net_local *tp,			unsigned char DataPtr[], unsigned int Length);/* "W" */void	 	tms380tr_wait(unsigned long time);static void 	tms380tr_write_rpl_status(RPL *rpl, unsigned int Status);static void 	tms380tr_write_tpl_status(TPL *tpl, unsigned int Status);#define SIFREADB(reg) (((struct net_local *)dev->priv)->sifreadb(dev, reg))#define SIFWRITEB(val, reg) (((struct net_local *)dev->priv)->sifwriteb(dev, val, reg))#define SIFREADW(reg) (((struct net_local *)dev->priv)->sifreadw(dev, reg))#define SIFWRITEW(val, reg) (((struct net_local *)dev->priv)->sifwritew(dev, val, reg))#if 0 /* TMS380TR_DEBUG > 0 */static int madgemc_sifprobe(struct net_device *dev){        unsigned char old, chk1, chk2;		old = SIFREADB(SIFADR);  /* Get the old SIFADR value */        chk1 = 0;       /* Begin with check value 0 */        do {		madgemc_setregpage(dev, 0);                /* Write new SIFADR value */		SIFWRITEB(chk1, SIFADR);		chk2 = SIFREADB(SIFADR);		if (chk2 != chk1)			return -1;				madgemc_setregpage(dev, 1);                /* Read, invert and write */		chk2 = SIFREADB(SIFADD);		if (chk2 != chk1)			return -1;		madgemc_setregpage(dev, 0);                chk2 ^= 0x0FE;		SIFWRITEB(chk2, SIFADR);                /* Read, invert and compare */		madgemc_setregpage(dev, 1);		chk2 = SIFREADB(SIFADD);		madgemc_setregpage(dev, 0);                chk2 ^= 0x0FE;                if(chk1 != chk2)                        return (-1);    /* No adapter */                chk1 -= 2;        } while(chk1 != 0);     /* Repeat 128 times (all byte values) */	madgemc_setregpage(dev, 0); /* sanity */        /* Restore the SIFADR value */	SIFWRITEB(old, SIFADR);        return (0);}#endif/* * Open/initialize the board. This is called sometime after * booting when the 'ifconfig' program is run. * * This routine should set everything up anew at each open, even * registers that "should" only need to be set once at boot, so that * there is non-reboot way to recover if something goes wrong. */int tms380tr_open(struct net_device *dev){	struct net_local *tp = netdev_priv(dev);	int err;		/* init the spinlock */	spin_lock_init(&tp->lock);	init_timer(&tp->timer);	/* Reset the hardware here. Don't forget to set the station address. */#ifdef CONFIG_ISA	if(dev->dma > 0) 	{		unsigned long flags=claim_dma_lock();		disable_dma(dev->dma);		set_dma_mode(dev->dma, DMA_MODE_CASCADE);		enable_dma(dev->dma);		release_dma_lock(flags);	}#endif		err = tms380tr_chipset_init(dev);  	if(err)	{		printk(KERN_INFO "%s: Chipset initialization error\n", 			dev->name);		return (-1);	}	tp->timer.expires	= jiffies + 30*HZ;	tp->timer.function	= tms380tr_timer_end_wait;	tp->timer.data		= (unsigned long)dev;	add_timer(&tp->timer);	printk(KERN_DEBUG "%s: Adapter RAM size: %dK\n", 	       dev->name, tms380tr_read_ptr(dev));	tms380tr_enable_interrupts(dev);	tms380tr_open_adapter(dev);	netif_start_queue(dev);		/* Wait for interrupt from hardware. If interrupt does not come,	 * there will be a timeout from the timer.	 */	tp->Sleeping = 1;	interruptible_sleep_on(&tp->wait_for_tok_int);	del_timer(&tp->timer);	/* If AdapterVirtOpenFlag is 1, the adapter is now open for use */	if(tp->AdapterVirtOpenFlag == 0)	{		tms380tr_disable_interrupts(dev);		return (-1);	}	tp->StartTime = jiffies;	/* Start function control timer */	tp->timer.expires	= jiffies + 2*HZ;	tp->timer.function	= tms380tr_timer_chk;	tp->timer.data		= (unsigned long)dev;	add_timer(&tp->timer);	return (0);}/* * Timeout function while waiting for event */static void tms380tr_timer_end_wait(unsigned long data){	struct net_device *dev = (struct net_device*)data;	struct net_local *tp = netdev_priv(dev);	if(tp->Sleeping)	{		tp->Sleeping = 0;		wake_up_interruptible(&tp->wait_for_tok_int);	}	return;}/* * Initialize the chipset */static int tms380tr_chipset_init(struct net_device *dev){	struct net_local *tp = netdev_priv(dev);	int err;	tms380tr_init_ipb(tp);	tms380tr_init_opb(dev);	tms380tr_init_net_local(dev);	if(tms380tr_debug > 3)		printk(KERN_DEBUG "%s: Resetting adapter...\n", dev->name);	err = tms380tr_reset_adapter(dev);	if(err < 0)		return (-1);	if(tms380tr_debug > 3)		printk(KERN_DEBUG "%s: Bringup diags...\n", dev->name);	err = tms380tr_bringup_diags(dev);	if(err < 0)		return (-1);	if(tms380tr_debug > 3)		printk(KERN_DEBUG "%s: Init adapter...\n", dev->name);	err = tms380tr_init_adapter(dev);	if(err < 0)		return (-1);	if(tms380tr_debug > 3)		printk(KERN_DEBUG "%s: Done!\n", dev->name);	return (0);}/* * Initializes the net_local structure. */static void tms380tr_init_net_local(struct net_device *dev){	struct net_local *tp = netdev_priv(dev);	int i;	dma_addr_t dmabuf;	tp->scb.CMD	= 0;	tp->scb.Parm[0] = 0;	tp->scb.Parm[1] = 0;	tp->ssb.STS	= 0;	tp->ssb.Parm[0] = 0;	tp->ssb.Parm[1] = 0;	tp->ssb.Parm[2] = 0;	tp->CMDqueue	= 0;	tp->AdapterOpenFlag	= 0;	tp->AdapterVirtOpenFlag = 0;	tp->ScbInUse		= 0;	tp->OpenCommandIssued	= 0;	tp->ReOpenInProgress	= 0;	tp->HaltInProgress	= 0;	tp->TransmitHaltScheduled = 0;	tp->LobeWireFaultLogged	= 0;	tp->LastOpenStatus	= 0;	tp->MaxPacketSize	= DEFAULT_PACKET_SIZE;	/* Create circular chain of transmit lists */	for (i = 0; i < TPL_NUM; i++)	{		tp->Tpl[i].NextTPLAddr = htonl(((char *)(&tp->Tpl[(i+1) % TPL_NUM]) - (char *)tp) + tp->dmabuffer); /* DMA buffer may be MMU driven */		tp->Tpl[i].Status	= 0;		tp->Tpl[i].FrameSize	= 0;		tp->Tpl[i].FragList[0].DataCount	= 0;		tp->Tpl[i].FragList[0].DataAddr		= 0;		tp->Tpl[i].NextTPLPtr	= &tp->Tpl[(i+1) % TPL_NUM];		tp->Tpl[i].MData	= NULL;		tp->Tpl[i].TPLIndex	= i;		tp->Tpl[i].DMABuff	= 0;		tp->Tpl[i].BusyFlag	= 0;	}	tp->TplFree = tp->TplBusy = &tp->Tpl[0];	/* Create circular chain of receive lists */	for (i = 0; i < RPL_NUM; i++)	{		tp->Rpl[i].NextRPLAddr = htonl(((char *)(&tp->Rpl[(i+1) % RPL_NUM]) - (char *)tp) + tp->dmabuffer); /* DMA buffer may be MMU driven */		tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);		tp->Rpl[i].FrameSize = 0;		tp->Rpl[i].FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize);		/* Alloc skb and point adapter to data area */		tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize);			tp->Rpl[i].DMABuff = 0;		/* skb == NULL ? then use local buffer */		if(tp->Rpl[i].Skb == NULL)		{			tp->Rpl[i].SkbStat = SKB_UNAVAILABLE;			tp->Rpl[i].FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[i] - (char *)tp) + tp->dmabuffer);			tp->Rpl[i].MData = tp->LocalRxBuffers[i];		}		else	/* SKB != NULL */		{			tp->Rpl[i].Skb->dev = dev;			skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize);			/* data unreachable for DMA ? then use local buffer */			dmabuf = dma_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE);			if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit))			{				tp->Rpl[i].SkbStat = SKB_DATA_COPY;				tp->Rpl[i].FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[i] - (char *)tp) + tp->dmabuffer);				tp->Rpl[i].MData = tp->LocalRxBuffers[i];			}			else	/* DMA directly in skb->data */			{				tp->Rpl[i].SkbStat = SKB_DMA_DIRECT;				tp->Rpl[i].FragList[0].DataAddr = htonl(dmabuf);				tp->Rpl[i].MData = tp->Rpl[i].Skb->data;				tp->Rpl[i].DMABuff = dmabuf;			}		}		tp->Rpl[i].NextRPLPtr = &tp->Rpl[(i+1) % RPL_NUM];		tp->Rpl[i].RPLIndex = i;	}	tp->RplHead = &tp->Rpl[0];	tp->RplTail = &tp->Rpl[RPL_NUM-1];	tp->RplTail->Status = (RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);	return;}/* * Initializes the initialisation parameter block. */static void tms380tr_init_ipb(struct net_local *tp){	tp->ipb.Init_Options	= BURST_MODE;	tp->ipb.CMD_Status_IV	= 0;	tp->ipb.TX_IV		= 0;	tp->ipb.RX_IV		= 0;	tp->ipb.Ring_Status_IV	= 0;	tp->ipb.SCB_Clear_IV	= 0;	tp->ipb.Adapter_CHK_IV	= 0;	tp->ipb.RX_Burst_Size	= BURST_SIZE;	tp->ipb.TX_Burst_Size	= BURST_SIZE;	tp->ipb.DMA_Abort_Thrhld = DMA_RETRIES;	tp->ipb.SCB_Addr	= 0;	tp->ipb.SSB_Addr	= 0;

⌨️ 快捷键说明

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