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

📄 eth_v10.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (old_duplex != full_duplex) {		/* Duplex changed */		SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);		*R_NETWORK_REC_CONFIG = network_rec_config_shadow;	}	/* Reinitialize the timer. */	duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;	add_timer(&duplex_timer);	np->mii_if.full_duplex = full_duplex;}static voidgeneric_check_duplex(struct net_device* dev){	unsigned long data;	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);	if ((data & ADVERTISE_10FULL) ||	    (data & ADVERTISE_100FULL))		full_duplex = 1;	else		full_duplex = 0;}static voidtdk_check_duplex(struct net_device* dev){	unsigned long data;	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);	full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0;}static voidbroadcom_check_duplex(struct net_device* dev){	unsigned long data;	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);	full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0;}static voidintel_check_duplex(struct net_device* dev){	unsigned long data;	data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);	full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0;}static voide100_set_duplex(struct net_device* dev, enum duplex new_duplex){	if (new_duplex != current_duplex) {		current_duplex = new_duplex;		e100_negotiate(dev);	}}static inte100_probe_transceiver(struct net_device* dev){	unsigned int phyid_high;	unsigned int phyid_low;	unsigned int oui;	struct transceiver_ops* ops = NULL;	/* Probe MDIO physical address */	for (mdio_phy_addr = 0; mdio_phy_addr <= 31; mdio_phy_addr++) {		if (e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR) != 0xffff)			break;	}	if (mdio_phy_addr == 32)		 return -ENODEV;	/* Get manufacturer */	phyid_high = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID1);	phyid_low = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID2);	oui = (phyid_high << 6) | (phyid_low >> 10);	for (ops = &transceivers[0]; ops->oui; ops++) {		if (ops->oui == oui)			break;	}	transceiver = ops;	return 0;}static inte100_get_mdio_reg(struct net_device *dev, int phy_id, int location){	unsigned short cmd;    /* Data to be sent on MDIO port */	int data;   /* Data read from MDIO */	int bitCounter;	/* Start of frame, OP Code, Physical Address, Register Address */	cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (phy_id << 7) |		(location << 2);	e100_send_mdio_cmd(cmd, 0);	data = 0;	/* Data... */	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {		data |= (e100_receive_mdio_bit() << bitCounter);	}	return data;}static voide100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value){	int bitCounter;	unsigned short cmd;	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (phy_id << 7) |	      (location << 2);	e100_send_mdio_cmd(cmd, 1);	/* Data... */	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {		e100_send_mdio_bit(GET_BIT(bitCounter, value));	}}static voide100_send_mdio_cmd(unsigned short cmd, int write_cmd){	int bitCounter;	unsigned char data = 0x2;	/* Preamble */	for (bitCounter = 31; bitCounter>= 0; bitCounter--)		e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE));	for (bitCounter = 15; bitCounter >= 2; bitCounter--)		e100_send_mdio_bit(GET_BIT(bitCounter, cmd));	/* Turnaround */	for (bitCounter = 1; bitCounter >= 0 ; bitCounter--)		if (write_cmd)			e100_send_mdio_bit(GET_BIT(bitCounter, data));		else			e100_receive_mdio_bit();}static voide100_send_mdio_bit(unsigned char bit){	*R_NETWORK_MGM_CTRL =		IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) |		IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit);	udelay(1);	*R_NETWORK_MGM_CTRL =		IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) |		IO_MASK(R_NETWORK_MGM_CTRL, mdck) |		IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit);	udelay(1);}static unsigned chare100_receive_mdio_bit(){	unsigned char bit;	*R_NETWORK_MGM_CTRL = 0;	bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT);	udelay(1);	*R_NETWORK_MGM_CTRL = IO_MASK(R_NETWORK_MGM_CTRL, mdck);	udelay(1);	return bit;}static voide100_reset_transceiver(struct net_device* dev){	unsigned short cmd;	unsigned short data;	int bitCounter;	data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (MII_BMCR << 2);	e100_send_mdio_cmd(cmd, 1);	data |= 0x8000;	for (bitCounter = 15; bitCounter >= 0 ; bitCounter--) {		e100_send_mdio_bit(GET_BIT(bitCounter, data));	}}/* Called by upper layers if they decide it took too long to complete * sending a packet - we need to reset and stuff. */static voide100_tx_timeout(struct net_device *dev){	struct net_local *np = (struct net_local *)dev->priv;	unsigned long flags;	spin_lock_irqsave(&np->lock, flags);	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,	       tx_done(dev) ? "IRQ problem" : "network cable problem");	/* remember we got an error */	np->stats.tx_errors++;	/* reset the TX DMA in case it has hung on something */	RESET_DMA(NETWORK_TX_DMA_NBR);	WAIT_DMA(NETWORK_TX_DMA_NBR);	/* Reset the transceiver. */	e100_reset_transceiver(dev);	/* and get rid of the packets that never got an interrupt */	while (myFirstTxDesc != myNextTxDesc)	{		dev_kfree_skb(myFirstTxDesc->skb);		myFirstTxDesc->skb = 0;		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);	}	/* Set up transmit DMA channel so it can be restarted later */	*R_DMA_CH0_FIRST = 0;	*R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);	/* tell the upper layers we're ok again */	netif_wake_queue(dev);	spin_unlock_irqrestore(&np->lock, flags);}/* This will only be invoked if the driver is _not_ in XOFF state. * What this means is that we need not check it, and that this * invariant will hold if we make sure that the netif_*_queue() * calls are done at the proper times. */static inte100_send_packet(struct sk_buff *skb, struct net_device *dev){	struct net_local *np = (struct net_local *)dev->priv;	unsigned char *buf = skb->data;	unsigned long flags;#ifdef ETHDEBUG	printk("send packet len %d\n", length);#endif	spin_lock_irqsave(&np->lock, flags);  /* protect from tx_interrupt and ourself */	myNextTxDesc->skb = skb;	dev->trans_start = jiffies;	e100_hardware_send_packet(buf, skb->len);	myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next);	/* Stop queue if full */	if (myNextTxDesc == myFirstTxDesc) {		netif_stop_queue(dev);	}	spin_unlock_irqrestore(&np->lock, flags);	return 0;}/* * The typical workload of the driver: *   Handle the network interface interrupts. */static irqreturn_te100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct net_device *dev = (struct net_device *)dev_id;	struct net_local *np = (struct net_local *)dev->priv;	unsigned long irqbits = *R_IRQ_MASK2_RD;	/* Disable RX/TX IRQs to avoid reentrancy */	*R_IRQ_MASK2_CLR =	  IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |	  IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);	/* Handle received packets */	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {		/* acknowledge the eop interrupt */		*R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);		/* check if one or more complete packets were indeed received */		while ((*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) &&		       (myNextRxDesc != myLastRxDesc)) {			/* Take out the buffer and give it to the OS, then			 * allocate a new buffer to put a packet in.			 */			e100_rx(dev);			((struct net_local *)dev->priv)->stats.rx_packets++;			/* restart/continue on the channel, for safety */			*R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart);			/* clear dma channel 1 eop/descr irq bits */			*R_DMA_CH1_CLR_INTR =				IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) |				IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do);			/* now, we might have gotten another packet			   so we have to loop back and check if so */		}	}	/* Report any packets that have been sent */	while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&	       myFirstTxDesc != myNextTxDesc)	{		np->stats.tx_bytes += myFirstTxDesc->skb->len;		np->stats.tx_packets++;		/* dma is ready with the transmission of the data in tx_skb, so now		   we can release the skb memory */		dev_kfree_skb_irq(myFirstTxDesc->skb);		myFirstTxDesc->skb = 0;		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);	}	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {		/* acknowledge the eop interrupt and wake up queue */		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);		netif_wake_queue(dev);	}	/* Enable RX/TX IRQs again */	*R_IRQ_MASK2_SET =	  IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |	  IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);	return IRQ_HANDLED;}static irqreturn_te100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct net_device *dev = (struct net_device *)dev_id;	struct net_local *np = (struct net_local *)dev->priv;	unsigned long irqbits = *R_IRQ_MASK0_RD;	/* check for underrun irq */	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) {		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);		*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);		np->stats.tx_errors++;		D(printk("ethernet receiver underrun!\n"));	}	/* check for overrun irq */	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) {		update_rx_stats(&np->stats); /* this will ack the irq */		D(printk("ethernet receiver overrun!\n"));	}	/* check for excessive collision irq */	if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) {		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);		*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;		SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);		*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);		np->stats.tx_errors++;		D(printk("ethernet excessive collisions!\n"));	}	return IRQ_HANDLED;}/* We have a good packet(s), get it/them out of the buffers. */static voide100_rx(struct net_device *dev){	struct sk_buff *skb;	int length = 0;	struct net_local *np = (struct net_local *)dev->priv;	unsigned char *skb_data_ptr;#ifdef ETHDEBUG	int i;#endif	if (!led_active && time_after(jiffies, led_next_time)) {		/* light the network leds depending on the current speed. */		e100_set_network_leds(NETWORK_ACTIVITY);		/* Set the earliest time we may clear the LED */		led_next_time = jiffies + NET_FLASH_TIME;		led_active = 1;		mod_timer(&clear_led_timer, jiffies + HZ/10);	}	length = myNextRxDesc->descr.hw_len - 4;	((struct net_local *)dev->priv)->stats.rx_bytes += length;#ifdef ETHDEBUG	printk("Got a packet of length %d:\n", length);	/* dump the first bytes in the packet */	skb_data_ptr = (unsigned char *)phys_to_virt(myNextRxDesc->descr.buf);	for (i = 0; i < 8; i++) {		printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8,		       skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3],		       skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]);		skb_data_ptr += 8;	}#endif	if (length < RX_COPYBREAK) {		/* Small packet, copy data */		skb = dev_alloc_skb(length - ETHER_HEAD_LEN);		if (!skb) {			np->stats.rx_errors++;			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);			return;		}		skb_put(skb, length - ETHER_HEAD_LEN);        /* allocate room for the packet body */		skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */#ifdef ETHDEBUG		printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n",		  skb->head, skb->data, skb->tail, skb->end);		printk("copying packet to 0x%x.\n", skb_data_ptr);#endif		memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length);	}	else {		/* Large packet, send directly to upper layers and allocate new		 * memory (aligned to cache line boundary to avoid bug).		 * Before sending the skb to upper layers we must make sure that		 * skb->data points to the aligned start of the packet.		 */		int align;		struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);		if (!new_skb) {			np->stats.rx_errors++;			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);			return;		}		skb = myNextRxDesc->skb;		align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;		skb_put(skb, length + align);		skb_pull(skb, align); /* Remove alignment bytes */		myNextRxDesc->skb = new_skb;

⌨️ 快捷键说明

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