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

📄 sunbmac.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
			udelay(20);		}		if(timeout == 0)			printk("%s: PHY reset failed.\n", bp->dev->name);		bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);		/* Now we try 10baseT. */		bp->sw_bmcr &= ~(BMCR_SPEED100);		bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);		return 0;	}	/* We've tried them all. */	return -1;}static void bigmac_timer(unsigned long data){	struct bigmac *bp = (struct bigmac *) data;	struct bmac_tcvr *tregs = bp->tregs;	int restart_timer = 0;	bp->timer_ticks++;	if(bp->timer_state == ltrywait) {		bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMSR);		bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);		if(bp->sw_bmsr & BMSR_LSTATUS) {			printk("%s: Link is now up at %s.\n",			       bp->dev->name,			       (bp->sw_bmcr & BMCR_SPEED100) ?			       "100baseT" : "10baseT");			bp->timer_state = asleep;			restart_timer = 0;		} else {			if(bp->timer_ticks >= 4) {				int ret;				ret = try_next_permutation(bp, tregs);				if(ret == -1) {					printk("%s: Link down, cable problem?\n",					       bp->dev->name);					ret = bigmac_init(bp, 0);					if(ret) {						printk("%s: Error, cannot re-init the "						       "BigMAC.\n", bp->dev->name);					}					return;				}				bp->timer_ticks = 0;				restart_timer = 1;			} else {				restart_timer = 1;			}		}	} else {		/* Can't happens.... */		printk("%s: Aieee, link timer is asleep but we got one anyways!\n",		       bp->dev->name);		restart_timer = 0;		bp->timer_ticks = 0;		bp->timer_state = asleep; /* foo on you */	}	if(restart_timer != 0) {		bp->bigmac_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */		add_timer(&bp->bigmac_timer);	}}/* Well, really we just force the chip into 100baseT then * 10baseT, each time checking for a link status. */static void bigmac_begin_auto_negotiation(struct bigmac *bp){	struct bmac_tcvr *tregs = bp->tregs;	int timeout;	/* Grab new software copies of PHY registers. */	bp->sw_bmsr	= bigmac_tcvr_read(bp, tregs, BIGMAC_BMSR);	bp->sw_bmcr	= bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);	/* Reset the PHY. */	bp->sw_bmcr	= (BMCR_ISOLATE | BMCR_PDOWN | BMCR_LOOPBACK);	bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);	bp->sw_bmcr	= (BMCR_RESET);	bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);	timeout = 64;	while(--timeout) {		bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);		if((bp->sw_bmcr & BMCR_RESET) == 0)			break;		udelay(20);	}	if(timeout == 0)		printk("%s: PHY reset failed.\n", bp->dev->name);	bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);	/* First we try 100baseT. */	bp->sw_bmcr |= BMCR_SPEED100;	bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr);	bp->timer_state = ltrywait;	bp->timer_ticks = 0;	bp->bigmac_timer.expires = jiffies + (12 * HZ) / 10;	bp->bigmac_timer.data = (unsigned long) bp;	bp->bigmac_timer.function = &bigmac_timer;	add_timer(&bp->bigmac_timer);}static int bigmac_init(struct bigmac *bp, int from_irq){	struct qe_globreg    *gregs        = bp->gregs;	struct qe_creg       *cregs        = bp->creg;	struct BIG_MAC_regs  *bregs        = bp->bregs;	unsigned char *e = &bp->dev->dev_addr[0];	/* Latch current counters into statistics. */	bigmac_get_counters(bp, bregs);	/* Reset QEC. */	qec_global_reset(gregs);	/* Init QEC. */	qec_init(bp);	/* Alloc and reset the tx/rx descriptor chains. */#ifndef __sparc_v9__	if(sparc_cpu_model == sun4c)		sun4c_bigmac_init_rings(bp);	else#endif		bigmac_init_rings(bp, from_irq);	/* Initialize the PHY. */	bigmac_tcvr_init(bp);	/* Stop transmitter and receiver. */	bigmac_stop(bp);	/* Set hardware ethernet address. */	bregs->mac_addr2 = ((e[4] << 8) | e[5]);	bregs->mac_addr1 = ((e[2] << 8) | e[3]);	bregs->mac_addr0 = ((e[0] << 8) | e[1]);	/* Clear the hash table until mc upload occurs. */	bregs->htable3 = 0;	bregs->htable2 = 0;	bregs->htable1 = 0;	bregs->htable0 = 0;	/* Enable Big Mac hash table filter. */	bregs->rx_cfg = (BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_FIFO);	udelay(20);	/* Ok, configure the Big Mac transmitter. */	bregs->tx_cfg = BIGMAC_TXCFG_FIFO;	/* The HME docs recommend to use the 10LSB of our MAC here. */	bregs->rand_seed = ((e[5] | e[4] << 8) & 0x3ff);	/* Enable the output drivers no matter what. */	bregs->xif_cfg = (BIGMAC_XCFG_ODENABLE | BIGMAC_XCFG_RESV);	/* Tell the QEC where the ring descriptors are. */	cregs->rxds = bp->bblock_dvma + bib_offset(be_rxd, 0);	cregs->txds = bp->bblock_dvma + bib_offset(be_txd, 0);	/* Setup the FIFO pointers into QEC local memory. */	cregs->rxwbufptr = cregs->rxrbufptr = 0;	cregs->txwbufptr = cregs->txrbufptr = gregs->rsize;	/* Tell bigmac what interrupts we don't want to hear about. */	bregs->imask = (BIGMAC_IMASK_GOTFRAME | BIGMAC_IMASK_SENTFRAME);	/* Enable the various other irq's. */	cregs->rimask = 0;	cregs->timask = 0;	cregs->qmask = 0;	cregs->bmask = 0;	/* Set jam size to a reasonable default. */	bregs->jsize     = DEFAULT_JAMSIZE;	/* Clear collision counter. */	cregs->ccnt = 0;	/* Enable transmitter and receiver. */	bregs->tx_cfg |= BIGMAC_TXCFG_ENABLE;	bregs->rx_cfg |= BIGMAC_RXCFG_ENABLE;	/* Ok, start detecting link speed/duplex. */	bigmac_begin_auto_negotiation(bp);	/* Success. */	return 0;}/* Error interrupts get sent here. */static void bigmac_is_medium_rare(struct bigmac *bp,				  unsigned int qec_status,				  unsigned int bmac_status){	printk("bigmac_is_medium_rare: ");	if(qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) {		if(qec_status & GLOB_STAT_ER)			printk("QEC_ERROR, ");		if(qec_status & GLOB_STAT_BM)			printk("QEC_BMAC_ERROR, ");	}	if(bmac_status & CREG_STAT_ERRORS) {		if(bmac_status & CREG_STAT_BERROR)			printk("BMAC_ERROR, ");		if(bmac_status & CREG_STAT_TXDERROR)			printk("TXD_ERROR, ");		if(bmac_status & CREG_STAT_TXLERR)			printk("TX_LATE_ERROR, ");		if(bmac_status & CREG_STAT_TXPERR)			printk("TX_PARITY_ERROR, ");		if(bmac_status & CREG_STAT_TXSERR)			printk("TX_SBUS_ERROR, ");		if(bmac_status & CREG_STAT_RXDROP)			printk("RX_DROP_ERROR, ");		if(bmac_status & CREG_STAT_RXSMALL)			printk("RX_SMALL_ERROR, ");		if(bmac_status & CREG_STAT_RXLERR)			printk("RX_LATE_ERROR, ");		if(bmac_status & CREG_STAT_RXPERR)			printk("RX_PARITY_ERROR, ");		if(bmac_status & CREG_STAT_RXSERR)			printk("RX_SBUS_ERROR, ");	}	printk(" RESET\n");	bigmac_init(bp, 1);}/* BigMAC transmit complete service routines. */static inline void bigmac_tx(struct bigmac *bp){	struct be_txd *txbase = &bp->bmac_block->be_txd[0];	struct be_txd *this;	int elem = bp->tx_old;	DTX(("bigmac_tx: tx_old[%d] ", elem));	while(elem != bp->tx_new) {		struct sk_buff *skb;		this = &txbase[elem];		DTX(("this(%p) [flags(%08x)addr(%08x)]",		     this, this->tx_flags, this->tx_addr));		if(this->tx_flags & TXD_OWN)			break;		skb = bp->tx_skbs[elem];		DTX(("skb(%p) ", skb));		bp->tx_skbs[elem] = NULL;		dev_kfree_skb(skb);		bp->enet_stats.tx_packets++;		elem = NEXT_TX(elem);	}	DTX((" DONE, tx_old=%d\n", elem));	bp->tx_old = elem;}#ifndef __sparc_v9__static inline void sun4c_bigmac_tx(struct bigmac *bp){	struct be_txd *txbase = &bp->bmac_block->be_txd[0];	struct be_txd *this;	int elem = bp->tx_old;	while(elem != bp->tx_new) {		this = &txbase[elem];		if(this->tx_flags & TXD_OWN)			break;		bp->enet_stats.tx_packets++;		elem = NEXT_TX(elem);	}	bp->tx_old = elem;}#endif/* BigMAC receive complete service routines. */static inline void bigmac_rx(struct bigmac *bp){	struct be_rxd *rxbase = &bp->bmac_block->be_rxd[0];	struct be_rxd *this;	int elem = bp->rx_new, drops = 0;	this = &rxbase[elem];	while(!(this->rx_flags & RXD_OWN)) {		struct sk_buff *skb;		unsigned int flags = this->rx_flags;		int len = (flags & RXD_LENGTH); /* FCS not included */		/* Check for errors. */		if(len < ETH_ZLEN) {			bp->enet_stats.rx_errors++;			bp->enet_stats.rx_length_errors++;	drop_it:			/* Return it to the BigMAC. */			bp->enet_stats.rx_dropped++;			this->rx_addr = sbus_dvma_addr(bp->rx_skbs[elem]->data);			this->rx_flags =				(RXD_OWN | (RX_BUF_ALLOC_SIZE & RXD_LENGTH));			goto next;		}		skb = bp->rx_skbs[elem];#ifdef NEED_DMA_SYNCHRONIZATION#ifdef __sparc_v9__		if ((unsigned long) (skb->data + skb->len) >= MAX_DMA_ADDRESS) {			printk("sunbmac: Bogus DMA buffer address "			       "[%016lx]\n", ((unsigned long) skb->data));			panic("DMA address too large, tell DaveM");		}#endif		mmu_sync_dma(sbus_dvma_addr(skb->data),			     skb->len, bp->bigmac_sbus_dev->my_bus);#endif		if(len > RX_COPY_THRESHOLD) {			struct sk_buff *new_skb;			/* Now refill the entry, if we can. */			new_skb = big_mac_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);			if(!new_skb) {				drops++;				goto drop_it;			}			bp->rx_skbs[elem] = new_skb;			new_skb->dev = bp->dev;			skb_put(new_skb, ETH_FRAME_LEN);			skb_reserve(new_skb, 34);			rxbase[elem].rx_addr = sbus_dvma_addr(new_skb->data);			rxbase[elem].rx_flags =				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));			/* Trim the original skb for the netif. */			skb_trim(skb, len);		} else {			struct sk_buff *copy_skb = dev_alloc_skb(len + 2);			if(!copy_skb) {				drops++;				goto drop_it;			}			copy_skb->dev = bp->dev;			skb_reserve(copy_skb, 2);			skb_put(copy_skb, len);			eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0);			/* Reuse otiginal ring buffer. */			rxbase[elem].rx_addr = sbus_dvma_addr(skb->data);			rxbase[elem].rx_flags =				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));			skb = copy_skb;		}		/* No checksums done by the BigMAC ;-( */		skb->protocol = eth_type_trans(skb, bp->dev);		netif_rx(skb);		bp->enet_stats.rx_packets++;	next:		elem = NEXT_RX(elem);		this = &rxbase[elem];	}	bp->rx_new = elem;	if(drops)		printk("%s: Memory squeeze, deferring packet.\n", bp->dev->name);}#ifndef __sparc_v9__static inline void sun4c_bigmac_rx(struct bigmac *bp){	struct be_rxd *rxbase = &bp->bmac_block->be_rxd[0];	struct be_rxd *this;	struct bigmac_buffers *bbufs = bp->sun4c_buffers;	__u32 bbufs_dvma = bp->s4c_buf_dvma;	int elem = bp->rx_new, drops = 0;	this = &rxbase[elem];	while(!(this->rx_flags & RXD_OWN)) {		struct sk_buff *skb;		unsigned char *this_bbuf =			bbufs->rx_buf[elem & (SUN4C_RX_RING_SIZE - 1)];		__u32 this_bbuf_dvma = bbufs_dvma +			bbuf_offset(rx_buf, (elem & (SUN4C_RX_RING_SIZE - 1)));		struct be_rxd *end_rxd =			&rxbase[(elem+SUN4C_RX_RING_SIZE)&(RX_RING_SIZE-1)];		unsigned int flags = this->rx_flags;		int len = (flags & RXD_LENGTH) - 4; /* FCS not included */		/* Check for errors. */		if(len < ETH_ZLEN) {			bp->enet_stats.rx_errors++;			bp->enet_stats.rx_length_errors++;			bp->enet_stats.rx_dropped++;		} else {			skb = dev_alloc_skb(len + 2);			if(skb == 0) {				drops++;				bp->enet_stats.rx_dropped++;			} else {				skb->dev = bp->dev;				skb_reserve(skb, 2);				skb_put(skb, len);				eth_copy_and_sum(skb, (unsigned char *)this_bbuf,						 len, 0);				skb->protocol = eth_type_trans(skb, bp->dev);				netif_rx(skb);				bp->enet_stats.rx_packets++;			}		}		end_rxd->rx_addr = this_bbuf_dvma;		end_rxd->rx_flags = (RXD_OWN | (SUN4C_RX_BUFF_SIZE & RXD_LENGTH));				elem = NEXT_RX(elem);		this = &rxbase[elem];	}	bp->rx_new = elem;	if(drops)		printk("%s: Memory squeeze, deferring packet.\n", bp->dev->name);}#endifstatic void bigmac_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct bigmac *bp = (struct bigmac *) dev_id;	unsigned int qec_status, bmac_status;	DIRQ(("bigmac_interrupt: "));	/* Latch status registers now. */	bmac_status = bp->creg->stat;	qec_status = bp->gregs->stat;	bp->dev->interrupt = 1;	DIRQ(("qec_status=%08x bmac_status=%08x\n", qec_status, bmac_status));	if((qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) ||	   (bmac_status & CREG_STAT_ERRORS))		bigmac_is_medium_rare(bp, qec_status, bmac_status);	if(bmac_status & CREG_STAT_TXIRQ)		bigmac_tx(bp);	if(bmac_status & CREG_STAT_RXIRQ)		bigmac_rx(bp);	if(bp->dev->tbusy && (TX_BUFFS_AVAIL(bp) >= 0)) {		bp->dev->tbusy = 0;		mark_bh(NET_BH);	}	bp->dev->interrupt = 0;}#ifndef __sparc_v9__static void sun4c_bigmac_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct bigmac *bp = (struct bigmac *) dev_id;	unsigned int qec_status, bmac_status;	/* Latch status registers now. */	bmac_status = bp->creg->stat;	qec_status = bp->gregs->stat;	bp->dev->interrupt = 1;	if(qec_status & (GLOB_STAT_ER | GLOB_STAT_BM) ||	   (bmac_status & CREG_STAT_ERRORS))		bigmac_is_medium_rare(bp, qec_status, bmac_status);	if(bmac_status & CREG_STAT_TXIRQ)		sun4c_bigmac_tx(bp);	if(bmac_status & CREG_STAT_RXIRQ)		sun4c_bigmac_rx(bp);	if(bp->dev->tbusy && (SUN4C_TX_BUFFS_AVAIL(bp) >= 0)) {		bp->dev->tbusy = 0;		mark_bh(NET_BH);	}	bp->dev->interrupt = 0;}#endifstatic int bigmac_open(struct device *dev){	struct bigmac *bp = (struct bigmac *) dev->priv;	int res;#ifndef __sparc_v9__	if(sparc_cpu_model == sun4c) {		if(request_irq(dev->irq, &sun4c_bigmac_interrupt,			       SA_SHIRQ, "BIG MAC", (void *) bp)) {			printk("BIGMAC: Can't order irq %d to go.\n", dev->irq);			return -EAGAIN;		}	} else#endif	if(request_irq(dev->irq, &bigmac_interrupt,		       SA_SHIRQ, "BIG MAC", (void *) bp)) {		printk("BIGMAC: Can't order irq %d to go.\n", dev->irq);		return -EAGAIN;	}	init_timer(&bp->bigmac_timer);	res = bigmac_init(bp, 0);	if(!res) {		MOD_INC_USE_COUNT;

⌨️ 快捷键说明

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