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

📄 sunbmac.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			shift -= 1;		} while (shift >= 0);		(void) read_tcvr_bit(bp, tregs);		(void) read_tcvr_bit(bp, tregs);		(void) read_tcvr_bit(bp, tregs);	}	return retval;}static void bigmac_tcvr_init(struct bigmac *bp){	unsigned long tregs = bp->tregs;	u32 mpal;	idle_transceiver(tregs);	sbus_writel(MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK,		    tregs + TCVR_MPAL);	sbus_readl(tregs + TCVR_MPAL);	/* Only the bit for the present transceiver (internal or	 * external) will stick, set them both and see what stays.	 */	sbus_writel(MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO, tregs + TCVR_MPAL);	sbus_readl(tregs + TCVR_MPAL);	udelay(20);	mpal = sbus_readl(tregs + TCVR_MPAL);	if (mpal & MGMT_PAL_EXT_MDIO) {		bp->tcvr_type = external;		sbus_writel(~(TCVR_PAL_EXTLBACK | TCVR_PAL_MSENSE | TCVR_PAL_LTENABLE),			    tregs + TCVR_TPAL);		sbus_readl(tregs + TCVR_TPAL);	} else if (mpal & MGMT_PAL_INT_MDIO) {		bp->tcvr_type = internal;		sbus_writel(~(TCVR_PAL_SERIAL | TCVR_PAL_EXTLBACK |			      TCVR_PAL_MSENSE | TCVR_PAL_LTENABLE),			    tregs + TCVR_TPAL);		sbus_readl(tregs + TCVR_TPAL);	} else {		printk(KERN_ERR "BIGMAC: AIEEE, neither internal nor "		       "external MDIO available!\n");		printk(KERN_ERR "BIGMAC: mgmt_pal[%08x] tcvr_pal[%08x]\n",		       sbus_readl(tregs + TCVR_MPAL),		       sbus_readl(tregs + TCVR_TPAL));	}}static int bigmac_init(struct bigmac *, int);static int try_next_permutation(struct bigmac *bp, unsigned long tregs){	if (bp->sw_bmcr & BMCR_SPEED100) {		int timeout;		/* 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(KERN_ERR "%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;	unsigned long 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(KERN_INFO "%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(KERN_ERR "%s: Link down, cable problem?\n",					       bp->dev->name);					ret = bigmac_init(bp, 0);					if (ret) {						printk(KERN_ERR "%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(KERN_ERR "%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){	unsigned long 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(KERN_ERR "%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){	unsigned long gregs        = bp->gregs;	unsigned long cregs        = bp->creg;	unsigned long 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. */	bigmac_init_rings(bp, from_irq);	/* Initialize the PHY. */	bigmac_tcvr_init(bp);	/* Stop transmitter and receiver. */	bigmac_stop(bp);	/* Set hardware ethernet address. */	sbus_writel(((e[4] << 8) | e[5]), bregs + BMAC_MACADDR2);	sbus_writel(((e[2] << 8) | e[3]), bregs + BMAC_MACADDR1);	sbus_writel(((e[0] << 8) | e[1]), bregs + BMAC_MACADDR0);	/* Clear the hash table until mc upload occurs. */	sbus_writel(0, bregs + BMAC_HTABLE3);	sbus_writel(0, bregs + BMAC_HTABLE2);	sbus_writel(0, bregs + BMAC_HTABLE1);	sbus_writel(0, bregs + BMAC_HTABLE0);	/* Enable Big Mac hash table filter. */	sbus_writel(BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_FIFO,		    bregs + BMAC_RXCFG);	udelay(20);	/* Ok, configure the Big Mac transmitter. */	sbus_writel(BIGMAC_TXCFG_FIFO, bregs + BMAC_TXCFG);	/* The HME docs recommend to use the 10LSB of our MAC here. */	sbus_writel(((e[5] | e[4] << 8) & 0x3ff),		    bregs + BMAC_RSEED);	/* Enable the output drivers no matter what. */	sbus_writel(BIGMAC_XCFG_ODENABLE | BIGMAC_XCFG_RESV,		    bregs + BMAC_XIFCFG);	/* Tell the QEC where the ring descriptors are. */	sbus_writel(bp->bblock_dvma + bib_offset(be_rxd, 0),		    cregs + CREG_RXDS);	sbus_writel(bp->bblock_dvma + bib_offset(be_txd, 0),		    cregs + CREG_TXDS);	/* Setup the FIFO pointers into QEC local memory. */	sbus_writel(0, cregs + CREG_RXRBUFPTR);	sbus_writel(0, cregs + CREG_RXWBUFPTR);	sbus_writel(sbus_readl(gregs + GLOB_RSIZE),		    cregs + CREG_TXRBUFPTR);	sbus_writel(sbus_readl(gregs + GLOB_RSIZE),		    cregs + CREG_TXWBUFPTR);	/* Tell bigmac what interrupts we don't want to hear about. */	sbus_writel(BIGMAC_IMASK_GOTFRAME | BIGMAC_IMASK_SENTFRAME,		    bregs + BMAC_IMASK);	/* Enable the various other irq's. */	sbus_writel(0, cregs + CREG_RIMASK);	sbus_writel(0, cregs + CREG_TIMASK);	sbus_writel(0, cregs + CREG_QMASK);	sbus_writel(0, cregs + CREG_BMASK);	/* Set jam size to a reasonable default. */	sbus_writel(DEFAULT_JAMSIZE, bregs + BMAC_JSIZE);	/* Clear collision counter. */	sbus_writel(0, cregs + CREG_CCNT);	/* Enable transmitter and receiver. */	sbus_writel(sbus_readl(bregs + BMAC_TXCFG) | BIGMAC_TXCFG_ENABLE,		    bregs + BMAC_TXCFG);	sbus_writel(sbus_readl(bregs + BMAC_RXCFG) | BIGMAC_RXCFG_ENABLE,		    bregs + BMAC_RXCFG);	/* 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, u32 qec_status, u32 bmac_status){	printk(KERN_ERR "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 void bigmac_tx(struct bigmac *bp){	struct be_txd *txbase = &bp->bmac_block->be_txd[0];	struct net_device *dev = bp->dev;	int elem;	spin_lock(&bp->lock);	elem = bp->tx_old;	DTX(("bigmac_tx: tx_old[%d] ", elem));	while (elem != bp->tx_new) {		struct sk_buff *skb;		struct be_txd *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];		bp->enet_stats.tx_packets++;		bp->enet_stats.tx_bytes += skb->len;		sbus_unmap_single(bp->bigmac_sdev,				  this->tx_addr, skb->len,				  SBUS_DMA_TODEVICE);		DTX(("skb(%p) ", skb));		bp->tx_skbs[elem] = NULL;		dev_kfree_skb_irq(skb);		elem = NEXT_TX(elem);	}	DTX((" DONE, tx_old=%d\n", elem));	bp->tx_old = elem;	if (netif_queue_stopped(dev) &&	    TX_BUFFS_AVAIL(bp) > 0)		netif_wake_queue(bp->dev);	spin_unlock(&bp->lock);}/* BigMAC receive complete service routines. */static 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;	u32 flags;	this = &rxbase[elem];	while (!((flags = this->rx_flags) & RXD_OWN)) {		struct sk_buff *skb;		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_flags =				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));			goto next;		}		skb = bp->rx_skbs[elem];		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 == NULL) {				drops++;				goto drop_it;			}			sbus_unmap_single(bp->bigmac_sdev,					  this->rx_addr,					  RX_BUF_ALLOC_SIZE - 34,					  SBUS_DMA_FROMDEVICE);			bp->rx_skbs[elem] = new_skb;			new_skb->dev = bp->dev;			skb_put(new_skb, ETH_FRAME_LEN);			skb_reserve(new_skb, 34);			this->rx_addr = sbus_map_single(bp->bigmac_sdev,							new_skb->data,							RX_BUF_ALLOC_SIZE - 34,							SBUS_DMA_FROMDEVICE);			this->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 == NULL) {				drops++;				goto drop_it;			}			copy_skb->dev = bp->dev;			skb_reserve(copy_skb, 2);			skb_put(copy_skb, len);			sbus_dma_sync_single(bp->bigmac_sdev,					     this->rx_addr, len, SBUS_DMA_FROMDEVICE);			eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0);			/* Reuse original ring buffer. */			this->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++;		bp->enet_stats.rx_bytes += len;	next:		elem = NEXT_RX(elem);

⌨️ 快捷键说明

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