eth_v10.c

来自「linux 内核源代码」· C语言 代码 · 共 1,954 行 · 第 1/4 页

C
1,954
字号
	if (autoneg_normal) {	  data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR);	data |= BMCR_ANENABLE | BMCR_ANRESTART;	}	e100_set_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR, data);}static voide100_set_speed(struct net_device* dev, unsigned long speed){	struct net_local *np = netdev_priv(dev);	spin_lock(&np->transceiver_lock);	if (speed != current_speed_selection) {		current_speed_selection = speed;		e100_negotiate(dev);	}	spin_unlock(&np->transceiver_lock);}static voide100_check_duplex(unsigned long priv){	struct net_device *dev = (struct net_device *)priv;	struct net_local *np = netdev_priv(dev);	int old_duplex;	spin_lock(&np->transceiver_lock);	old_duplex = full_duplex;	transceiver->check_duplex(dev);	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;	spin_unlock(&np->transceiver_lock);}#if defined(CONFIG_ETRAX_NO_PHY)static voiddummy_check_duplex(struct net_device* dev){	full_duplex = 1;}#elsestatic voidgeneric_check_duplex(struct net_device* dev){	unsigned long data;	struct net_local *np = netdev_priv(dev);	data = e100_get_mdio_reg(dev, np->mii_if.phy_id, 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;	struct net_local *np = netdev_priv(dev);	data = e100_get_mdio_reg(dev, np->mii_if.phy_id,				 MDIO_TDK_DIAGNOSTIC_REG);	full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0;}static voidbroadcom_check_duplex(struct net_device* dev){	unsigned long data;	struct net_local *np = netdev_priv(dev);	data = e100_get_mdio_reg(dev, np->mii_if.phy_id,				 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;	struct net_local *np = netdev_priv(dev);	data = e100_get_mdio_reg(dev, np->mii_if.phy_id,				 MDIO_INT_STATUS_REG_2);	full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0;}#endifstatic voide100_set_duplex(struct net_device* dev, enum duplex new_duplex){	struct net_local *np = netdev_priv(dev);	spin_lock(&np->transceiver_lock);	if (new_duplex != current_duplex) {		current_duplex = new_duplex;		e100_negotiate(dev);	}	spin_unlock(&np->transceiver_lock);}static inte100_probe_transceiver(struct net_device* dev){	int ret = 0;#if !defined(CONFIG_ETRAX_NO_PHY)	unsigned int phyid_high;	unsigned int phyid_low;	unsigned int oui;	struct transceiver_ops* ops = NULL;	struct net_local *np = netdev_priv(dev);	spin_lock(&np->transceiver_lock);	/* Probe MDIO physical address */	for (np->mii_if.phy_id = 0; np->mii_if.phy_id <= 31;	     np->mii_if.phy_id++) {		if (e100_get_mdio_reg(dev,				      np->mii_if.phy_id, MII_BMSR) != 0xffff)			break;	}	if (np->mii_if.phy_id == 32) {		ret = -ENODEV;		goto out;	}	/* Get manufacturer */	phyid_high = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_PHYSID1);	phyid_low = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_PHYSID2);	oui = (phyid_high << 6) | (phyid_low >> 10);	for (ops = &transceivers[0]; ops->oui; ops++) {		if (ops->oui == oui)			break;	}	transceiver = ops;out:	spin_unlock(&np->transceiver_lock);#endif	return ret;}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){	struct net_local *np = netdev_priv(dev);	unsigned short cmd;	unsigned short data;	int bitCounter;	data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR);	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (np->mii_if.phy_id << 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 = netdev_priv(dev);	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 = netdev_priv(dev);	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(np, 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 net_device *dev = (struct net_device *)dev_id;	struct net_local *np = netdev_priv(dev);	unsigned long irqbits;	/*	 * Note that both rx and tx interrupts are blocked at this point,	 * regardless of which got us here.	 */	irqbits = *R_IRQ_MASK2_RD;	/* 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);			np->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 (virt_to_phys(myFirstTxDesc) != *R_DMA_CH0_FIRST &&	       (netif_queue_stopped(dev) || 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);                /* Wake up queue. */		netif_wake_queue(dev);	}	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {		/* acknowledge the eop interrupt. */		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);	}	return IRQ_HANDLED;}static irqreturn_te100nw_interrupt(int irq, void *dev_id){	struct net_device *dev = (struct net_device *)dev_id;	struct net_local *np = netdev_priv(dev);	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);		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 = netdev_priv(dev);	unsigned char *skb_data_ptr;#ifdef ETHDEBUG	int i;#endif	etrax_eth_descr *prevRxDesc;  /* The descriptor right before myNextRxDesc */	spin_lock(&np->led_lock);	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);	}	spin_unlock(&np->led_lock);	length = myNextRxDesc->descr.hw_len - 4;	np->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);			goto update_nextrxdesc;

⌨️ 快捷键说明

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