📄 acenic.c
字号:
/* * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card * and other Tigon based cards. * * Copyright 1998 by Jes Sorensen, <Jes.Sorensen@cern.ch>. * * Thanks to Alteon and 3Com for providing hardware and documentation * enabling me to write this driver. * * A mailing list for discussing the use of this driver has been * setup, please subscribe to the lists if you have any questions * about the driver. Send mail to linux-acenic-help@sunsite.auc.dk to * see how to subscribe. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Additional work by Pete Wyckoff <wyckoff@ca.sandia.gov> for initial * Alpha and trace dump support. */#define PKT_COPY_THRESHOLD 300#include <linux/module.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/pci.h>#include <linux/kernel.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/mm.h>#include <net/sock.h>#include <net/ip.h>#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/byteorder.h>#include <asm/uaccess.h>#include "acenic.h"/* * These must be defined before the firmware is included. */#define MAX_TEXT_LEN 96*1024#define MAX_RODATA_LEN 8*1024#define MAX_DATA_LEN 2*1024#include "acenic_firmware.h"#ifndef PCI_VENDOR_ID_ALTEON#define PCI_VENDOR_ID_ALTEON 0x12ae #define PCI_DEVICE_ID_ALTEON_ACENIC 0x0001#endif#ifndef PCI_DEVICE_ID_3COM_3C985#define PCI_DEVICE_ID_3COM_3C985 0x0001#endif#ifndef PCI_VENDOR_ID_NETGEAR#define PCI_VENDOR_ID_NETGEAR 0x1385#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a#endif/* * This driver currently supports Tigon I and Tigon II based cards * including the Alteon AceNIC and the 3Com 3C985. The driver should * also work on the NetGear GA620, however I have not been able to * test that myself. * * This card is really neat, it supports receive hardware checksumming * and jumbo frames (up to 9000 bytes) and does a lot of work in the * firmware. Also the programming interface is quite neat, except for * the parts dealing with the i2c eeprom on the card ;-) * * Using jumbo frames: * * To enable jumbo frames, simply specify an mtu between 1500 and 9000 * bytes to ifconfig. Jumbo frames can be enabled or disabled at any time * by running `ifconfig eth<X> mtu <MTU>' with <X> being the Ethernet * interface number and <MTU> being the MTU value. * * Module parameters: * * When compiled as a loadable module, the driver allows for a number * of module parameters to be specified. The driver supports the * following module parameters: * * trace=<val> - Firmware trace level. This requires special traced * firmware to replace the firmware supplied with * the driver - for debugging purposes only. * * link=<val> - Link state. Normally you want to use the default link * parameters set by the driver. This can be used to * override these in case your switch doesn't negotiate * the link properly. Valid values are: * 0x0001 - Force half duplex link. * 0x0002 - Do not negotiate line speed with the other end. * 0x0010 - 10Mbit/sec link. * 0x0020 - 100Mbit/sec link. * 0x0040 - 1000Mbit/sec link. * 0x0100 - Do not negotiate flow control. * 0x0200 - Enable RX flow control Y * 0x0400 - Enable TX flow control Y (Tigon II NICs only). * Default value is 0x0270, ie. enable link+flow * control negotiation. Negotiating the highest * possible link speed with RX flow control enabled. * * When disabling link speed negotiation, only one link * speed is allowed to be specified! * * tx_coal_tick=<val> - number of coalescing clock ticks (us) allowed * to wait for more packets to arive before * interrupting the host, from the time the first * packet arrives. * * rx_coal_tick=<val> - number of coalescing clock ticks (us) allowed * to wait for more packets to arive in the transmit ring, * before interrupting the host, after transmitting the * first packet in the ring. * * max_tx_desc=<val> - maximum number of transmit descriptors * (packets) transmitted before interrupting the host. * * max_rx_desc=<val> - maximum number of receive descriptors * (packets) received before interrupting the host. * * tx_ratio=<val> - 7 bit value (0 - 63) specifying the split in 64th * increments of the NIC's on board memory to be used for * transmit and receive buffers. For the 1MB NIC app. 800KB * is available, on the 1/2MB NIC app. 300KB is available. * 68KB will always be available as a minimum for both * directions. The default value is a 50/50 split. * * If you use more than one NIC, specify the parameters for the * individual NICs with a comma, ie. trace=0,0x00001fff,0 you want to * run tracing on NIC #2 but not on NIC #1 and #3. * * TODO: * * - Proper multicast support. * - NIC dump support. * - More tuning parameters. * * The mini ring is not used under Linux and I am not sure it makes sense * to actually use it. *//* * Default values for tuning parameters */#define DEF_TX_RATIO 31#define DEF_TX_COAL TICKS_PER_SEC / 500#define DEF_TX_MAX_DESC 7#define DEF_RX_COAL TICKS_PER_SEC / 10000#define DEF_RX_MAX_DESC 2#define DEF_TRACE 0#define DEF_STAT 2 * TICKS_PER_SECstatic int link[8] = {0, };static int trace[8] = {0, };static int tx_coal_tick[8] = {0, };static int rx_coal_tick[8] = {0, };static int max_tx_desc[8] = {0, };static int max_rx_desc[8] = {0, };static int tx_ratio[8] = {0, };static const char __initdata *version = "acenic.c: v0.32 03/15/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n";static struct device *root_dev = NULL;static int probed __initdata = 0;__initfunc(int acenic_probe (struct device *dev)){ int boards_found = 0; int version_disp; struct ace_private *ap; u8 pci_latency;#if 0 u16 vendor, device; u8 pci_bus; u8 pci_dev_fun; u8 irq;#endif struct pci_dev *pdev = NULL; if (probed) return -ENODEV; probed ++; if (!pci_present()) /* is PCI support present? */ return -ENODEV; version_disp = 0; while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))){ dev = NULL; if (!((pdev->vendor == PCI_VENDOR_ID_ALTEON) && (pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC)) && !((pdev->vendor == PCI_VENDOR_ID_3COM) && (pdev->device == PCI_DEVICE_ID_3COM_3C985)) && !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) && (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620))) continue; dev = init_etherdev(dev, sizeof(struct ace_private)); if (dev == NULL){ printk(KERN_ERR "Unable to allocate etherdev " "structure!\n"); break; } if (!dev->priv) dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL); if (!dev->priv) return -ENOMEM; ap = dev->priv; ap->pdev = pdev; ap->vendor = pdev->vendor; dev->irq = pdev->irq;#ifdef __SMP__ spin_lock_init(&ap->lock);#endif dev->open = &ace_open; dev->hard_start_xmit = &ace_start_xmit; dev->stop = &ace_close; dev->get_stats = &ace_get_stats; dev->set_multicast_list = &ace_set_multicast_list;#if 0 dev->do_ioctl = &ace_ioctl;#endif dev->set_mac_address = &ace_set_mac_addr; dev->change_mtu = &ace_change_mtu; /* * Dummy value. */ dev->base_addr = 42; /* display version info if adapter is found */ if (!version_disp) { /* set display flag to TRUE so that */ /* we only display this string ONCE */ version_disp = 1; printk(version); } pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command); pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency <= 0x40){ pci_latency = 0x40; pci_write_config_byte(pdev, PCI_LATENCY_TIMER, pci_latency); } pci_set_master(pdev); switch(ap->vendor){ case PCI_VENDOR_ID_ALTEON: sprintf(ap->name, "AceNIC Gigabit Ethernet"); printk(KERN_INFO "%s: Alteon AceNIC ", dev->name); break; case PCI_VENDOR_ID_3COM: sprintf(ap->name, "3Com 3C985 Gigabit Ethernet"); printk(KERN_INFO "%s: 3Com 3C985 ", dev->name); break; case PCI_VENDOR_ID_NETGEAR: sprintf(ap->name, "NetGear GA620 Gigabit Ethernet"); printk(KERN_INFO "%s: NetGear GA620 ", dev->name); break; default: sprintf(ap->name, "Unknown AceNIC based Gigabit Ethernet"); printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); break; } printk("Gigabit Ethernet at 0x%08lx, irq %i, PCI latency %i " "clks\n", pdev->base_address[0], dev->irq, pci_latency); /* * Remap the regs into kernel space. */ ap->regs = (struct ace_regs *)ioremap(pdev->base_address[0], 0x4000); if (!ap->regs){ printk(KERN_ERR "%s: Unable to map I/O register, " "AceNIC %i will be disabled.\n", dev->name, boards_found); break; }#ifdef MODULE if (ace_init(dev, boards_found)) continue;#else if (ace_init(dev, -1)) continue;#endif boards_found++; /* * This is bollocks, but we need to tell the net-init * code that it shall go for the next device. */ dev->base_addr = 0; } /* * If we're at this point we're going through ace_probe() for * the first time. Return success (0) if we've initialized 1 * or more boards. Otherwise, return failure (-ENODEV). */#ifdef MODULE return boards_found;#else if (boards_found > 0) return 0; else return -ENODEV;#endif}#ifdef MODULE#if LINUX_VERSION_CODE > 0x20118MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@cern.ch>");MODULE_DESCRIPTION("AceNIC/3C985 Gigabit Ethernet driver");MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i");MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i");MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i");MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");#endifint init_module(void){ int cards; root_dev = NULL; cards = acenic_probe(NULL); return cards ? 0 : -ENODEV;}void cleanup_module(void){ struct ace_private *ap; struct ace_regs *regs; struct device *next; short i; unsigned long flags; while (root_dev){ next = ((struct ace_private *)root_dev->priv)->next; ap = (struct ace_private *)root_dev->priv; regs = ap->regs; spin_lock_irqsave(&ap->lock, flags); writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); if (ap->version == 2) writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); writel(0, ®s->Mb0Lo); spin_unlock_irqrestore(&ap->lock, flags); /* * Release the RX buffers. */ for (i = 0; i < RX_STD_RING_ENTRIES; i++) { if (ap->rx_std_skbuff[i]) { ap->rx_std_ring[i].size = 0; set_aceaddr_bus(&ap->rx_std_ring[i].addr, 0); dev_kfree_skb(ap->rx_std_skbuff[i]); } } iounmap(regs); if(ap->trace_buf) kfree(ap->trace_buf); kfree(ap->info); free_irq(root_dev->irq, root_dev); unregister_netdev(root_dev); kfree(root_dev); root_dev = next; }}#endif/* * Commands are considered to be slow. */static inline void ace_issue_cmd(struct ace_regs *regs, struct cmd *cmd){ u32 idx; idx = readl(®s->CmdPrd); writel(*(u32 *)(cmd), ®s->CmdRng[idx]); idx = (idx + 1) % CMD_RING_ENTRIES; writel(idx, ®s->CmdPrd);}__initfunc(static int ace_init(struct device *dev, int board_idx)){ struct ace_private *ap; struct ace_regs *regs; struct ace_info *info; u32 tig_ver, mac1, mac2, tmp; unsigned long tmp_ptr, myjif; short i; ap = dev->priv; regs = ap->regs; /* * Don't access any other registes before this point! */#ifdef __BIG_ENDIAN writel(((BYTE_SWAP | WORD_SWAP | CLR_INT) | ((BYTE_SWAP | WORD_SWAP | CLR_INT) << 24)), ®s->HostCtrl);#else writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)), ®s->HostCtrl);#endif mb(); /* * Stop the NIC CPU and clear pending interrupts */ writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); writel(0, ®s->Mb0Lo); tig_ver = readl(®s->HostCtrl) >> 28; switch(tig_ver){ case 4: printk(KERN_INFO" Tigon I (Rev. 4), Firmware: %i.%i.%i, ", tigonFwReleaseMajor, tigonFwReleaseMinor, tigonFwReleaseFix); writel(0, ®s->LocalCtrl); ap->version = 1; break; case 6: printk(KERN_INFO" Tigon II (Rev. %i), Firmware: %i.%i.%i, ", tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor, tigon2FwReleaseFix); writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); writel(SRAM_BANK_512K, ®s->LocalCtrl); writel(SYNC_SRAM_TIMING, ®s->MiscCfg); ap->version = 2; break; default: printk(KERN_INFO" Unsupported Tigon version detected (%i), ", tig_ver); return -ENODEV; } /* * ModeStat _must_ be set after the SRAM settings as this change * seems to corrupt the ModeStat and possible other registers. * The SRAM settings survive resets and setting it to the same * value a second time works as well. This is what caused the * `Firmware not running' problem on the Tigon II. */#ifdef __LITTLE_ENDIAN writel(ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL | ACE_WORD_SWAP | ACE_NO_JUMBO_FRAG, ®s->ModeStat);#else#error "this driver doesn't run on big-endian machines yet!"#endif mac1 = 0; for(i = 0; i < 4; i++){ mac1 = mac1 << 8; mac1 |= read_eeprom_byte(regs, 0x8c+i); } mac2 = 0; for(i = 4; i < 8; i++){ mac2 = mac2 << 8; mac2 |= read_eeprom_byte(regs, 0x8c+i); } writel(mac1, ®s->MacAddrHi); writel(mac2, ®s->MacAddrLo); printk("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", (mac1 >> 8) & 0xff, mac1 & 0xff, (mac2 >> 24) &0xff, (mac2 >> 16) & 0xff, (mac2 >> 8) & 0xff, mac2 & 0xff); dev->dev_addr[0] = (mac1 >> 8) & 0xff; dev->dev_addr[1] = mac1 & 0xff; dev->dev_addr[2] = (mac2 >> 24) & 0xff; dev->dev_addr[3] = (mac2 >> 16) & 0xff; dev->dev_addr[4] = (mac2 >> 8) & 0xff; dev->dev_addr[5] = mac2 & 0xff; /* * Set the max DMA transfer size. Seems that for most systems * the performance is better when no MAX parameter is * set. However for systems enabling PCI write and invalidate, * DMA writes must be set to the L1 cache line size to get * optimal performance. */ tmp = READ_CMD_MEM | WRITE_CMD_MEM; if (ap->version == 2){#if 0 /* * According to the documentation this enables writes * to all PCI regs - NOT good. */ tmp |= DMA_WRITE_ALL_ALIGN;#endif tmp |= MEM_READ_MULTIPLE; if (ap->pci_command & PCI_COMMAND_INVALIDATE){ switch(L1_CACHE_BYTES){ case 16: tmp |= DMA_WRITE_MAX_16; break; case 32: tmp |= DMA_WRITE_MAX_32; break; case 64: tmp |= DMA_WRITE_MAX_64; break; default: printk(KERN_INFO " Cache line size %i not " "supported, PCI write and invalidate " "disabled\n", L1_CACHE_BYTES); ap->pci_command &= ~PCI_COMMAND_INVALIDATE; pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); } } } writel(tmp, ®s->PciState); if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) { printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); return -EAGAIN; } /* * Initialize the generic info block and the command+event rings * and the control blocks for the transmit and receive rings * as they need to be setup once and for all. */ if (!(info = kmalloc(sizeof(struct ace_info), GFP_KERNEL | GFP_DMA))){ free_irq(dev->irq, dev); return -EAGAIN; } /* * Register the device here to be able to catch allocated * interrupt handlers in case the firmware doesn't come up. */ ap->next = root_dev; root_dev = dev; ap->info = info; memset(info, 0, sizeof(struct ace_info)); ace_load_firmware(dev); ap->fw_running = 0; tmp_ptr = virt_to_bus((void *)info);#if (BITS_PER_LONG == 64) writel(tmp_ptr >> 32, ®s->InfoPtrHi);#else writel(0, ®s->InfoPtrHi);#endif writel(tmp_ptr & 0xffffffff, ®s->InfoPtrLo); memset(ap->evt_ring, 0, EVT_RING_ENTRIES * sizeof(struct event)); set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring); info->evt_ctrl.flags = 0; set_aceaddr(&info->evt_prd_ptr, &ap->evt_prd); ap->evt_prd = 0; writel(0, ®s->EvtCsm); info->cmd_ctrl.flags = 0; set_aceaddr_bus(&info->cmd_ctrl.rngptr, (void *)0x100); info->cmd_ctrl.max_len = 0; for (i = 0; i < CMD_RING_ENTRIES; i++) writel(0, ®s->CmdRng[i]); writel(0, ®s->CmdPrd); writel(0, ®s->CmdCsm); set_aceaddr(&info->stats2_ptr, &info->s.stats); info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4; set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_std_ring); info->rx_std_ctrl.flags = FLG_RX_TCP_UDP_SUM; memset(ap->rx_std_ring, 0, RX_STD_RING_ENTRIES * sizeof(struct rx_desc)); info->rx_jumbo_ctrl.max_len = 0; set_aceaddr(&info->rx_jumbo_ctrl.rngptr, ap->rx_jumbo_ring); info->rx_jumbo_ctrl.flags = FLG_RX_TCP_UDP_SUM;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -