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

📄 hamachi.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
err_out:	return ret;}static int __init 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);}static void mdio_write(long ioaddr, int phy_id, int location, int value){	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(value, ioaddr + MII_Wr_Data);	/* Wait for the command to finish. */	for (i = 10000; i >= 0; i--)		if ((readw(ioaddr + MII_Status) & 1) == 0)			break;	return;}static int hamachi_open(struct net_device *dev){	struct hamachi_private *hmp = dev->priv;	long ioaddr = dev->base_addr;	int i;	u32 rx_int_var, tx_int_var;	u16 fifo_info;	i = request_irq(dev->irq, &hamachi_interrupt, SA_SHIRQ, dev->name, dev);	if (i)		return i;	if (hamachi_debug > 1)		printk(KERN_DEBUG "%s: hamachi_open() irq %d.\n",			   dev->name, dev->irq);	hamachi_init_ring(dev);#if ADDRLEN == 64	/* writellll anyone ? */	writel(cpu_to_le64(hmp->rx_ring_dma), ioaddr + RxPtr);	writel(cpu_to_le64(hmp->rx_ring_dma) >> 32, ioaddr + RxPtr + 4);	writel(cpu_to_le64(hmp->tx_ring_dma), ioaddr + TxPtr);	writel(cpu_to_le64(hmp->tx_ring_dma) >> 32, ioaddr + TxPtr + 4);#else	writel(cpu_to_le32(hmp->rx_ring_dma), ioaddr + RxPtr);	writel(cpu_to_le32(hmp->tx_ring_dma), ioaddr + TxPtr);#endif	/* TODO:  It would make sense to organize this as words since the card 	 * documentation does. -KDU	 */	for (i = 0; i < 6; i++)		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);	/* Initialize other registers: with so many this eventually this will	   converted to an offset/value list. */	/* Configure the FIFO */	fifo_info = (readw(ioaddr + GPIO) & 0x00C0) >> 6;	switch (fifo_info){		case 0 : 			/* No FIFO */			writew(0x0000, ioaddr + FIFOcfg);			break;		case 1 : 			/* Configure the FIFO for 512K external, 16K used for Tx. */			writew(0x0028, ioaddr + FIFOcfg);			break;		case 2 : 			/* Configure the FIFO for 1024 external, 32K used for Tx. */			writew(0x004C, ioaddr + FIFOcfg);			break;		case 3 : 			/* Configure the FIFO for 2048 external, 32K used for Tx. */			writew(0x006C, ioaddr + FIFOcfg);			break;		default : 			printk(KERN_WARNING "%s:  Unsupported external memory config!\n",				dev->name);			/* Default to no FIFO */			writew(0x0000, ioaddr + FIFOcfg);			break;	}		if (dev->if_port == 0)		dev->if_port = hmp->default_port;	/* Setting the Rx mode will start the Rx process. */	/* If someone didn't choose a duplex, default to full-duplex */ 	if (hmp->duplex_lock != 1)		hmp->full_duplex = 1;	/* always 1, takes no more time to do it */	writew(0x0001, ioaddr + RxChecksum);#ifdef TX_CHECKSUM	writew(0x0001, ioaddr + TxChecksum);#else	writew(0x0000, ioaddr + TxChecksum);#endif	writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */	writew(0x215F, ioaddr + MACCnfg);	writew(0x000C, ioaddr + FrameGap0); 	/* WHAT?!?!?  Why isn't this documented somewhere? -KDU */	writew(0x1018, ioaddr + FrameGap1);	/* Why do we enable receives/transmits here? -KDU */	writew(0x0780, ioaddr + MACCnfg2); /* Upper 16 bits control LEDs. */	/* Enable automatic generation of flow control frames, period 0xffff. */	writel(0x0030FFFF, ioaddr + FlowCtrl);	writew(MAX_FRAME_SIZE, ioaddr + MaxFrameSize); 	/* dev->mtu+14 ??? */	/* Enable legacy links. */	writew(0x0400, ioaddr + ANXchngCtrl);	/* Enable legacy links. */	/* Initial Link LED to blinking red. */	writeb(0x03, ioaddr + LEDCtrl);	/* Configure interrupt mitigation.  This has a great effect on	   performance, so systems tuning should start here!. */	rx_int_var = hmp->rx_int_var;	tx_int_var = hmp->tx_int_var;	if (hamachi_debug > 1) {		printk("max_tx_latency: %d, max_tx_gap: %d, min_tx_pkt: %d\n",			tx_int_var & 0x00ff, (tx_int_var & 0x00ff00) >> 8, 			(tx_int_var & 0x00ff0000) >> 16);		printk("max_rx_latency: %d, max_rx_gap: %d, min_rx_pkt: %d\n",			rx_int_var & 0x00ff, (rx_int_var & 0x00ff00) >> 8, 			(rx_int_var & 0x00ff0000) >> 16);		printk("rx_int_var: %x, tx_int_var: %x\n", rx_int_var, tx_int_var);	}	writel(tx_int_var, ioaddr + TxIntrCtrl); 	writel(rx_int_var, ioaddr + RxIntrCtrl); 	set_rx_mode(dev);	netif_start_queue(dev);	/* Enable interrupts by setting the interrupt mask. */	writel(0x80878787, ioaddr + InterruptEnable);	writew(0x0000, ioaddr + EventStatus);	/* Clear non-interrupting events */	/* Configure and start the DMA channels. */	/* Burst sizes are in the low three bits: size = 4<<(val&7) */#if ADDRLEN == 64	writew(0x005D, ioaddr + RxDMACtrl); 		/* 128 dword bursts */	writew(0x005D, ioaddr + TxDMACtrl);#else	writew(0x001D, ioaddr + RxDMACtrl);	writew(0x001D, ioaddr + TxDMACtrl);#endif	writew(0x0001, dev->base_addr + RxCmd);	if (hamachi_debug > 2) {		printk(KERN_DEBUG "%s: Done hamachi_open(), status: Rx %x Tx %x.\n",			   dev->name, readw(ioaddr + RxStatus), readw(ioaddr + TxStatus));	}	/* Set the timer to check for link beat. */	init_timer(&hmp->timer);	hmp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */	hmp->timer.data = (unsigned long)dev;	hmp->timer.function = &hamachi_timer;				/* timer handler */	add_timer(&hmp->timer);	return 0;}static inline int hamachi_tx(struct net_device *dev){	struct hamachi_private *hmp = dev->priv;	/* Update the dirty pointer until we find an entry that is		still owned by the card */	for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++) {		int entry = hmp->dirty_tx % TX_RING_SIZE;		struct sk_buff *skb;		if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) 			break;		/* Free the original skb. */		skb = hmp->tx_skbuff[entry];		if (skb != 0) {			pci_unmap_single(hmp->pci_dev, 				hmp->tx_ring[entry].addr, skb->len, 				PCI_DMA_TODEVICE);			dev_kfree_skb(skb);			hmp->tx_skbuff[entry] = 0;		}		hmp->tx_ring[entry].status_n_length = 0;		if (entry >= TX_RING_SIZE-1) 			hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=				cpu_to_le32(DescEndRing);   		hmp->stats.tx_packets++;	}	return 0;}static void hamachi_timer(unsigned long data){	struct net_device *dev = (struct net_device *)data;	struct hamachi_private *hmp = dev->priv;	long ioaddr = dev->base_addr;	int next_tick = 10*HZ;	if (hamachi_debug > 2) {		printk(KERN_INFO "%s: Hamachi Autonegotiation status %4.4x, LPA "			   "%4.4x.\n", dev->name, readw(ioaddr + ANStatus),			   readw(ioaddr + ANLinkPartnerAbility));		printk(KERN_INFO "%s: Autonegotiation regs %4.4x %4.4x %4.4x "		       "%4.4x %4.4x %4.4x.\n", dev->name,		       readw(ioaddr + 0x0e0),		       readw(ioaddr + 0x0e2),		       readw(ioaddr + 0x0e4),		       readw(ioaddr + 0x0e6),		       readw(ioaddr + 0x0e8),		       readw(ioaddr + 0x0eA));	}	/* We could do something here... nah. */	hmp->timer.expires = RUN_AT(next_tick);	add_timer(&hmp->timer);}static void hamachi_tx_timeout(struct net_device *dev){	int i;	struct hamachi_private *hmp = dev->priv;	long ioaddr = dev->base_addr;	printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x,"		   " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus));	{		int i;		printk(KERN_DEBUG "  Rx ring %p: ", hmp->rx_ring);		for (i = 0; i < RX_RING_SIZE; i++)			printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length);		printk("\n"KERN_DEBUG"  Tx ring %p: ", hmp->tx_ring);		for (i = 0; i < TX_RING_SIZE; i++)			printk(" %4.4x", hmp->tx_ring[i].status_n_length);		printk("\n");	}	/* Reinit the hardware and make sure the Rx and Tx processes 		are up and running.	 */	dev->if_port = 0;	/* The right way to do Reset. -KDU	 *		-Clear OWN bit in all Rx/Tx descriptors	 *		-Wait 50 uS for channels to go idle	 *		-Turn off MAC receiver	 *		-Issue Reset	 */		for (i = 0; i < RX_RING_SIZE; i++)		hmp->rx_ring[i].status_n_length &= cpu_to_le32(~DescOwn);	/* Presume that all packets in the Tx queue are gone if we have to	 * re-init the hardware.	 */	for (i = 0; i < TX_RING_SIZE; i++){		struct sk_buff *skb;		if (i >= TX_RING_SIZE - 1)			hmp->tx_ring[i].status_n_length = cpu_to_le32(				DescEndRing |				(hmp->tx_ring[i].status_n_length & 0x0000FFFF));		else				hmp->tx_ring[i].status_n_length &= 0x0000ffff;		skb = hmp->tx_skbuff[i];		if (skb){			pci_unmap_single(hmp->pci_dev, hmp->tx_ring[i].addr, 				skb->len, PCI_DMA_TODEVICE);			dev_kfree_skb(skb);			hmp->tx_skbuff[i] = 0;		}	}	udelay(60); /* Sleep 60 us just for safety sake */	writew(0x0002, dev->base_addr + RxCmd); /* STOP Rx */			writeb(0x01, ioaddr + ChipReset);  /* Reinit the hardware */ 	hmp->tx_full = 0;	hmp->cur_rx = hmp->cur_tx = 0;	hmp->dirty_rx = hmp->dirty_tx = 0;	/* Rx packets are also presumed lost; however, we need to make sure a	 * ring of buffers is in tact. -KDU	 */ 	for (i = 0; i < RX_RING_SIZE; i++){		struct sk_buff *skb = hmp->rx_skbuff[i];		if (skb){			pci_unmap_single(hmp->pci_dev, hmp->rx_ring[i].addr, 				hmp->rx_buf_sz, PCI_DMA_FROMDEVICE);			dev_kfree_skb(skb);			hmp->rx_skbuff[i] = 0;		}	}	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */	for (i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz);		hmp->rx_skbuff[i] = skb;		if (skb == NULL)			break;		skb->dev = dev;         /* Mark as being used by this device. */		skb_reserve(skb, 2); /* 16 byte align the IP header. */                hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, 			skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));		hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | 			DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2));	}	hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);	/* Mark the last entry as wrapping the ring. */	hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing);	/* Trigger an immediate transmit demand. */	dev->trans_start = jiffies;	hmp->stats.tx_errors++;	/* Restart the chip's Tx/Rx processes . */	writew(0x0002, dev->base_addr + TxCmd); /* STOP Tx */	writew(0x0001, dev->base_addr + TxCmd); /* START Tx */	writew(0x0001, dev->base_addr + RxCmd); /* START Rx */	netif_wake_queue(dev);}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void hamachi_init_ring(struct net_device *dev){	struct hamachi_private *hmp = dev->priv;	int i;	hmp->tx_full = 0;	hmp->cur_rx = hmp->cur_tx = 0;	hmp->dirty_rx = hmp->dirty_tx = 0;#if 0	/* This is wrong.  I'm not sure what the original plan was, but this	 * is wrong.  An MTU of 1 gets you a buffer of 1536, while an MTU	 * of 1501 gets a buffer of 1533? -KDU	 */	hmp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);#endif	/* My attempt at a reasonable correction */	/* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the	 * card needs room to do 8 byte alignment, +2 so we can reserve 	 * the first 2 bytes, and +16 gets room for the status word from the 	 * card.  -KDU

⌨️ 快捷键说明

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