hamachi.c

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

C
1,953
字号
	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 const 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 {	__le32 status_n_length;#if ADDRLEN == 64	u32 pad;	__le64 addr;#else	__le32 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 */#define MII_CNT		4struct hamachi_private {	/* Descriptor rings first for alignment.  Tx requires a second descriptor	   for status. */	struct hamachi_desc *rx_ring;	struct hamachi_desc *tx_ring;	struct sk_buff* rx_skbuff[RX_RING_SIZE];	struct sk_buff* tx_skbuff[TX_RING_SIZE];	dma_addr_t tx_ring_dma;	dma_addr_t rx_ring_dma;	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;	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 duplex_lock:1;	unsigned int default_port:4;		/* Last dev->if_port value. */	/* MII transceiver section. */	int mii_cnt;								/* MII device addresses. */	struct mii_if_info mii_if;		/* MII lib hooks/info */	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */	u32 rx_int_var, tx_int_var;	/* interrupt control variables */	u32 option;							/* Hold on to a copy of the options */	struct pci_dev *pci_dev;	void __iomem *base;};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_LICENSE("GPL");module_param(max_interrupt_work, int, 0);module_param(mtu, int, 0);module_param(debug, int, 0);module_param(min_rx_pkt, int, 0);module_param(max_rx_gap, int, 0);module_param(max_rx_latency, int, 0);module_param(min_tx_pkt, int, 0);module_param(max_tx_gap, int, 0);module_param(max_tx_latency, int, 0);module_param(rx_copybreak, int, 0);module_param_array(rx_params, int, NULL, 0);module_param_array(tx_params, int, NULL, 0);module_param_array(options, int, NULL, 0);module_param_array(full_duplex, int, NULL, 0);module_param(force32, int, 0);MODULE_PARM_DESC(max_interrupt_work, "GNIC-II maximum events handled per interrupt");MODULE_PARM_DESC(mtu, "GNIC-II MTU (all boards)");MODULE_PARM_DESC(debug, "GNIC-II debug level (0-7)");MODULE_PARM_DESC(min_rx_pkt, "GNIC-II minimum Rx packets processed between interrupts");MODULE_PARM_DESC(max_rx_gap, "GNIC-II maximum Rx inter-packet gap in 8.192 microsecond units");MODULE_PARM_DESC(max_rx_latency, "GNIC-II time between Rx interrupts in 8.192 microsecond units");MODULE_PARM_DESC(min_tx_pkt, "GNIC-II minimum Tx packets processed between interrupts");MODULE_PARM_DESC(max_tx_gap, "GNIC-II maximum Tx inter-packet gap in 8.192 microsecond units");MODULE_PARM_DESC(max_tx_latency, "GNIC-II time between Tx interrupts in 8.192 microsecond units");MODULE_PARM_DESC(rx_copybreak, "GNIC-II copy breakpoint for copy-only-tiny-frames");MODULE_PARM_DESC(rx_params, "GNIC-II min_rx_pkt+max_rx_gap+max_rx_latency");MODULE_PARM_DESC(tx_params, "GNIC-II min_tx_pkt+max_tx_gap+max_tx_latency");MODULE_PARM_DESC(options, "GNIC-II Bits 0-3: media type, bits 4-6: as force32, bit 7: half duplex, bit 9 full duplex");MODULE_PARM_DESC(full_duplex, "GNIC-II full duplex setting(s) (1)");MODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)");static int read_eeprom(void __iomem *ioaddr, int location);static int mdio_read(struct net_device *dev, int phy_id, int location);static void mdio_write(struct net_device *dev, int phy_id, int location, int value);static int hamachi_open(struct net_device *dev);static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static 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 irqreturn_t hamachi_interrupt(int irq, void *dev_instance);static 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 const struct ethtool_ops ethtool_ops;static const struct ethtool_ops ethtool_ops_no_mii;static int __devinit hamachi_init_one (struct pci_dev *pdev,				    const struct pci_device_id *ent){	struct hamachi_private *hmp;	int option, i, rx_int_var, tx_int_var, boguscnt;	int chip_id = ent->driver_data;	int irq;	void __iomem *ioaddr;	unsigned long base;	static int card_idx;	struct net_device *dev;	void *ring_space;	dma_addr_t ring_dma;	int ret = -ENOMEM;	DECLARE_MAC_BUF(mac);/* when built into the kernel, we only print version if device is found */#ifndef MODULE	static int printed_version;	if (!printed_version++)		printk(version);#endif	if (pci_enable_device(pdev)) {		ret = -EIO;		goto err_out;	}	base = pci_resource_start(pdev, 0);#ifdef __alpha__				/* Really "64 bit addrs" */	base |= (pci_resource_start(pdev, 1) << 32);#endif	pci_set_master(pdev);	i = pci_request_regions(pdev, DRV_NAME);	if (i)		return i;	irq = pdev->irq;	ioaddr = ioremap(base, 0x400);	if (!ioaddr)		goto err_out_release;	dev = alloc_etherdev(sizeof(struct hamachi_private));	if (!dev)		goto err_out_iounmap;	SET_NETDEV_DEV(dev, &pdev->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	for (i = 0; i < 6; i++)		dev->dev_addr[i] = 1 ? read_eeprom(ioaddr, 4 + i)			: readb(ioaddr + StationAddr + i);#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	hmp = netdev_priv(dev);	spin_lock_init(&hmp->lock);	hmp->mii_if.dev = dev;	hmp->mii_if.mdio_read = mdio_read;	hmp->mii_if.mdio_write = mdio_write;	hmp->mii_if.phy_id_mask = 0x1f;	hmp->mii_if.reg_num_mask = 0x1f;	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);	if (!ring_space)		goto err_out_cleardev;	hmp->tx_ring = (struct hamachi_desc *)ring_space;	hmp->tx_ring_dma = ring_dma;	ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);	if (!ring_space)		goto err_out_unmap_tx;	hmp->rx_ring = (struct hamachi_desc *)ring_space;	hmp->rx_ring_dma = ring_dma;	/* 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);	}	hmp->base = ioaddr;	dev->base_addr = (unsigned long)ioaddr;	dev->irq = irq;	pci_set_drvdata(pdev, dev);	hmp->chip_id = chip_id;	hmp->pci_dev = pdev;	/* The lower four bits are the media type. */	if (option > 0) {		hmp->option = option;		if (option & 0x200)			hmp->mii_if.full_duplex = 1;		else if (option & 0x080)			hmp->mii_if.full_duplex = 0;		hmp->default_port = option & 15;		if (hmp->default_port)			hmp->mii_if.force_media = 1;	}	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)		hmp->mii_if.full_duplex = 1;	/* lock the duplex mode if someone specified a value */	if (hmp->mii_if.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;	dev->do_ioctl = &netdev_ioctl;	if (chip_tbl[hmp->chip_id].flags & CanHaveMII)		SET_ETHTOOL_OPS(dev, &ethtool_ops);	else		SET_ETHTOOL_OPS(dev, &ethtool_ops_no_mii);	dev->tx_timeout = &hamachi_tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	if (mtu)		dev->mtu = mtu;	i = register_netdev(dev);	if (i) {		ret = i;		goto err_out_unmap_rx;	}	printk(KERN_INFO "%s: %s type %x at %p, %s, IRQ %d.\n",		   dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev),		   ioaddr, print_mac(mac, dev->dev_addr), irq);	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));	if (chip_tbl[hmp->chip_id].flags & CanHaveMII) {		int phy, phy_idx = 0;		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {			int mii_status = mdio_read(dev, phy, MII_BMSR);			if (mii_status != 0xffff  &&				mii_status != 0x0000) {				hmp->phys[phy_idx++] = phy;				hmp->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);				printk(KERN_INFO "%s: MII PHY found at address %d, status "					   "0x%4.4x advertising %4.4x.\n",					   dev->name, phy, mii_status, hmp->mii_if.advertising);			}		}		hmp->mii_cnt = phy_idx;		if (hmp->mii_cnt > 0)			hmp->mii_if.phy_id = hmp->phys[0];		else			memset(&hmp->mii_if, 0, sizeof(hmp->mii_if));	}	/* 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;

⌨️ 快捷键说明

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