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

📄 hamachi.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
03/14/2000 KDU Further tuning:  	-adjusted boguscnt in hamachi_rx() to depend on interrupt	mitigation parameters chosen.	-Selected a set of interrupt parameters based on some extensive testing.  	These may change with more testing.TO DO:-Consider borrowing from the acenic driver code to check PCI_COMMAND forPCI_COMMAND_INVALIDATE.  Set maximum burst size to cache line size inthat case.-fix the reset procedure.  It doesn't quite work.  *//* A few values that may be tweaked. *//* Size of each temporary Rx buffer, calculated as: * 1518 bytes (ethernet packet) + 2 bytes (to get 8 byte alignment for * the card) + 8 bytes of status info + 8 bytes for the Rx Checksum + * 2 more because we use skb_reserve.   */#define PKT_BUF_SZ		1538/* For now, this is going to be set to the maximum size of an ethernet * packet.  Eventually, we may want to make it a variable that is * related to the MTU */#define MAX_FRAME_SIZE  1518/* The rest of these values should never change. */static void hamachi_timer(unsigned long data);enum capability_flags {CanHaveMII=1, };static struct chip_info {	u16	vendor_id, device_id, device_id_mask, pad;	const char *name;	void (*media_timer)(unsigned long data);	int flags;} chip_tbl[] = {	{0x1318, 0x0911, 0xffff, 0, "Hamachi GNIC-II", hamachi_timer, 0},	{0,},};/* Offsets to the Hamachi registers.  Various sizes. */enum hamachi_offsets {	TxDMACtrl=0x00, TxCmd=0x04, TxStatus=0x06, TxPtr=0x08, TxCurPtr=0x10,	RxDMACtrl=0x20, RxCmd=0x24, RxStatus=0x26, RxPtr=0x28, RxCurPtr=0x30,	PCIClkMeas=0x060, MiscStatus=0x066, ChipRev=0x68, ChipReset=0x06B,	LEDCtrl=0x06C, VirtualJumpers=0x06D, GPIO=0x6E,	TxChecksum=0x074, RxChecksum=0x076,	TxIntrCtrl=0x078, RxIntrCtrl=0x07C,	InterruptEnable=0x080, InterruptClear=0x084, IntrStatus=0x088,	EventStatus=0x08C,	MACCnfg=0x0A0, FrameGap0=0x0A2, FrameGap1=0x0A4,	/* See enum MII_offsets below. */	MACCnfg2=0x0B0, RxDepth=0x0B8, FlowCtrl=0x0BC, MaxFrameSize=0x0CE,	AddrMode=0x0D0, StationAddr=0x0D2,	/* Gigabit AutoNegotiation. */	ANCtrl=0x0E0, ANStatus=0x0E2, ANXchngCtrl=0x0E4, ANAdvertise=0x0E8,	ANLinkPartnerAbility=0x0EA,	EECmdStatus=0x0F0, EEData=0x0F1, EEAddr=0x0F2,	FIFOcfg=0x0F8,};/* Offsets to the MII-mode registers. */enum MII_offsets {	MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC,	MII_Status=0xAE,};/* Bits in the interrupt status/mask registers. */enum intr_status_bits {	IntrRxDone=0x01, IntrRxPCIFault=0x02, IntrRxPCIErr=0x04,	IntrTxDone=0x100, IntrTxPCIFault=0x200, IntrTxPCIErr=0x400,	LinkChange=0x10000, NegotiationChange=0x20000, StatsMax=0x40000, };/* The Hamachi Rx and Tx buffer descriptors. */struct hamachi_desc {	u32 status_n_length;			#if ADDRLEN == 64	u32 pad;	u64 addr;#else	u32 addr;#endif};/* Bits in hamachi_desc.status_n_length */enum desc_status_bits {	DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000, 	DescIntr=0x10000000,};#define PRIV_ALIGN   15    				/* Required alignment mask */struct hamachi_private {	/* Descriptor rings first for alignment.  Tx requires a second descriptor	   for status. */	struct hamachi_desc rx_ring[RX_RING_SIZE];	struct hamachi_desc tx_ring[TX_RING_SIZE];	/* The addresses of receive-in-place skbuffs. */	struct sk_buff* rx_skbuff[RX_RING_SIZE];	/* The saved address of a sent-in-place packet/buffer, for skfree(). */	struct sk_buff* tx_skbuff[TX_RING_SIZE];	struct net_device_stats stats;	struct timer_list timer;				/* Media selection timer. */	/* Frequently used and paired value: keep adjacent for cache effect. */	spinlock_t lock;	int chip_id;	struct hamachi_desc *rx_head_desc;	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */	unsigned int cur_tx, dirty_tx;	unsigned int rx_buf_sz;					/* Based on MTU+slack. */	unsigned int tx_full:1;					/* The Tx queue is full. */	unsigned int full_duplex:1;			/* Full-duplex operation requested. */	unsigned int duplex_lock:1;	unsigned int medialock:1;				/* Do not sense media. */	unsigned int default_port:4;			/* Last dev->if_port value. */	/* MII transceiver section. */	int mii_cnt;								/* MII device addresses. */	u16 advertising;							/* NWay media advertisement */	unsigned char phys[2];					/* MII device addresses. */	u_int32_t rx_int_var, tx_int_var;	/* interrupt control variables */	u_int32_t option;							/* Hold on to a copy of the options */	u_int8_t pad[16];							/* Used for 32-byte alignment */};MODULE_AUTHOR("Donald Becker <becker@scyld.com>, Eric Kasten <kasten@nscl.msu.edu>, Keith Underwood <keithu@parl.clemson.edu>");MODULE_DESCRIPTION("Packet Engines 'Hamachi' GNIC-II Gigabit Ethernet driver");MODULE_PARM(max_interrupt_work, "i");MODULE_PARM(mtu, "i");MODULE_PARM(debug, "i");MODULE_PARM(min_rx_pkt, "i");MODULE_PARM(max_rx_gap, "i");MODULE_PARM(max_rx_latency, "i");MODULE_PARM(min_tx_pkt, "i");MODULE_PARM(max_tx_gap, "i");MODULE_PARM(max_tx_latency, "i");MODULE_PARM(rx_copybreak, "i");MODULE_PARM(rx_params, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(tx_params, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(force32, "i");static int read_eeprom(long ioaddr, int location);static int mdio_read(long ioaddr, int phy_id, int location);static void mdio_write(long ioaddr, int phy_id, int location, int value);static int hamachi_open(struct net_device *dev);#ifdef HAVE_PRIVATE_IOCTLstatic int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);#endifstatic void hamachi_timer(unsigned long data);static void hamachi_tx_timeout(struct net_device *dev);static void hamachi_init_ring(struct net_device *dev);static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev);static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static inline int hamachi_rx(struct net_device *dev);static inline int hamachi_tx(struct net_device *dev);static void hamachi_error(struct net_device *dev, int intr_status);static int hamachi_close(struct net_device *dev);static struct net_device_stats *hamachi_get_stats(struct net_device *dev);static void set_rx_mode(struct net_device *dev);static int __init hamachi_init_one (struct pci_dev *pdev,				    const struct pci_device_id *ent){	static int did_version = 0;			/* Already printed version info. */	struct hamachi_private *hmp;	int option, i, rx_int_var, tx_int_var, boguscnt;	int chip_id = ent->driver_data;	int irq = pdev->irq;	long ioaddr;	static int card_idx = 0;	struct net_device *dev;	if (hamachi_debug > 0  &&  did_version++ == 0)		printk(version);	ioaddr = pci_resource_start(pdev, 0);#ifdef __alpha__				/* Really "64 bit addrs" */	ioaddr |= (pci_resource_start(pdev, 1) << 32);#endif	if (pci_enable_device(pdev))		return -EIO;	pci_set_master(pdev);	ioaddr = (long) ioremap(ioaddr, 0x400);	if (!ioaddr)		return -ENOMEM;	dev = init_etherdev(NULL, sizeof(struct hamachi_private));	if (!dev) {		iounmap((char *)ioaddr);		return -ENOMEM;	}	SET_MODULE_OWNER(dev);#ifdef TX_CHECKSUM	printk("check that skbcopy in ip_queue_xmit isn't happening\n");	dev->hard_header_len += 8;  /* for cksum tag */#endif	printk(KERN_INFO "%s: %s type %x at 0x%lx, ",		   dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev),		   ioaddr);	for (i = 0; i < 6; i++)		dev->dev_addr[i] = 1 ? read_eeprom(ioaddr, 4 + i)			: readb(ioaddr + StationAddr + i);	for (i = 0; i < 5; i++)			printk("%2.2x:", dev->dev_addr[i]);	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);#if ! defined(final_version)	if (hamachi_debug > 4)		for (i = 0; i < 0x10; i++)			printk("%2.2x%s",				   read_eeprom(ioaddr, i), i % 16 != 15 ? " " : "\n");#endif#if 0 /* Moving this until after the force 32 check and reset. */	i = readb(ioaddr + PCIClkMeas);	printk(KERN_INFO "%s:  %d-bit %d Mhz PCI bus (%d), Virtual Jumpers "		   "%2.2x, LPA %4.4x.\n",		   dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32,		   i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers),		   readw(ioaddr + ANLinkPartnerAbility));#endif	hmp = dev->priv;	spin_lock_init(&hmp->lock);	/* Check for options being passed in */	option = card_idx < MAX_UNITS ? options[card_idx] : 0;	if (dev->mem_start)		option = dev->mem_start;	/* If the bus size is misidentified, do the following. */	force32 = force32 ? force32 : 		((option  >= 0) ? ((option & 0x00000070) >> 4) : 0 );	if (force32)		writeb(force32, ioaddr + VirtualJumpers);	/* Hmmm, do we really need to reset the chip???. */	writeb(0x01, ioaddr + ChipReset);	/* After a reset, the clock speed measurement of the PCI bus will not	 * be valid for a moment.  Wait for a little while until it is.  If	 * it takes more than 10ms, forget it.	 */	udelay(10);		i = readb(ioaddr + PCIClkMeas);	for (boguscnt = 0; (!(i & 0x080)) && boguscnt < 1000; boguscnt++){		udelay(10);			i = readb(ioaddr + PCIClkMeas);		}	printk(KERN_INFO "%s:  %d-bit %d Mhz PCI bus (%d), Virtual Jumpers "		   "%2.2x, LPA %4.4x.\n",		   dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32,		   i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers),		   readw(ioaddr + ANLinkPartnerAbility));	dev->base_addr = ioaddr;	dev->irq = irq;	hmp->chip_id = chip_id;	/* The lower four bits are the media type. */	if (option > 0) {		hmp->option = option;		if (option & 0x200)			hmp->full_duplex = 1;		else if (option & 0x080)			hmp->full_duplex = 0;		hmp->default_port = option & 15;		if (hmp->default_port)			hmp->medialock = 1;	}	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)		hmp->full_duplex = 1;	/* lock the duplex mode if someone specified a value */	if (hmp->full_duplex || (option & 0x080))		hmp->duplex_lock = 1;	/* Set interrupt tuning parameters */	max_rx_latency = max_rx_latency & 0x00ff;	max_rx_gap = max_rx_gap & 0x00ff;	min_rx_pkt = min_rx_pkt & 0x00ff;	max_tx_latency = max_tx_latency & 0x00ff;	max_tx_gap = max_tx_gap & 0x00ff;	min_tx_pkt = min_tx_pkt & 0x00ff;	rx_int_var = card_idx < MAX_UNITS ? rx_params[card_idx] : -1;	tx_int_var = card_idx < MAX_UNITS ? tx_params[card_idx] : -1;	hmp->rx_int_var = rx_int_var >= 0 ? rx_int_var : 		(min_rx_pkt << 16 | max_rx_gap << 8 | max_rx_latency);	hmp->tx_int_var = tx_int_var >= 0 ? tx_int_var : 		(min_tx_pkt << 16 | max_tx_gap << 8 | max_tx_latency);	/* The Hamachi-specific entries in the device structure. */	dev->open = &hamachi_open;	dev->hard_start_xmit = &hamachi_start_xmit;	dev->stop = &hamachi_close;	dev->get_stats = &hamachi_get_stats;	dev->set_multicast_list = &set_rx_mode;#ifdef HAVE_PRIVATE_IOCTL	dev->do_ioctl = &mii_ioctl;#endif	dev->tx_timeout = &hamachi_tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	if (mtu)		dev->mtu = mtu;	if (chip_tbl[hmp->chip_id].flags & CanHaveMII) {		int phy, phy_idx = 0;		for (phy = 0; phy < 32 && phy_idx < 4; phy++) {			int mii_status = mdio_read(ioaddr, phy, 1);			if (mii_status != 0xffff  &&				mii_status != 0x0000) {				hmp->phys[phy_idx++] = phy;				hmp->advertising = mdio_read(ioaddr, phy, 4);				printk(KERN_INFO "%s: MII PHY found at address %d, status "					   "0x%4.4x advertising %4.4x.\n",					   dev->name, phy, mii_status, hmp->advertising);			}		}		hmp->mii_cnt = phy_idx;	}	/* Configure gigabit autonegotiation. */	writew(0x0400, ioaddr + ANXchngCtrl);	/* Enable legacy links. */	writew(0x08e0, ioaddr + ANAdvertise);	/* Set our advertise word. */	writew(0x1000, ioaddr + ANCtrl);			/* Enable negotiation */	card_idx++;	return 0;}static int read_eeprom(long ioaddr, int location){	int bogus_cnt = 1000;	/* We should check busy first - per docs -KDU */	while ((readb(ioaddr + EECmdStatus) & 0x40)  && --bogus_cnt > 0);	writew(location, ioaddr + EEAddr);	writeb(0x02, ioaddr + EECmdStatus);	bogus_cnt = 1000;	while ((readb(ioaddr + EECmdStatus) & 0x40)  && --bogus_cnt > 0);	if (hamachi_debug > 5)		printk("   EEPROM status is %2.2x after %d ticks.\n",			   (int)readb(ioaddr + EECmdStatus), 1000- bogus_cnt);	return readb(ioaddr + EEData);}/* MII Managemen Data I/O accesses.   These routines assume the MDIO controller is idle, and do not exit until   the command is finished. */static int mdio_read(long ioaddr, int phy_id, int location){	int i;	/* We should check busy first - per docs -KDU */	for (i = 10000; i >= 0; i--)		if ((readw(ioaddr + MII_Status) & 1) == 0)			break;	writew((phy_id<<8) + location, ioaddr + MII_Addr);	writew(0x0001, ioaddr + MII_Cmd);	for (i = 10000; i >= 0; i--)		if ((readw(ioaddr + MII_Status) & 1) == 0)			break;	return readw(ioaddr + MII_Rd_Data);}

⌨️ 快捷键说明

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