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

📄 rtl8139.c.1

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 1
📖 第 1 页 / 共 3 页
字号:
			}		}		if (phy_idx == 0) {			printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "				   "transceiver.\n",				   dev->name);			tp->phys[0] = -1;		}	} else {			tp->phys[0] = 32;	}	/* Put the chip into low-power mode. */	outb(0xC0, ioaddr + Cfg9346);	outb(0x03, ioaddr + Config1);	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */	/* The lower four bits are the media type. */	if (option > 0) {		tp->full_duplex = (option & 0x200) ? 1 : 0;		tp->default_port = option & 15;		if (tp->default_port)			tp->medialock = 1;	}	if (found_cnt < MAX_UNITS  &&  full_duplex[found_cnt] > 0)		tp->full_duplex = full_duplex[found_cnt];	if (tp->full_duplex) {		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);		mdio_write(dev, tp->phys[0], 4, 0x141);		tp->duplex_lock = 1;	}	/* The Rtl8129-specific entries in the device structure. */	dev->open = &rtl8129_open;	dev->hard_start_xmit = &rtl8129_start_xmit;	dev->stop = &rtl8129_close;	dev->get_stats = &rtl8129_get_stats;	dev->set_multicast_list = &set_rx_mode;	dev->do_ioctl = &mii_ioctl;	return dev;}/* Serial EEPROM section. *//*  EEPROM_Ctrl bits. */#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */#define EE_CS			0x08	/* EEPROM chip select. */#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */#define EE_WRITE_0		0x00#define EE_WRITE_1		0x02#define EE_DATA_READ	0x01	/* EEPROM chip data out. */#define EE_ENB			(0x80 | EE_CS)/* Delay between EEPROM clock transitions.   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. */#define eeprom_delay()	inl(ee_addr)/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD	(5 << 6)#define EE_READ_CMD		(6 << 6)#define EE_ERASE_CMD	(7 << 6)static int read_eeprom(long ioaddr, int location){	int i;	unsigned retval = 0;	long ee_addr = ioaddr + Cfg9346;	int read_cmd = location | EE_READ_CMD;	outb(EE_ENB & ~EE_CS, ee_addr);	outb(EE_ENB, ee_addr);	/* Shift the read command bits out. */	for (i = 10; i >= 0; i--) {		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;		outb(EE_ENB | dataval, ee_addr);		eeprom_delay();		outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);		eeprom_delay();	}	outb(EE_ENB, ee_addr);	eeprom_delay();	for (i = 16; i > 0; i--) {		outb(EE_ENB | EE_SHIFT_CLK, ee_addr);		eeprom_delay();		retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);		outb(EE_ENB, ee_addr);		eeprom_delay();	}	/* Terminate the EEPROM access. */	outb(~EE_CS, ee_addr);	return retval;}/* MII serial management: mostly bogus for now. *//* Read and write the MII management registers using software-generated   serial MDIO protocol.   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually   met by back-to-back PCI I/O cycles, but we insert a delay to avoid   "overclocking" issues. */#define MDIO_DIR		0x80#define MDIO_DATA_OUT	0x04#define MDIO_DATA_IN	0x02#define MDIO_CLK		0x01#define MDIO_WRITE0 (MDIO_DIR)#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)#define mdio_delay()	inb(mdio_addr)static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert,								 NWayLPAR, NWayExpansion, 0 };/* Syncronize the MII management interface by shifting 32 one bits out. */static void mdio_sync(long mdio_addr){	int i;	for (i = 32; i >= 0; i--) {		outb(MDIO_WRITE1, mdio_addr);		mdio_delay();		outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);		mdio_delay();	}	return;}static int mdio_read(struct device *dev, int phy_id, int location){	long mdio_addr = dev->base_addr + MII_SMI;	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;	int retval = 0;	int i;	if ((phy_id & 0x1f) == 0) {	/* Really a 8139.  Use internal registers. */		return location < 8 && mii_2_8139_map[location] ?			inw(dev->base_addr + mii_2_8139_map[location]) : 0;	}	mdio_sync(mdio_addr);	/* Shift the read command bits out. */	for (i = 15; i >= 0; i--) {		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;		outb(MDIO_DIR | dataval, mdio_addr);		mdio_delay();		outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);		mdio_delay();	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 19; i > 0; i--) {		outb(0, mdio_addr);		mdio_delay();		retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0);		outb(MDIO_CLK, mdio_addr);		mdio_delay();	}	return (retval>>1) & 0xffff;}static void mdio_write(struct device *dev, int phy_id, int location, int value){	long mdio_addr = dev->base_addr + MII_SMI;	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;	int i;	if (phy_id == 32) {			/* Really a 8139.  Use internal registers. */		if (location < 8  &&  mii_2_8139_map[location])			outw(value, dev->base_addr + mii_2_8139_map[location]);		return;	}	mdio_sync(mdio_addr);	/* Shift the command bits out. */	for (i = 31; i >= 0; i--) {		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;		outb(dataval, mdio_addr);		mdio_delay();		outb(dataval | MDIO_CLK, mdio_addr);		mdio_delay();	}	/* Clear out extra bits. */	for (i = 2; i > 0; i--) {		outb(0, mdio_addr);		mdio_delay();		outb(MDIO_CLK, mdio_addr);		mdio_delay();	}	return;}static intrtl8129_open(struct device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	int i;	/* Soft reset the chip. */	outb(CmdReset, ioaddr + ChipCmd);	if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) {		return -EAGAIN;	}	request_irq(14, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev);	request_irq(9, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev);	request_irq(11, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev);	MOD_INC_USE_COUNT;	tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);	tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL);	if (tp->tx_bufs == NULL ||  tp->rx_ring == NULL) {		if (tp->tx_bufs)			kfree(tp->tx_bufs);		if (rtl8129_debug > 0)			printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n",				   dev->name, RX_BUF_LEN);		return -ENOMEM;	}	rtl8129_init_ring(dev);	/* Check that the chip has finished the reset. */	for (i = 1000; i > 0; i--)		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)			break;	for (i = 0; i < 6; i++)		outb(dev->dev_addr[i], ioaddr + MAC0 + i);	/* Must enable Tx/Rx before setting transfer thresholds! */	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),		 ioaddr + RxConfig);	outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);	tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000;	tp->full_duplex = tp->duplex_lock;	if (tp->phys[0] >= 0  ||  (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) {		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);		if (mii_reg5 == 0xffff)			;					/* Not there */		else if ((mii_reg5 & 0x0100) == 0x0100				 || (mii_reg5 & 0x00C0) == 0x0040)			tp->full_duplex = 1;		if (rtl8129_debug > 1)			printk(KERN_INFO"%s: Setting %s%s-duplex based on"				   " auto-negotiated partner ability %4.4x.\n", dev->name,				   mii_reg5 == 0 ? "" :				   (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",				   tp->full_duplex ? "full" : "half", mii_reg5);	}	outb(0xC0, ioaddr + Cfg9346);	outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);	outb(0x00, ioaddr + Cfg9346);	outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf);	/* Start the chip's Tx and Rx process. */	outl(0, ioaddr + RxMissed);	set_rx_mode(dev);	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);	dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 1;	/* Enable all known interrupts by setting the interrupt mask. */	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver		| TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);	if (rtl8129_debug > 1)		printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"			   " GP Pins %2.2x %s-duplex.\n",			   dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),			   tp->full_duplex ? "full" : "half");	/* Set the timer to switch to check for link beat and perhaps switch	   to an alternate media type. */	init_timer(&tp->timer);	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */	tp->timer.data = (unsigned long)dev;	tp->timer.function = &rtl8129_timer;				/* timer handler */	add_timer(&tp->timer);	return 0;}static void rtl8129_timer(unsigned long data){	struct device *dev = (struct device *)data;	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	int next_tick = 0;	int mii_reg5 = mdio_read(dev, tp->phys[0], 5);	printk("inside rtl8129_timer\n");	if (! tp->duplex_lock  &&  mii_reg5 != 0xffff) {		int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;		if (tp->full_duplex != duplex) {			tp->full_duplex = duplex;			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"				   " partner ability of %4.4x.\n", dev->name,				   tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5);			outb(0xC0, ioaddr + Cfg9346);			outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);			outb(0x00, ioaddr + Cfg9346);		}		next_tick = 60*HZ;	}	if (rtl8129_debug > 2) {		if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)			printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",				   dev->name, inb(ioaddr + GPPinData));		else			printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n",				   dev->name, inw(ioaddr + NWayLPAR));		printk(KERN_DEBUG"%s:  Other registers are IntMask %4.4x IntStatus %4.4x"			   " RxStatus %4.4x.\n",			   dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus),			   inl(ioaddr + RxEarlyStatus));		printk(KERN_DEBUG"%s:  Chip config %2.2x %2.2x.\n",			   dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));	}	if (next_tick) {		tp->timer.expires = RUN_AT(next_tick);		add_timer(&tp->timer);	}}static void rtl8129_tx_timeout(struct device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	int mii_reg, i;	if (rtl8129_debug > 0)		printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x "			   "media %2.2x.\n",			   dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus),			   inb(ioaddr + GPPinData));	/* Disable interrupts by clearing the interrupt mask. */	outw(0x0000, ioaddr + IntrMask);	/* Emit info to figure out what went wrong. */	printk("%s: Tx queue start entry %d  dirty entry %d.\n",		   dev->name, tp->cur_tx, tp->dirty_tx);	for (i = 0; i < NUM_TX_DESC; i++)		printk(KERN_DEBUG"%s:  Tx descriptor %d is %8.8x.%s\n",			   dev->name, i, inl(ioaddr + TxStatus0 + i*4),			   i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");	printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]);	for (mii_reg = 0; mii_reg < 8; mii_reg++)		printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg));	printk(".\n");	/* Soft reset the chip. */	outb(CmdReset, ioaddr + ChipCmd);	/* Check that the chip has finished the reset. */	for (i = 1000; i > 0; i--)		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)			break;	for (i = 0; i < 6; i++)		outb(dev->dev_addr[i], ioaddr + MAC0 + i);	outb(0x00, ioaddr + Cfg9346);	tp->cur_rx = 0;	/* Must enable Tx/Rx before setting transfer thresholds! */	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),		 ioaddr + RxConfig);	outl((TX_DMA_BURST<<8), ioaddr + TxConfig);	set_rx_mode(dev);	{							/* Save the unsent Tx packets. */		struct sk_buff *saved_skb[NUM_TX_DESC], *skb;		int j;		for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++)			saved_skb[j] = tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC];		tp->dirty_tx = tp->cur_tx = 0;		for (i = 0; i < j; i++) {			skb = tp->tx_skbuff[i] = saved_skb[i];			if ((long)skb->data & 3) {		/* Must use alignment buffer. */				memcpy(tp->tx_buf[i], skb->data, skb->len);				outl(virt_to_bus(tp->tx_buf[i]), ioaddr + TxAddr0 + i*4);			} else				outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + i*4);			/* Note: the chip doesn't have auto-pad! */			outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),				 ioaddr + TxStatus0 + i*4);		}		tp->cur_tx = i;		while (i < NUM_TX_DESC)			tp->tx_skbuff[i] = 0;		if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */			dev->tbusy = 0;			tp->tx_full = 0;		} else {			tp->tx_full = 1;		}	}	dev->trans_start = jiffies;	tp->stats.tx_errors++;	/* Enable all known interrupts by setting the interrupt mask. */	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);	return;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static voidrtl8129_init_ring(struct device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	int i;	tp->tx_full = 0;	tp->cur_rx = 0;	tp->dirty_tx = tp->cur_tx = 0;	for (i = 0; i < NUM_TX_DESC; i++) {		tp->tx_skbuff[i] = 0;		tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE];	}}static intrtl8129_start_xmit(struct sk_buff *skb, struct device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	int entry;	printk("start rtl8129_start_xmit\n");	/* Block a timer-based transmit from overlapping.  This could better be	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {		if (jiffies - dev->trans_start < TX_TIMEOUT)			return 1;		rtl8129_tx_timeout(dev);		return 1;	}	/* Calculate the next Tx descriptor entry. */	entry = tp->cur_tx % NUM_TX_DESC;	tp->tx_skbuff[entry] = skb;	if ((long)skb->data & 3) {			/* Must use alignment buffer. */		memcpy(tp->tx_buf[entry], skb->data, skb->len);		outl(virt_to_bus(tp->tx_buf[entry]), ioaddr + TxAddr0 + entry*4);	} else		outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4);	/* Note: the chip doesn't have auto-pad! */	outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),		 ioaddr + TxStatus0 + entry*4);	if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */		clear_bit(0, (void*)&dev->tbusy);	} else {		tp->tx_full = 1;	}	dev->trans_start = jiffies;	if (rtl8129_debug > 4)

⌨️ 快捷键说明

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