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

📄 sgiseeq.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
		hregs->tx_ndptr = PHYSADDR(td);		hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;	}}static inline void sgiseeq_tx(struct 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 inline void tx_maybe_unbusy(struct sgiseeq_private *sp,				   struct device *dev){	if((TX_BUFFS_AVAIL(sp) >= 0) && dev->tbusy) {		dev->tbusy = 0;		mark_bh(NET_BH);	}}static void sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct device *dev = (struct 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;	dev->interrupt = 1;	/* 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);	tx_maybe_unbusy(sp, dev);	dev->interrupt = 0;}static int sgiseeq_open(struct 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);	dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 1;	restore_flags(flags);	return 0;}static int sgiseeq_close(struct device *dev){	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;	volatile struct sgiseeq_regs *sregs = sp->sregs;	dev->start = 0;	dev->tbusy = 1;	/* Shutdown the Seeq. */	reset_hpc3_and_seeq(sp->hregs, sregs);	free_irq(dev->irq, dev);	return 0;}static inline int sgiseeq_reset(struct 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;	dev->interrupt = 0;	dev->start = 1;	dev->tbusy = 0;	return 0;}void sgiseeq_my_reset(void){	printk("RESET!\n");	sgiseeq_reset(gdev);}static inline int verify_tx(struct sgiseeq_private *sp,			    struct device *dev,			    struct sk_buff *skb){	/* Are we bolixed? */	if(dev->tbusy) {		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < 20)			return 1;		printk("%s: transmit timed out, ticks=%d resetting\n",		       dev->name, tickssofar);		sgiseeq_reset(dev);		return 0;	}	/* Are we getting in someone else's way? */	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {		printk("%s: Transmitter access conflict.\n", dev->name);		return -1;	}	/* Can we even send anything? */	if(!TX_BUFFS_AVAIL(sp))		return -1;	return 0;}static int sgiseeq_start_xmit(struct sk_buff *skb, struct 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;	if(verify_tx(sp, dev, skb))		return -1; /* Yeee... */	save_flags(flags); cli();	/* Setup... */	skblen = skb->len;	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;	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 *)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))		dev->tbusy = 0;	restore_flags(flags);	return 0;}static struct enet_statistics *sgiseeq_get_stats(struct device *dev){	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;	return &sp->stats;}static void sgiseeq_set_multicast(struct 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 device *dev, struct sgiseeq_regs *sregs,		 struct hpc3_ethregs *hregs, int irq){	static unsigned version_printed = 0;	int i;	struct sgiseeq_private *sp;	if(dev == NULL) {		dev = init_etherdev(0, sizeof(struct sgiseeq_private));	} else {		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->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 device *dev){	char *ep;	/* First get the ethernet address of the onboard	 * interface from ARCS.	 */	ep = romvec->get_evar("eaddr");	str2eaddr(onboard_eth_addr, ep);	return sgiseeq_init(dev,			    (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)),			    &hpc3c0->ethregs, 3);}

⌨️ 快捷键说明

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