diff options
Diffstat (limited to 'drivers/net/netxen/netxen_nic_main.c')
-rw-r--r-- | drivers/net/netxen/netxen_nic_main.c | 348 |
1 files changed, 284 insertions, 64 deletions
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 0b4a56a8c8d..9f9d6081959 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -34,13 +34,18 @@ #include <net/ip.h> #include <linux/ipv6.h> #include <linux/inetdevice.h> +#include <linux/sysfs.h> -MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); +MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID); +MODULE_FIRMWARE(NX_P2_MN_ROMIMAGE_NAME); +MODULE_FIRMWARE(NX_P3_CT_ROMIMAGE_NAME); +MODULE_FIRMWARE(NX_P3_MN_ROMIMAGE_NAME); +MODULE_FIRMWARE(NX_UNIFIED_ROMIMAGE_NAME); char netxen_nic_driver_name[] = "netxen_nic"; -static char netxen_nic_driver_string[] = "NetXen Network Driver version " +static char netxen_nic_driver_string[] = "QLogic/NetXen Network Driver v" NETXEN_NIC_LINUX_VERSIONID; static int port_mode = NETXEN_PORT_MODE_AUTO_NEG; @@ -52,7 +57,10 @@ static int use_msi = 1; static int use_msi_x = 1; -/* Local functions to NetXen NIC driver */ +static int auto_fw_reset = AUTO_FW_RESET_ENABLED; +module_param(auto_fw_reset, int, 0644); +MODULE_PARM_DESC(auto_fw_reset,"Auto firmware reset (0=disabled, 1=enabled"); + static int __devinit netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static void __devexit netxen_nic_remove(struct pci_dev *pdev); @@ -73,6 +81,8 @@ static void netxen_nic_poll_controller(struct net_device *netdev); static void netxen_create_sysfs_entries(struct netxen_adapter *adapter); static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter); +static void netxen_create_diag_entries(struct netxen_adapter *adapter); +static void netxen_remove_diag_entries(struct netxen_adapter *adapter); static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter); static int netxen_can_start_firmware(struct netxen_adapter *adapter); @@ -330,7 +340,7 @@ netxen_check_hw_init(struct netxen_adapter *adapter, int first_boot) if (!(first_boot & 0x4)) { first_boot |= 0x4; NXWR32(adapter, NETXEN_PCIE_REG(0x4), first_boot); - first_boot = NXRD32(adapter, NETXEN_PCIE_REG(0x4)); + NXRD32(adapter, NETXEN_PCIE_REG(0x4)); } /* This is the first boot after power up */ @@ -437,6 +447,7 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) netdev->dev_addr[i] = *(p + 5 - i); memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); + memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len); /* set station address */ @@ -459,6 +470,7 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p) netxen_napi_disable(adapter); } + memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len); memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); adapter->macaddr_set(adapter, addr->sa_data); @@ -607,14 +619,12 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) * Set the CRB window to invalid. If any register in window 0 is * accessed it should set the window to 0 and then reset it to 1. */ - adapter->curr_window = 255; - adapter->ahw.qdr_sn_window = -1; - adapter->ahw.ddr_mn_window = -1; + adapter->ahw.crb_win = -1; + adapter->ahw.ocm_win = -1; /* remap phys address */ mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ mem_len = pci_resource_len(pdev, 0); - pci_len0 = 0; /* 128 Meg of memory */ if (mem_len == NETXEN_PCI_128MB_SIZE) { @@ -623,6 +633,7 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) SECOND_PAGE_GROUP_SIZE); mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); + pci_len0 = FIRST_PAGE_GROUP_SIZE; } else if (mem_len == NETXEN_PCI_32MB_SIZE) { mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE); mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - @@ -635,19 +646,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) return -EIO; } pci_len0 = mem_len; - - adapter->ahw.ddr_mn_window = 0; - adapter->ahw.qdr_sn_window = 0; - - adapter->ahw.mn_win_crb = NETXEN_PCI_CRBSPACE + - 0x100000 + PCIX_MN_WINDOW + (pci_func * 0x20); - adapter->ahw.ms_win_crb = NETXEN_PCI_CRBSPACE + - 0x100000 + PCIX_SN_WINDOW; - if (pci_func < 4) - adapter->ahw.ms_win_crb += (pci_func * 0x20); - else - adapter->ahw.ms_win_crb += - 0xA0 + ((pci_func - 4) * 0x10); } else { return -EIO; } @@ -661,6 +659,15 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) adapter->ahw.pci_base1 = mem_ptr1; adapter->ahw.pci_base2 = mem_ptr2; + if (NX_IS_REVISION_P3P(adapter->ahw.revision_id)) { + adapter->ahw.ocm_win_crb = netxen_get_ioaddr(adapter, + NETXEN_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func))); + + } else if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + adapter->ahw.ocm_win_crb = netxen_get_ioaddr(adapter, + NETXEN_PCIX_PS_REG(PCIE_MN_WINDOW_REG(pci_func))); + } + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) goto skip_doorbell; @@ -725,7 +732,8 @@ netxen_check_options(struct netxen_adapter *adapter) if (adapter->portnum == 0) { get_brd_name_by_type(adapter->ahw.board_type, brd_name); - printk(KERN_INFO "NetXen %s Board S/N %s Chip rev 0x%x\n", + pr_info("%s: %s Board S/N %s Chip rev 0x%x\n", + module_name(THIS_MODULE), brd_name, serial_num, adapter->ahw.revision_id); } @@ -813,11 +821,11 @@ netxen_start_firmware(struct netxen_adapter *adapter) if (err < 0) goto err_out; if (err == 0) - goto ready; + goto wait_init; if (first_boot != 0x55555555) { NXWR32(adapter, CRB_CMDPEG_STATE, 0); - netxen_pinit_from_rom(adapter, 0); + netxen_pinit_from_rom(adapter); msleep(1); } @@ -856,9 +864,6 @@ netxen_start_firmware(struct netxen_adapter *adapter) | (_NETXEN_NIC_LINUX_SUBVERSION); NXWR32(adapter, CRB_DRIVER_VERSION, val); -ready: - NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_READY); - wait_init: /* Handshake with the card before we register the devices. */ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); @@ -867,6 +872,8 @@ wait_init: goto err_out; } + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_READY); + nx_update_dma_mask(adapter); netxen_check_options(adapter); @@ -941,8 +948,9 @@ netxen_nic_init_coalesce_defaults(struct netxen_adapter *adapter) NETXEN_DEFAULT_INTR_COALESCE_TX_PACKETS; } +/* with rtnl_lock */ static int -netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) +__netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) { int err; @@ -956,7 +964,7 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) return err; } if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - adapter->macaddr_set(adapter, netdev->dev_addr); + adapter->macaddr_set(adapter, adapter->mac_addr); adapter->set_multi(netdev); adapter->set_mtu(adapter, netdev->mtu); @@ -983,14 +991,32 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) return 0; } +/* Usage: During resume and firmware recovery module.*/ + +static inline int +netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) +{ + int err = 0; + + rtnl_lock(); + if (netif_running(netdev)) + err = __netxen_nic_up(adapter, netdev); + rtnl_unlock(); + + return err; +} + +/* with rtnl_lock */ static void -netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) +__netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) { if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) return; - clear_bit(__NX_DEV_UP, &adapter->state); + if (!test_and_clear_bit(__NX_DEV_UP, &adapter->state)) + return; + smp_mb(); spin_lock(&adapter->tx_clean_lock); netif_carrier_off(netdev); netif_tx_disable(netdev); @@ -1009,6 +1035,17 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) spin_unlock(&adapter->tx_clean_lock); } +/* Usage: During suspend and firmware recovery module */ + +static inline void +netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) +{ + rtnl_lock(); + if (netif_running(netdev)) + __netxen_nic_down(adapter, netdev); + rtnl_unlock(); + +} static int netxen_nic_attach(struct netxen_adapter *adapter) @@ -1117,14 +1154,14 @@ netxen_nic_reset_context(struct netxen_adapter *adapter) netif_device_detach(netdev); if (netif_running(netdev)) - netxen_nic_down(adapter, netdev); + __netxen_nic_down(adapter, netdev); netxen_nic_detach(adapter); if (netif_running(netdev)) { err = netxen_nic_attach(adapter); if (!err) - err = netxen_nic_up(adapter, netdev); + err = __netxen_nic_up(adapter, netdev); if (err) goto done; @@ -1207,16 +1244,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int pci_func_id = PCI_FUNC(pdev->devfn); uint8_t revision_id; - if (pdev->class != 0x020000) { - printk(KERN_DEBUG "NetXen function %d, class %x will not " - "be enabled.\n",pci_func_id, pdev->class); - return -ENODEV; - } - if (pdev->revision >= NX_P3_A0 && pdev->revision < NX_P3_B1) { - printk(KERN_WARNING "NetXen chip revisions between 0x%x-0x%x" + pr_warning("%s: chip revisions between 0x%x-0x%x" "will not be enabled.\n", - NX_P3_A0, NX_P3_B1); + module_name(THIS_MODULE), NX_P3_A0, NX_P3_B1); return -ENODEV; } @@ -1250,7 +1281,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) revision_id = pdev->revision; adapter->ahw.revision_id = revision_id; - rwlock_init(&adapter->adapter_lock); + rwlock_init(&adapter->ahw.crb_lock); + spin_lock_init(&adapter->ahw.mem_lock); + spin_lock_init(&adapter->tx_clean_lock); INIT_LIST_HEAD(&adapter->mac_list); @@ -1280,7 +1313,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = netxen_start_firmware(adapter); if (err) - goto err_out_iounmap; + goto err_out_decr_ref; /* * See if the firmware gave us a virtual-physical port mapping. @@ -1315,6 +1348,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; } + netxen_create_diag_entries(adapter); + return 0; err_out_disable_msi: @@ -1322,6 +1357,7 @@ err_out_disable_msi: netxen_free_dummy_dma(adapter); +err_out_decr_ref: nx_decr_dev_ref_cnt(adapter); err_out_iounmap: @@ -1367,6 +1403,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) netxen_teardown_intr(adapter); + netxen_remove_diag_entries(adapter); + netxen_cleanup_pci_map(adapter); netxen_release_firmware(adapter); @@ -1447,7 +1485,8 @@ netxen_nic_resume(struct pci_dev *pdev) if (err) return err; - adapter->curr_window = 255; + adapter->ahw.crb_win = -1; + adapter->ahw.ocm_win = -1; err = netxen_start_firmware(adapter); if (err) { @@ -1492,7 +1531,7 @@ static int netxen_nic_open(struct net_device *netdev) if (err) return err; - err = netxen_nic_up(adapter, netdev); + err = __netxen_nic_up(adapter, netdev); if (err) goto err_out; @@ -1512,7 +1551,7 @@ static int netxen_nic_close(struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); - netxen_nic_down(adapter, netdev); + __netxen_nic_down(adapter, netdev); return 0; } @@ -1859,12 +1898,8 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) linkup = (val == XG_LINK_UP_P3); } else { val = NXRD32(adapter, CRB_XG_STATE); - if (adapter->ahw.port_type == NETXEN_NIC_GBE) - linkup = (val >> port) & 1; - else { - val = (val >> port*8) & 0xff; - linkup = (val == XG_LINK_UP); - } + val = (val >> port*8) & 0xff; + linkup = (val == XG_LINK_UP); } netxen_advert_link_change(adapter, linkup); @@ -1925,7 +1960,7 @@ request_reset: struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); - struct net_device_stats *stats = &adapter->net_stats; + struct net_device_stats *stats = &netdev->stats; memset(stats, 0, sizeof(*stats)); @@ -2018,7 +2053,7 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget) if ((work_done < budget) && tx_complete) { napi_complete(&sds_ring->napi); - if (netif_running(adapter->netdev)) + if (test_bit(__NX_DEV_UP, &adapter->state)) netxen_nic_enable_int(sds_ring); } @@ -2182,14 +2217,13 @@ netxen_fwinit_work(struct work_struct *work) netxen_fwinit_work, 2 * FW_POLL_DELAY); return; } - break; case NX_DEV_FAILED: default: + nx_incr_dev_ref_cnt(adapter); break; } - nx_incr_dev_ref_cnt(adapter); clear_bit(__NX_RESETTING, &adapter->state); } @@ -2204,25 +2238,29 @@ netxen_detach_work(struct work_struct *work) netif_device_detach(netdev); - if (netif_running(netdev)) - netxen_nic_down(adapter, netdev); + netxen_nic_down(adapter, netdev); netxen_nic_detach(adapter); status = NXRD32(adapter, NETXEN_PEG_HALT_STATUS1); - ref_cnt = nx_decr_dev_ref_cnt(adapter); - if (status & NX_RCODE_FATAL_ERROR) - return; + goto err_ret; if (adapter->temp == NX_TEMP_PANIC) - return; + goto err_ret; + + ref_cnt = nx_decr_dev_ref_cnt(adapter); delay = (ref_cnt == 0) ? 0 : (2 * FW_POLL_DELAY); adapter->fw_wait_cnt = 0; netxen_schedule_work(adapter, netxen_fwinit_work, delay); + + return; + +err_ret: + clear_bit(__NX_RESETTING, &adapter->state); } static int @@ -2261,7 +2299,8 @@ netxen_check_health(struct netxen_adapter *adapter) dev_info(&netdev->dev, "firmware hang detected\n"); detach: - if (!test_and_set_bit(__NX_RESETTING, &adapter->state)) + if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) && + !test_and_set_bit(__NX_RESETTING, &adapter->state)) netxen_schedule_work(adapter, netxen_detach_work, 0); return 1; } @@ -2339,6 +2378,161 @@ static struct device_attribute dev_attr_bridged_mode = { .store = netxen_store_bridged_mode, }; +static ssize_t +netxen_store_diag_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct netxen_adapter *adapter = dev_get_drvdata(dev); + unsigned long new; + + if (strict_strtoul(buf, 2, &new)) + return -EINVAL; + + if (!!new != !!(adapter->flags & NETXEN_NIC_DIAG_ENABLED)) + adapter->flags ^= NETXEN_NIC_DIAG_ENABLED; + + return len; +} + +static ssize_t +netxen_show_diag_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct netxen_adapter *adapter = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", + !!(adapter->flags & NETXEN_NIC_DIAG_ENABLED)); +} + +static struct device_attribute dev_attr_diag_mode = { + .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)}, + .show = netxen_show_diag_mode, + .store = netxen_store_diag_mode, +}; + +static int +netxen_sysfs_validate_crb(struct netxen_adapter *adapter, + loff_t offset, size_t size) +{ + if (!(adapter->flags & NETXEN_NIC_DIAG_ENABLED)) + return -EIO; + + if ((size != 4) || (offset & 0x3)) + return -EINVAL; + + if (offset < NETXEN_PCI_CRBSPACE) + return -EINVAL; + + return 0; +} + +static ssize_t +netxen_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct netxen_adapter *adapter = dev_get_drvdata(dev); + u32 data; + int ret; + + ret = netxen_sysfs_validate_crb(adapter, offset, size); + if (ret != 0) + return ret; + + data = NXRD32(adapter, offset); + memcpy(buf, &data, size); + return size; +} + +static ssize_t +netxen_sysfs_write_crb(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct netxen_adapter *adapter = dev_get_drvdata(dev); + u32 data; + int ret; + + ret = netxen_sysfs_validate_crb(adapter, offset, size); + if (ret != 0) + return ret; + + memcpy(&data, buf, size); + NXWR32(adapter, offset, data); + return size; +} + +static int +netxen_sysfs_validate_mem(struct netxen_adapter *adapter, + loff_t offset, size_t size) +{ + if (!(adapter->flags & NETXEN_NIC_DIAG_ENABLED)) + return -EIO; + + if ((size != 8) || (offset & 0x7)) + return -EIO; + + return 0; +} + +static ssize_t +netxen_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct netxen_adapter *adapter = dev_get_drvdata(dev); + u64 data; + int ret; + + ret = netxen_sysfs_validate_mem(adapter, offset, size); + if (ret != 0) + return ret; + + if (adapter->pci_mem_read(adapter, offset, &data)) + return -EIO; + + memcpy(buf, &data, size); + + return size; +} + +ssize_t netxen_sysfs_write_mem(struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct netxen_adapter *adapter = dev_get_drvdata(dev); + u64 data; + int ret; + + ret = netxen_sysfs_validate_mem(adapter, offset, size); + if (ret != 0) + return ret; + + memcpy(&data, buf, size); + + if (adapter->pci_mem_write(adapter, offset, data)) + return -EIO; + + return size; +} + + +static struct bin_attribute bin_attr_crb = { + .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = netxen_sysfs_read_crb, + .write = netxen_sysfs_write_crb, +}; + +static struct bin_attribute bin_attr_mem = { + .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = netxen_sysfs_read_mem, + .write = netxen_sysfs_write_mem, +}; + + static void netxen_create_sysfs_entries(struct netxen_adapter *adapter) { @@ -2364,6 +2558,33 @@ netxen_remove_sysfs_entries(struct netxen_adapter *adapter) device_remove_file(dev, &dev_attr_bridged_mode); } +static void +netxen_create_diag_entries(struct netxen_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct device *dev; + + dev = &pdev->dev; + if (device_create_file(dev, &dev_attr_diag_mode)) + dev_info(dev, "failed to create diag_mode sysfs entry\n"); + if (device_create_bin_file(dev, &bin_attr_crb)) + dev_info(dev, "failed to create crb sysfs entry\n"); + if (device_create_bin_file(dev, &bin_attr_mem)) + dev_info(dev, "failed to create mem sysfs entry\n"); +} + + +static void +netxen_remove_diag_entries(struct netxen_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct device *dev = &pdev->dev; + + device_remove_file(dev, &dev_attr_diag_mode); + device_remove_bin_file(dev, &bin_attr_crb); + device_remove_bin_file(dev, &bin_attr_mem); +} + #ifdef CONFIG_INET #define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops) @@ -2522,7 +2743,6 @@ static int __init netxen_init_module(void) register_netdevice_notifier(&netxen_netdev_cb); register_inetaddr_notifier(&netxen_inetaddr_cb); #endif - return pci_register_driver(&netxen_driver); } |