Re: [PATCH 1/1] atl1: Attansic L1 Gigabit Ethernet driver
From: Stephen Hemminger <hidden>
Date: 2006-09-27 17:50:25
Also in:
lkml
Oh boy, another vendor driver to shred. On Wed, 27 Sep 2006 08:23:45 -0500 Jay Cliburn [off-list ref] wrote:
quoted hunk
Full patch for the Attansic L1 gigabit ethernet driver. Signed-off-by: Jay Cliburn <redacted> drivers/net/Kconfig | 9 drivers/net/Makefile | 1 drivers/net/atl1.c | 5519 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/atl1.h | 1598 ++++++++++++++ include/linux/pci_ids.h | 3 5 files changed, 7130 insertions(+), 0 deletions(-)diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6315477..b735b68 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig@@ -2248,6 +2248,15 @@ config SPIDER_NET This driver supports the Gigabit Ethernet chips present on the Cell Processor-Based Blades from IBM. +config ATTANSIC_L1 + tristate "Attansic L1 gigabit ethernet support" + depends on PCI + help + This driver supports the Attansic L1 gigabit Ethernet device. + + To compile this driver as a module, choose M here: the module + will be called atl1. This is recommended. + config GIANFAR tristate "Gianfar Ethernet" depends on 85xx || 83xx || PPC_86xxdiff --git a/drivers/net/Makefile b/drivers/net/Makefile index f270bc4..e1fcb86 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile@@ -69,6 +69,7 @@ obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o obj-$(CONFIG_RIONET) += rionet.o +obj-$(CONFIG_ATTANSIC_L1) += atl1.o # # end link order sectiondiff --git a/drivers/net/atl1.c b/drivers/net/atl1.c new file mode 100644 index 0000000..ab87071 --- /dev/null +++ b/drivers/net/atl1.c@@ -0,0 +1,5519 @@ +/* + * atl1.c: Attansic L1 gigabit ethernet driver. + * + * This code is derived from the Attansic reference driver (copyright message + * below) provided to Jay Cliburn for addition to the Linux kernel. + * + * The code has been merged into one source file and cleaned up to follow + * Linux coding style. + * + * The changes are (c) Copyright 2006, Jay Cliburn (jacliburn@bellsouth.net) + * + * This source has not been verified for use in safety critical systems. + * + * Please direct inquiries about the revamped driver to the linux-kernel + * mail list, not to Attansic. + * + * Original code: + * + * Copyright (c) 1999-2005 Attansic Corporation (xiong_huang@attansic.com) + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * Author: Xiong Huang + * + * MODULE_LICENSE("GPL");
Why bury this in a comment?
+ * + */ + + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/mm.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/delay.h> +#include <linux/timer.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/string.h> +#include <asm/io.h> +#include <linux/reboot.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/version.h> + + +/* The following header files were provided in the original + * source code, but apparently weren't needed for compilation. + * They're left here for posterity. + */ +/* #include <linux/sched.h> */ +/* #include <linux/pagemap.h> */ +/* #include <linux/list.h> */ +/* #include <linux/stddef.h> */ +/* #include <linux/config.h> */ +/* #include <linux/vmalloc.h> */ +/* #include <linux/capability.h> */ +/* #include <asm/byteorder.h> */ +/* #include <asm/bitops.h> */ +/* #include <asm/irq.h> */ +/* #include <net/pkt_sched.h> */ + +#include "atl1.h" + +#define RUN_REALTIME 0 +#define DRV_VERSION "0.1.40.6" + +char at_driver_name[] = "atl1"; +char at_driver_string[] = "Attansic L1 Ethernet Network Driver"; +char at_driver_version[] = DRV_VERSION; +char at_copyright[] = "Copyright (C) 1999-2005 Attansic Corporation.";
static const char...
+
+MODULE_AUTHOR("Attansic Corporation");
+MODULE_DESCRIPTION("Attansic L1 1000M Ethernet Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+static struct pci_device_id at_pci_tbl[] = {
+ { PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ {0,}
+};use PCI_DEVICE macro
+
+MODULE_DEVICE_TABLE(pci, at_pci_tbl);
+
+/* This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+
+#define AT_MAX_NIC 32
+#define OPTION_UNSET -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED 1
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+#define AT_PARAM_INIT { [0 ... AT_MAX_NIC] = OPTION_UNSET }
+#ifndef module_param_array
+
+/* Module Parameters are always initialized to -1, so that the driver
+ * can tell the difference between no user specified value or the
+ * user asking for the default value.
+ * The true default values are loaded in when e1000_check_options is called.
+ *
+ * This is a GCC extension to ANSI C.
+ * See the item "Labeled Elements in Initializers" in the section
+ * "Extensions to the C Language Family" of the GCC documentation.
+ */
+
+#define AT_PARAM(X, desc) \
+ static const int __devinitdata X[AT_MAX_NIC+1] = AT_PARAM_INIT; \
+ MODULE_PARM(X, "1-" __MODULE_STRING(AT_MAX_NIC) "i"); \
+ MODULE_PARM_DESC(X, desc);
+#else
+#define AT_PARAM(X, desc) \
+ static int __devinitdata X[AT_MAX_NIC+1] = AT_PARAM_INIT; \
+ static int num_##X = 0; \
+ module_param_array_named(X, X, int, &num_##X, 0); \
+ MODULE_PARM_DESC(X, desc);
+#endifmoduleparam is always in 2.6. So this macro can be eliminated and just code directly.
+ +/* Transmit Descriptor Count + * + * Valid Range: 64-2048 + * + * Default Value: 128 + */ +AT_PARAM(TxDescriptors, "Number of transmit descriptors"); + +/* Receive Descriptor Count + * + * Valid Range: 64-4096 + * + * Default Value: 256 + */ +AT_PARAM(RxDescriptors, "Number of receive descriptors"); + +/* User Specified MediaType Override + * + * Valid Range: 0-5 + * - 0 - auto-negotiate at all supported speeds + * - 1 - only link at 1000Mbps Full Duplex + * - 2 - only link at 100Mbps Full Duplex + * - 3 - only link at 100Mbps Half Duplex + * - 4 - only link at 10Mbps Full Duplex + * - 5 - only link at 10Mbps Half Duplex + * Default Value: 0 + */ +AT_PARAM(MediaType, "MediaType Select"); + +/* Interrupt Moderate Timer in units of 2 us + * + * Valid Range: 10-65535 + * + * Default Value: 45000(90ms) + */ +AT_PARAM(IntModTimer, "Interrupt Moderator Timer"); + +/* FlashVendor + * Valid Range: 0-2 + * 0 - Atmel + * 1 - SST + * 2 - ST + */ +AT_PARAM(FlashVendor, "SPI Flash Vendor"); + +#define AUTONEG_ADV_DEFAULT 0x2F +#define AUTONEG_ADV_MASK 0x2F +#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL + +#define DEFAULT_INT_MOD_CNT 100 // 200us +#define MAX_INT_MOD_CNT 65000 +#define MIN_INT_MOD_CNT 50 + +#define FLASH_VENDOR_DEFAULT 0 +#define FLASH_VENDOR_MIN 0 +#define FLASH_VENDOR_MAX 2 + +/* function prototypes */ + +int32_t at_reset_hw(struct at_hw* hw);
Need to make all local functions private (static). Don't use C99 types, in kernel (int32_t) instead use kernel types: u32, s32, ... I suspect most of these int32_t should just be int.
+int32_t at_read_mac_addr(struct at_hw* hw); +int32_t at_init_hw(struct at_hw* hw); +int32_t at_phy_setup_autoneg_adv(struct at_hw *hw); +int32_t at_phy_reset(struct at_hw *hw); +int32_t at_get_speed_and_duplex(struct at_hw *hw, uint16_t *speed, uint16_t *duplex); +int32_t at_set_speed_and_duplex(struct at_hw *hw, uint16_t speed, uint16_t duplex); +uint32_t at_auto_get_fc(struct at_adapter* adapter, uint16_t duplex); +uint32_t at_hash_mc_addr(struct at_hw *hw, uint8_t *mc_addr); +void at_hash_set(struct at_hw *hw, uint32_t hash_value); +int32_t at_read_phy_reg(struct at_hw *hw, uint16_t reg_addr, uint16_t *phy_data); +int32_t at_write_phy_reg(struct at_hw *hw, uint32_t reg_addr, uint16_t phy_data); +void at_read_pci_cfg(struct at_hw* hw, uint32_t reg, uint16_t *value); +void at_write_pci_cfg(struct at_hw* hw, uint32_t reg, uint16_t *value); +int32_t at_validate_mdi_setting(struct at_hw* hw); +int32_t at_setup_link(struct at_hw* hw); +void set_mac_addr(struct at_hw* hw); +int get_permanent_address(struct at_hw* hw); +boolean_t read_eeprom(struct at_hw* hw, uint32_t Offset, uint32_t* pValue); +void init_flash_opcode(struct at_hw* hw); +boolean_t spi_read(struct at_hw* hw, uint32_t addr, uint32_t* buf); +int32_t at_phy_enter_power_saving(struct at_hw* hw); +int32_t at_phy_leave_power_saving(struct at_hw* hw); +int32_t at_up(struct at_adapter* adapter); +void at_down(struct at_adapter* adapter); +int at_reset(struct at_adapter* adapter); +int32_t at_setup_ring_resources(struct at_adapter* adapter); +void at_free_ring_resources(struct at_adapter* adapter); +char at_driver_name[]; +char at_driver_version[];
Get rid of having lots of forward declarations, by just reordering the code, it's simpler.
+
+#ifdef SIOCGMIIPHY
+int at_set_spd_dplx(struct at_adapter* adapter,uint16_t spddplx);
+#endif
+
+static int at_init_module(void);
+static void at_exit_module(void);
+static int at_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void __devexit at_remove(struct pci_dev *pdev);
+static int at_sw_init(struct at_adapter *adapter);
+static int at_open(struct net_device *netdev);
+static int at_close(struct net_device *netdev);
+static int at_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+static struct net_device_stats * at_get_stats(struct net_device *netdev);
+static int at_change_mtu(struct net_device *netdev, int new_mtu);
+static void at_set_multi(struct net_device *netdev);
+static int at_set_mac(struct net_device *netdev, void *p);
+static int at_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+static void at_tx_timeout(struct net_device *dev);
+static irqreturn_t at_intr(int irq, void *data, struct pt_regs *regs);
+static void at_inc_smb(struct at_adapter * adapter);
+static void at_intr_rx(struct at_adapter* adapter);
+static void at_intr_tx(struct at_adapter* adapter);
+static void at_watchdog(unsigned long data);
+static void at_phy_config(unsigned long data);
+static void at_tx_timeout_task(struct net_device *netdev);
+static void at_check_for_link(struct at_adapter* adapter);
+static void at_link_chg_task(struct net_device* netdev);
+static uint32_t at_check_link(struct at_adapter* adapter);
+static void at_clean_tx_ring(struct at_adapter *adapter);
+static uint16_t at_alloc_rx_buffers(struct at_adapter *adapter);
+static uint32_t at_configure(struct at_adapter *adapter);
+static void at_pcie_patch(struct at_adapter *adapter);
+
+#ifdef SIOCGMIIPHY
+static int at_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+#endif
+
+#ifdef NETIF_F_HW_VLAN_TX
+static void at_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
+static void at_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
+static void at_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
+static void at_restore_vlan(struct at_adapter *adapter);
+#endif
+
+static int at_notify_reboot(struct notifier_block *nb, unsigned long event, void *p);
+//static int at_suspend(struct pci_dev *pdev, uint32_t state);
+static int at_suspend(struct pci_dev *pdev, pm_message_t state);
+
+#ifdef CONFIG_PM
+static int at_resume(struct pci_dev *pdev);
+#endif
+
+static void at_via_workaround(struct at_adapter * adapter);
+
+struct notifier_block at_notifier_reboot = {
+ .notifier_call = at_notify_reboot,
+ .next = NULL,
+ .priority = 0
+};Don't initialize fields that can just be zero. Do you really need a reboot notifier at all?
+void at_check_options(struct at_adapter *adapter);
+int at_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr);
+
+#ifdef SIOCDEVPRIVATE
+int at_priv_ioctl(struct net_device* netdev, struct ifreq* ifr);
+#endif
+
+struct at_option {
+ enum { enable_option, range_option, list_option } type;
+ char *name;
+ char *err;
+ int def;
+ union {
+ struct { /* range_option info */
+ int min;
+ int max;
+ } r;
+ struct { /* list_option info */
+ int nr;
+ struct at_opt_list { int i; char *str; } *p;
+ } l;
+ } arg;
+};
+
+static int __devinit at_validate_option(int *value, struct at_option *opt)
+{
+ if(*value == OPTION_UNSET) {
+ *value = opt->def;
+ return 0;
+ }
+
+ switch (opt->type) {
+ case enable_option:
+ switch (*value) {
+ case OPTION_ENABLED:
+ printk(KERN_INFO "%s Enabled\n", opt->name);
+ return 0;
+ case OPTION_DISABLED:
+ printk(KERN_INFO "%s Disabled\n", opt->name);
+ return 0;
+ }
+ break;Indentation does not match kernel style, run through scripts/Lindent.
+ case range_option:
+ if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+ printk(KERN_INFO "%s set to %i\n", opt->name, *value);
+ return 0;
+ }
+ break;
+
+ case list_option: {
+ int i;
+ struct at_opt_list *ent;
+
+ for (i = 0; i < opt->arg.l.nr; i++) {
+ ent = &opt->arg.l.p[i];
+ if (*value == ent->i) {
+ if (ent->str[0] != '\0')
+ printk(KERN_INFO "%s\n", ent->str);
+ return 0;
+ }
+ }
+ break;
+ }
+
+ default:
+ BUG();
+ }
+
+ printk(KERN_INFO "Invalid %s specified (%i) %s\n",
+ opt->name, *value, opt->err);
+ *value = opt->def;
+ return -1;
+}
+
+/**
+ * at_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input. If an invalid value is given, or if no user specified
+ * value exists, a default value is used. The final value is stored
+ * in a variable in the adapter structure.
+ **/
+
+void __devinit at_check_options(struct at_adapter *adapter)
+{
+ int bd = adapter->bd_number;
+ if (bd >= AT_MAX_NIC) {
+ printk(KERN_NOTICE
+ "Warning: no configuration for board #%i\n", bd);
+ printk(KERN_NOTICE "Using defaults for all values\n");
+#ifndef module_param_array
+ bd = AT_MAX_NIC;
+#endif
+ }
+
+ { /* Transmit Descriptor Count */
+ struct at_option opt = {
+ .type = range_option,
+ .name = "Transmit Descriptors",
+ .err = "using default of "
+ __MODULE_STRING(AT_DEFAULT_TPD),
+ .def = AT_DEFAULT_TPD,
+ .arg = { .r = { .min = AT_MIN_TPD, .max = AT_MAX_TPD }}
+ };
+ struct at_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ int val;
+#ifdef module_param_array
+ if (num_TxDescriptors > bd) {
+#endif
+ val = TxDescriptors[bd];
+ at_validate_option(&val, &opt);
+ tpd_ring->count = ((uint16_t) val)&~1;
+#ifdef module_param_array
+ } else {
+ tpd_ring->count = (uint16_t)opt.def;
+ }
+#endif
+ }
+
+ { /* Receive Descriptor Count */
+ struct at_option opt = {
+ .type = range_option,
+ .name = "Receive Descriptors",
+ .err = "using default of "
+ __MODULE_STRING(AT_DEFAULT_RFD),
+ .def = AT_DEFAULT_RFD,
+ .arg = { .r = { .min = AT_MIN_RFD, .max = AT_MAX_RFD }}
+ };
+ struct at_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct at_rrd_ring * rrd_ring = &adapter->rrd_ring;
+ int val;
+#ifdef module_param_array
+ if (num_RxDescriptors > bd) {
+#endif
+ val = RxDescriptors[bd];
+ at_validate_option(&val, &opt);
+ rrd_ring->count = rfd_ring->count = ((uint16_t)val)&~1;
+ // even number
+#ifdef module_param_array
+ } else {
+ rfd_ring->count = rrd_ring->count = (uint16_t)opt.def;
+ }
+#endif
+ }
+
+ { /* Interrupt Moderate Timer */
+ struct at_option opt = {
+ .type = range_option,
+ .name = "Interrupt Moderate Timer",
+ .err = "using default of " __MODULE_STRING(DEFAULT_INT_MOD_CNT),
+ .def = DEFAULT_INT_MOD_CNT,
+ .arg = { .r = { .min = MIN_INT_MOD_CNT, .max = MAX_INT_MOD_CNT }}
+ } ;
+ int val;
+#ifdef module_param_array
+ if (num_IntModTimer > bd) {
+#endif
+ val = IntModTimer[bd];
+ at_validate_option(&val, &opt);
+ adapter->imt = (uint16_t) val;
+#ifdef module_param_array
+ } else {
+ adapter->imt = (uint16_t)(opt.def);
+ }
+#endif
+ }
+
+ { /* Flash Vendor */
+ struct at_option opt = {
+ .type = range_option,
+ .name = "SPI Flash Vendor",
+ .err = "using default of " __MODULE_STRING(FLASH_VENDOR_DEFAULT),
+ .def = DEFAULT_INT_MOD_CNT,
+ .arg = { .r = { .min = FLASH_VENDOR_MIN, .max = FLASH_VENDOR_MAX }}
+ } ;
+ int val;
+#ifdef module_param_array
+ if (num_FlashVendor > bd) {
+#endif
+ val = FlashVendor[bd];
+ at_validate_option(&val, &opt);
+ adapter->hw.flash_vendor = (uint8_t) val;
+#ifdef module_param_array
+ } else {
+ adapter->hw.flash_vendor = (uint8_t)(opt.def);
+ }
+#endif
+ }
+
+ { /* MediaType */
+ struct at_option opt = {
+ .type = range_option,
+ .name = "Speed/Duplex Selection",
+ .err = "using default of " __MODULE_STRING(MEDIA_TYPE_AUTO_SENSOR),
+ .def = MEDIA_TYPE_AUTO_SENSOR,
+ .arg = { .r = { .min = MEDIA_TYPE_AUTO_SENSOR, .max = MEDIA_TYPE_10M_HALF }}
+ } ;
+ int val;
+#ifdef module_param_array
+ if (num_MediaType > bd) {
+#endif
+ val = MediaType[bd];
+ at_validate_option(&val, &opt);
+ adapter->hw.MediaType = (uint16_t) val;
+#ifdef module_param_array
+ } else {
+ adapter->hw.MediaType = (uint16_t)(opt.def);
+ }
+#endif
+ }
+}
+This complexity is an argument for not using lots of module options, and just use ethtool to change stuff.
+ +#ifdef SIOCDEVPRIVATE +#include <asm/uaccess.h> + +// set rfd buffer size. do not support !
/* C style comments are preferred */ ..
+int at_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
+{
+ struct at_adapter *adapter = netdev->priv;
+ void *addr = ifr->ifr_data;
+ uint32_t cmd;
+
+ if (get_user(cmd, (uint32_t *) addr))
+ return -EFAULT;
+Do not do your own ethtool ioctl processing, to easy to get wrong. Use ethtool_ops instead.
+/* Removed large chunk of kcompat stuff -- JKC 09/2006 */
+
+/**
+ * at_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in at_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * at_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+
+static int __devinit
+at_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct at_adapter *adapter;
+ static int cards_found = 0;
+ unsigned long mmio_start;
+ int mmio_len;
+ boolean_t pci_using_64 = TRUE;
+ int err;
+// uint16_t eeprom_data;
+
+ DEBUGFUNC("at_probe !");
+
+ if ((err = pci_enable_device(pdev)))
+ return err;
+
+ if ((err = pci_set_dma_mask(pdev, PCI_DMA_64BIT))) {
+ if ((err = pci_set_dma_mask(pdev, PCI_DMA_32BIT))) {
+ AT_ERR("No usable DMA configuration, aborting\n");
+ return err;
+ }
+ pci_using_64 = FALSE;
+ }
+
+
+ // Mark all PCI regions associated with PCI device
+ // pdev as being reserved by owner at_driver_name
+ if ((err = pci_request_regions(pdev, at_driver_name)))
+ return err;
+
+ // Enables bus-mastering on the device and calls
+ // pcibios_set_master to do the needed arch specific settings
+ pci_set_master(pdev);
+
+ netdev = alloc_etherdev(sizeof(struct at_adapter));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_alloc_etherdev;
+ }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ adapter->hw.back = adapter;
+
+ mmio_start = pci_resource_start(pdev, BAR_0);
+ mmio_len = pci_resource_len(pdev, BAR_0);
+
+ /* AT_DBG("base memory = %lx memory length = %x \n",
+ mmio_start, mmio_len); FIXME */
+ adapter->hw.mem_rang = (uint32_t)mmio_len;
+ adapter->hw.hw_addr = ioremap_nocache(mmio_start, mmio_len);
+ if (!adapter->hw.hw_addr) {
+ err = -EIO;
+ goto err_ioremap;
+ }
+ /* get device reversion number */
+ adapter->hw.dev_rev = AT_READ_REGW(&adapter->hw, (REG_MASTER_CTRL+2));
+
+ netdev->open = &at_open;
+ netdev->stop = &at_close;
+ netdev->hard_start_xmit = &at_xmit_frame;
+ netdev->get_stats = &at_get_stats;
+ netdev->set_multicast_list = &at_set_multi;
+ netdev->set_mac_address = &at_set_mac;
+ netdev->change_mtu = &at_change_mtu;
+ netdev->do_ioctl = &at_ioctl;
+#ifdef HAVE_TX_TIMEOUT
+ netdev->tx_timeout = &at_tx_timeout;
+ netdev->watchdog_timeo = 5 * HZ;
+#endif
+#ifdef NETIF_F_HW_VLAN_TX
+ netdev->vlan_rx_register = at_vlan_rx_register;
+ netdev->vlan_rx_add_vid = at_vlan_rx_add_vid;
+ netdev->vlan_rx_kill_vid = at_vlan_rx_kill_vid;
+#endif
+
+ netdev->mem_start = mmio_start;
+ netdev->mem_end = mmio_start + mmio_len;
+ //netdev->base_addr = adapter->io_base;
+ adapter->bd_number = cards_found;
+ adapter->pci_using_64 = pci_using_64;
+
+ /* setup the private structure */
+
+ if ((err = at_sw_init(adapter)))
+ goto err_sw_init;
+
+ netdev->features = NETIF_F_HW_CSUM;
+
+#ifdef MAX_SKB_FRAGS
+ netdev->features |= NETIF_F_SG;
+#endif
+#ifdef NETIF_F_HW_VLAN_TX
+ netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+#endif
+#ifdef NETIF_F_TSO
+ netdev->features |= NETIF_F_TSO;
+#endif/*NETIF_F_TSO*/
+
+ if (pci_using_64) {
+ netdev->features |= NETIF_F_HIGHDMA;
+ /* AT_DBG("pci using 64bit address\n"); FIXME */
+ }
+#ifdef NETIF_F_LLTX
+ netdev->features |= NETIF_F_LLTX;
+#endif
+
+ /* patch for some L1 of old version,
+ * the final version of L1 may not need these
+ * patches
+ */
+ at_pcie_patch(adapter);
+
+ /* really reset GPHY core */
+ AT_WRITE_REGW(&adapter->hw, REG_GPHY_ENABLE, 0);
+
+ /* reset the controller to
+ * put the device in a known good starting state */
+
+ if (at_reset_hw(&adapter->hw)) {
+ err = -EIO;
+ goto err_reset;
+ }
+
+ /* copy the MAC address out of the EEPROM */
+
+ at_read_mac_addr(&adapter->hw);
+ memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ err = -EIO;
+ goto err_eeprom;
+ }
+
+ /*
+ AT_DBG("mac address : %02x-%02x-%02x-%02x-%02x-%02x\n",
+ adapter->hw.mac_addr[0],
+ adapter->hw.mac_addr[1],
+ adapter->hw.mac_addr[2],
+ adapter->hw.mac_addr[3],
+ adapter->hw.mac_addr[4],
+ adapter->hw.mac_addr[5] );
+ */
+
+ at_check_options(adapter);
+
+ /* pre-init the MAC, and setup link */
+
+ if ((err = at_init_hw(&adapter->hw))) {
+ err = -EIO;
+ goto err_init_hw;
+ }
+
+ /* assume we have no link for now */
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &at_watchdog;
+ adapter->watchdog_timer.data = (unsigned long) adapter;
+
+ init_timer(&adapter->phy_config_timer);
+ adapter->phy_config_timer.function = &at_phy_config;
+ adapter->phy_config_timer.data = (unsigned long) adapter;
+ adapter->phy_timer_pending = FALSE;
+
+ INIT_WORK(&adapter->tx_timeout_task,
+ (void (*)(void *))at_tx_timeout_task, netdev);
+
+ INIT_WORK(&adapter->link_chg_task,
+ (void (*)(void *))at_link_chg_task, netdev);
+
+ INIT_WORK(&adapter->pcie_dma_to_rst_task,
+ (void (*)(void *))at_tx_timeout_task, netdev);
+
+ if ((err = register_netdev(netdev)))
+ goto err_register;
+
+ cards_found++;
+ at_via_workaround(adapter);
+
+ return 0;
+
+err_init_hw:
+err_reset:
+err_register:
+err_sw_init:
+err_eeprom:
+ iounmap(adapter->hw.hw_addr);
+err_ioremap:
+ free_netdev(netdev);
+err_alloc_etherdev:
+ pci_release_regions(pdev);
+ return err;
+}...
quoted hunk
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6a1e098..1eb6f80 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h@@ -2042,6 +2042,9 @@ #define PCI_VENDOR_ID_TOPSPIN 0x1867 #define PCI_VENDOR_ID_TDI 0x192E #define PCI_DEVICE_ID_TDI_EHCI 0x0101 +#define PCI_VENDOR_ID_ATTANSIC 0x1969 +#define PCI_DEVICE_ID_ATTANSIC_L1 0x1048 + #define PCI_VENDOR_ID_JMICRON 0x197B #define PCI_DEVICE_ID_JMICRON_JMB360 0x2360 #define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
Don't bother with PCI id's update, for each sub device. Vendor is probably useful. -- Stephen Hemminger [off-list ref]