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

📄 sgiseeq.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
}static inline void kick_tx(struct sgiseeq_tx_desc *td,			   volatile struct hpc3_ethregs *hregs){	/* If the HPC aint doin nothin, and there are more packets	 * with ETXD cleared and XIU set we must make very certain	 * that we restart the HPC else we risk locking up the	 * adapter.  The following code is only safe iff the HPCDMA	 * is not active!	 */	while ((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) ==	      (HPCDMA_XIU | HPCDMA_ETXD))		td = (struct sgiseeq_tx_desc *)(long) KSEG1ADDR(td->tdma.pnext);	if (td->tdma.cntinfo & HPCDMA_XIU) {		hregs->tx_ndptr = PHYSADDR(td);		hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;	}}static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp,			      volatile struct hpc3_ethregs *hregs,			      volatile struct sgiseeq_regs *sregs){	struct sgiseeq_tx_desc *td;	unsigned long status = hregs->tx_ctrl;	int j;	tx_maybe_reset_collisions(sp, sregs);	if (!(status & (HPC3_ETXCTRL_ACTIVE | SEEQ_TSTAT_PTRANS))) {		/* Oops, HPC detected some sort of error. */		if (status & SEEQ_TSTAT_R16)			sp->stats.tx_aborted_errors++;		if (status & SEEQ_TSTAT_UFLOW)			sp->stats.tx_fifo_errors++;		if (status & SEEQ_TSTAT_LCLS)			sp->stats.collisions++;	}	/* Ack 'em... */	for (j = sp->tx_old; j != sp->tx_new; j = NEXT_TX(j)) {		td = &sp->srings.tx_desc[j];		if (!(td->tdma.cntinfo & (HPCDMA_XIU)))			break;		if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) {			if(!(status & HPC3_ETXCTRL_ACTIVE)) {				hregs->tx_ndptr = PHYSADDR(td);				hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;			}			break;		}		sp->stats.tx_packets++;		sp->tx_old = NEXT_TX(sp->tx_old);		td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE);		td->tdma.cntinfo |= HPCDMA_EOX;	}}static void sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = (struct net_device *) dev_id;	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;	volatile struct hpc3_ethregs *hregs = sp->hregs;	volatile struct sgiseeq_regs *sregs = sp->sregs;	/* Ack the IRQ and set software state. */	hregs->rx_reset = HPC3_ERXRST_CLRIRQ;	/* Always check for received packets. */	sgiseeq_rx(dev, sp, hregs, sregs);	/* Only check for tx acks iff we have something queued. */	if (sp->tx_old != sp->tx_new)		sgiseeq_tx(dev, sp, hregs, sregs);	if ((TX_BUFFS_AVAIL(sp) > 0) && netif_queue_stopped(dev)) {		netif_wake_queue(dev);	}}static int sgiseeq_open(struct net_device *dev){	struct sgiseeq_private *sp = (struct sgiseeq_private *)dev->priv;	volatile struct sgiseeq_regs *sregs = sp->sregs;	unsigned long flags;	save_flags(flags); cli();	if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, (void *) dev)) {		printk("Seeq8003: Can't get irq %d\n", dev->irq);		restore_flags(flags);		return -EAGAIN;	}	init_seeq(dev, sp, sregs);	netif_start_queue(dev);	restore_flags(flags);	return 0;}static int sgiseeq_close(struct net_device *dev){	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;	volatile struct sgiseeq_regs *sregs = sp->sregs;	netif_stop_queue(dev);	/* Shutdown the Seeq. */	reset_hpc3_and_seeq(sp->hregs, sregs);	free_irq(dev->irq, dev);	return 0;}static inline int sgiseeq_reset(struct net_device *dev){	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;	volatile struct sgiseeq_regs *sregs = sp->sregs;	init_seeq(dev, sp, sregs);	dev->trans_start = jiffies;	netif_wake_queue(dev);	return 0;}void sgiseeq_my_reset(void){	printk("RESET!\n");	sgiseeq_reset(gdev);}static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;	volatile struct hpc3_ethregs *hregs = sp->hregs;	unsigned long flags;	struct sgiseeq_tx_desc *td;	int skblen, len, entry;	save_and_cli(flags);	/* Setup... */	skblen = skb->len;	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;	sp->stats.tx_bytes += len;	entry = sp->tx_new;	td = &sp->srings.tx_desc[entry];	/* Create entry.  There are so many races with adding a new	 * descriptor to the chain:	 * 1) Assume that the HPC is off processing a DMA chain while	 *    we are changing all of the following.	 * 2) Do no allow the HPC to look at a new descriptor until	 *    we have completely set up it's state.  This means, do	 *    not clear HPCDMA_EOX in the current last descritptor	 *    until the one we are adding looks consistant and could	 *    be processes right now.	 * 3) The tx interrupt code must notice when we've added a new	 *    entry and the HPC got to the end of the chain before we	 *    added this new entry and restarted it.	 */	memcpy((char *)(long)td->buf_vaddr, skb->data, skblen);	td->tdma.cntinfo = (len & HPCDMA_BCNT) |	                   (HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX);	if (sp->tx_old != sp->tx_new) {		struct sgiseeq_tx_desc *backend;		backend = &sp->srings.tx_desc[PREV_TX(sp->tx_new)];		backend->tdma.cntinfo &= ~(HPCDMA_EOX);	}	sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */	/* Maybe kick the HPC back into motion. */	if (!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE))		kick_tx(&sp->srings.tx_desc[sp->tx_old], hregs);	dev->trans_start = jiffies;	dev_kfree_skb(skb);	if (!TX_BUFFS_AVAIL(sp))		netif_stop_queue(dev);	restore_flags(flags);	return 0;}static void timeout(struct net_device *dev){	printk("%s: transmit timed out, resetting\n", dev->name);	sgiseeq_reset(dev);	dev->trans_start = jiffies;	netif_wake_queue(dev);}static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev){	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;	return &sp->stats;}static void sgiseeq_set_multicast(struct net_device *dev){}static inline void setup_tx_ring(struct sgiseeq_tx_desc *buf, int nbufs){	int i = 0;	while (i < (nbufs - 1)) {		buf[i].tdma.pnext = PHYSADDR(&buf[i + 1]);		buf[i].tdma.pbuf = 0;		i++;	}	buf[i].tdma.pnext = PHYSADDR(&buf[0]);}static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs){	int i = 0;	while (i < (nbufs - 1)) {		buf[i].rdma.pnext = PHYSADDR(&buf[i + 1]);		buf[i].rdma.pbuf = 0;		i++;	}	buf[i].rdma.pbuf = 0;	buf[i].rdma.pnext = PHYSADDR(&buf[0]);}static char onboard_eth_addr[6];#define ALIGNED(x)  ((((unsigned long)(x)) + 0xf) & ~(0xf))int sgiseeq_init(struct net_device *dev, struct sgiseeq_regs *sregs,		 struct hpc3_ethregs *hregs, int irq){	static unsigned version_printed = 0;	int i;	struct sgiseeq_private *sp;	dev->priv = (struct sgiseeq_private *) get_free_page(GFP_KERNEL);	if (dev->priv == NULL)		return -ENOMEM;	if (!version_printed++)		printk(version);	printk("%s: SGI Seeq8003 ", dev->name);	for (i = 0; i < 6; i++)		printk("%2.2x%c",		       dev->dev_addr[i] = onboard_eth_addr[i],		       i == 5 ? ' ': ':');	printk("\n");	sp = (struct sgiseeq_private *) dev->priv;#ifdef DEBUG	gpriv = sp;	gdev = dev;#endif	memset((char *)dev->priv, 0, sizeof(struct sgiseeq_private));	sp->sregs = sregs;	sp->hregs = hregs;	sp->name = sgiseeqstr;	sp->srings.rx_desc = (struct sgiseeq_rx_desc *)	                     (KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0])));	dma_cache_wback_inv((unsigned long)&sp->srings.rxvector,	                    sizeof(sp->srings.rxvector));	sp->srings.tx_desc = (struct sgiseeq_tx_desc *)	                     (KSEG1ADDR(ALIGNED(&sp->srings.txvector[0])));	dma_cache_wback_inv((unsigned long)&sp->srings.txvector,	                    sizeof(sp->srings.txvector));	/* A couple calculations now, saves many cycles later. */	setup_rx_ring(sp->srings.rx_desc, SEEQ_RX_BUFFERS);	setup_tx_ring(sp->srings.tx_desc, SEEQ_TX_BUFFERS);	/* Reset the chip. */	hpc3_eth_reset((volatile struct hpc3_ethregs *) hregs);	sp->is_edlc = !(sregs->rw.rregs.collision_tx[0] & 0xff);	if (sp->is_edlc) {		sp->control = (SEEQ_CTRL_XCNT | SEEQ_CTRL_ACCNT |			       SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT |			       SEEQ_CTRL_ENCARR);	}	dev->open                 = sgiseeq_open;	dev->stop                 = sgiseeq_close;	dev->hard_start_xmit      = sgiseeq_start_xmit;	dev->tx_timeout           = timeout;	dev->watchdog_timeo       = (200 * HZ) / 1000;	dev->get_stats            = sgiseeq_get_stats;	dev->set_multicast_list   = sgiseeq_set_multicast;	dev->irq                  = irq;	dev->dma                  = 0;	ether_setup(dev);	return 0;}static inline unsigned char str2hexnum(unsigned char c){	if (c >= '0' && c <= '9')		return c - '0';	if (c >= 'a' && c <= 'f')		return c - 'a' + 10;	return 0; /* foo */}static inline void str2eaddr(unsigned char *ea, unsigned char *str){	int i;	for (i = 0; i < 6; i++) {		unsigned char num;		if(*str == ':')			str++;		num = str2hexnum(*str++) << 4;		num |= (str2hexnum(*str++));		ea[i] = num;	}}int sgiseeq_probe(struct net_device *dev){	static int initialized = 0;	char *ep;	if (initialized)	/* Already initialized? */		return 1;	initialized++;	/* First get the ethernet address of the onboard interface from ARCS.	 * This is fragile; PROM doesn't like running from cache.	 * On MIPS64 it crashes for some other, yet unknown reason ...	 */	ep = ArcGetEnvironmentVariable("eaddr");	str2eaddr(onboard_eth_addr, ep);	return sgiseeq_init(dev,			    (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)),			    &hpc3c0->ethregs, SGI_ENET_IRQ);}

⌨️ 快捷键说明

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