diff options
Diffstat (limited to 'drivers/net/netxen')
-rw-r--r-- | drivers/net/netxen/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic.h | 12 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_ctx.c | 16 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_ethtool.c | 2 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_hdr.h | 5 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_hw.c | 47 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_hw.h | 2 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_init.c | 8 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_main.c | 263 |
9 files changed, 240 insertions, 117 deletions
diff --git a/drivers/net/netxen/Makefile b/drivers/net/netxen/Makefile index 11d94e2434e..861a0590b1f 100644 --- a/drivers/net/netxen/Makefile +++ b/drivers/net/netxen/Makefile @@ -18,7 +18,7 @@ # MA 02111-1307, USA. # # The full GNU General Public License is included in this distribution -# in the file called LICENSE. +# in the file called "COPYING". # # diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 9bc5bd1d538..0f703838e21 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ @@ -53,8 +53,8 @@ #define _NETXEN_NIC_LINUX_MAJOR 4 #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 72 -#define NETXEN_NIC_LINUX_VERSIONID "4.0.72" +#define _NETXEN_NIC_LINUX_SUBVERSION 73 +#define NETXEN_NIC_LINUX_VERSIONID "4.0.73" #define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define _major(v) (((v) >> 24) & 0xff) @@ -420,7 +420,7 @@ struct status_desc { } __attribute__ ((aligned(16))); /* UNIFIED ROMIMAGE *************************/ -#define NX_UNI_FW_MIN_SIZE 0x3eb000 +#define NX_UNI_FW_MIN_SIZE 0xc8000 #define NX_UNI_DIR_SECT_PRODUCT_TBL 0x0 #define NX_UNI_DIR_SECT_BOOTLD 0x6 #define NX_UNI_DIR_SECT_FW 0x7 @@ -1427,8 +1427,8 @@ static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring) } -int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac); -int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac); +int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 *mac); +int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, u64 *mac); extern void netxen_change_ringparam(struct netxen_adapter *adapter); extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9cb8f687804..f26e54716c8 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ @@ -669,13 +669,15 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) } sds_ring->desc_head = (struct status_desc *)addr; - sds_ring->crb_sts_consumer = - netxen_get_ioaddr(adapter, - recv_crb_registers[port].crb_sts_consumer[ring]); + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + sds_ring->crb_sts_consumer = + netxen_get_ioaddr(adapter, + recv_crb_registers[port].crb_sts_consumer[ring]); - sds_ring->crb_intr_mask = - netxen_get_ioaddr(adapter, - recv_crb_registers[port].sw_int_mask[ring]); + sds_ring->crb_intr_mask = + netxen_get_ioaddr(adapter, + recv_crb_registers[port].sw_int_mask[ring]); + } } diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 542f408333f..f8499e56cbe 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index d138fc22927..622e4c8be93 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ @@ -969,7 +969,8 @@ enum { #define NX_DEV_READY 3 #define NX_DEV_NEED_RESET 4 #define NX_DEV_NEED_QUISCENT 5 -#define NX_DEV_FAILED 6 +#define NX_DEV_NEED_AER 6 +#define NX_DEV_FAILED 7 #define NX_RCODE_DRIVER_INFO 0x20000000 #define NX_RCODE_DRIVER_CAN_RELOAD 0x40000000 diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 85e28e60ecf..b1cf46a0c48 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -19,10 +19,11 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ +#include <linux/slab.h> #include "netxen_nic.h" #include "netxen_nic_hw.h" @@ -539,7 +540,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) struct netxen_adapter *adapter = netdev_priv(netdev); struct dev_mc_list *mc_ptr; u8 null_addr[6]; - int index = 0; + int i; memset(null_addr, 0, 6); @@ -554,7 +555,7 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) return; } - if (netdev->mc_count == 0) { + if (netdev_mc_empty(netdev)) { adapter->set_promisc(adapter, NETXEN_NIU_NON_PROMISC_MODE); netxen_nic_disable_mcast_filter(adapter); @@ -563,23 +564,20 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) adapter->set_promisc(adapter, NETXEN_NIU_ALLMULTI_MODE); if (netdev->flags & IFF_ALLMULTI || - netdev->mc_count > adapter->max_mc_count) { + netdev_mc_count(netdev) > adapter->max_mc_count) { netxen_nic_disable_mcast_filter(adapter); return; } netxen_nic_enable_mcast_filter(adapter); - for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next, index++) - netxen_nic_set_mcast_addr(adapter, index, mc_ptr->dmi_addr); - - if (index != netdev->mc_count) - printk(KERN_WARNING "%s: %s multicast address count mismatch\n", - netxen_nic_driver_name, netdev->name); + i = 0; + netdev_for_each_mc_addr(mc_ptr, netdev) + netxen_nic_set_mcast_addr(adapter, i++, mc_ptr->dmi_addr); /* Clear out remaining addresses */ - for (; index < adapter->max_mc_count; index++) - netxen_nic_set_mcast_addr(adapter, index, null_addr); + while (i < adapter->max_mc_count) + netxen_nic_set_mcast_addr(adapter, i++, null_addr); } static int @@ -704,16 +702,14 @@ void netxen_p3_nic_set_multi(struct net_device *netdev) } if ((netdev->flags & IFF_ALLMULTI) || - (netdev->mc_count > adapter->max_mc_count)) { + (netdev_mc_count(netdev) > adapter->max_mc_count)) { mode = VPORT_MISS_MODE_ACCEPT_MULTI; goto send_fw_cmd; } - if (netdev->mc_count > 0) { - for (mc_ptr = netdev->mc_list; mc_ptr; - mc_ptr = mc_ptr->next) { + if (!netdev_mc_empty(netdev)) { + netdev_for_each_mc_addr(mc_ptr, netdev) nx_p3_nic_add_mac(adapter, mc_ptr->dmi_addr, &del_list); - } } send_fw_cmd: @@ -777,17 +773,20 @@ int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr) int netxen_config_intr_coalesce(struct netxen_adapter *adapter) { nx_nic_req_t req; - u64 word; - int rv; + u64 word[6]; + int rv, i; memset(&req, 0, sizeof(nx_nic_req_t)); + memset(word, 0, sizeof(word)); req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); - word = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); - req.req_hdr = cpu_to_le64(word); + word[0] = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word[0]); - memcpy(&req.words[0], &adapter->coal, sizeof(adapter->coal)); + memcpy(&word[0], &adapter->coal, sizeof(adapter->coal)); + for (i = 0; i < 6; i++) + req.words[i] = cpu_to_le64(word[i]); rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); if (rv != 0) { @@ -1033,7 +1032,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base, return 0; } -int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac) +int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 *mac) { __le32 *pmac = (__le32 *) mac; u32 offset; @@ -1058,7 +1057,7 @@ int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac) return 0; } -int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac) +int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, u64 *mac) { uint32_t crbaddr, mac_hi, mac_lo; int pci_func = adapter->ahw.pci_func; diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index 3fd1dcb3583..e2c5b6f2df0 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -19,7 +19,7 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 64cff68d372..02876f59cbb 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -19,12 +19,13 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ #include <linux/netdevice.h> #include <linux/delay.h> +#include <linux/slab.h> #include "netxen_nic.h" #include "netxen_nic_hw.h" @@ -761,7 +762,7 @@ nx_get_bios_version(struct netxen_adapter *adapter) if (adapter->fw_type == NX_UNIFIED_ROMIMAGE) { bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off]) + NX_UNI_BIOS_VERSION_OFF)); - return (bios_ver << 24) + ((bios_ver >> 8) & 0xff00) + + return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24); } else return cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]); @@ -780,6 +781,9 @@ netxen_need_fw_reset(struct netxen_adapter *adapter) if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) return 1; + if (adapter->need_fw_reset) + return 1; + /* last attempt had failed */ if (NXRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED) return 1; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 24279e6e55f..ce838f7c8b0 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -19,10 +19,11 @@ * MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution - * in the file called LICENSE. + * in the file called "COPYING". * */ +#include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/interrupt.h> #include "netxen_nic_hw.h" @@ -35,6 +36,7 @@ #include <linux/ipv6.h> #include <linux/inetdevice.h> #include <linux/sysfs.h> +#include <linux/aer.h> MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver"); MODULE_LICENSE("GPL"); @@ -84,6 +86,7 @@ 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_dev_request_aer(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); @@ -98,7 +101,7 @@ static void netxen_config_indev_addr(struct net_device *dev, unsigned long); {PCI_DEVICE(PCI_VENDOR_ID_NETXEN, (device)), \ .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0} -static struct pci_device_id netxen_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(netxen_pci_tbl) = { ENTRY(PCI_DEVICE_ID_NX2031_10GXSR), ENTRY(PCI_DEVICE_ID_NX2031_10GCX4), ENTRY(PCI_DEVICE_ID_NX2031_4GCU), @@ -430,7 +433,7 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) { int i; unsigned char *p; - __le64 mac_addr; + u64 mac_addr; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; @@ -602,16 +605,14 @@ netxen_cleanup_pci_map(struct netxen_adapter *adapter) static int netxen_setup_pci_map(struct netxen_adapter *adapter) { - void __iomem *mem_ptr0 = NULL; - void __iomem *mem_ptr1 = NULL; - void __iomem *mem_ptr2 = NULL; void __iomem *db_ptr = NULL; resource_size_t mem_base, db_base; - unsigned long mem_len, db_len = 0, pci_len0 = 0; + unsigned long mem_len, db_len = 0; struct pci_dev *pdev = adapter->pdev; int pci_func = adapter->ahw.pci_func; + struct netxen_hardware_context *ahw = &adapter->ahw; int err = 0; @@ -628,24 +629,40 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) /* 128 Meg of memory */ if (mem_len == NETXEN_PCI_128MB_SIZE) { - mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); - mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START, + + ahw->pci_base0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); + ahw->pci_base1 = ioremap(mem_base + SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_SIZE); - mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START, + ahw->pci_base2 = ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); - pci_len0 = FIRST_PAGE_GROUP_SIZE; + if (ahw->pci_base0 == NULL || ahw->pci_base1 == NULL || + ahw->pci_base2 == NULL) { + dev_err(&pdev->dev, "failed to map PCI bar 0\n"); + err = -EIO; + goto err_out; + } + + ahw->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 - + + ahw->pci_base1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE); + ahw->pci_base2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); + if (ahw->pci_base1 == NULL || ahw->pci_base2 == NULL) { + dev_err(&pdev->dev, "failed to map PCI bar 0\n"); + err = -EIO; + goto err_out; + } + } else if (mem_len == NETXEN_PCI_2MB_SIZE) { - mem_ptr0 = pci_ioremap_bar(pdev, 0); - if (mem_ptr0 == NULL) { + ahw->pci_base0 = pci_ioremap_bar(pdev, 0); + if (ahw->pci_base0 == NULL) { dev_err(&pdev->dev, "failed to map PCI bar 0\n"); return -EIO; } - pci_len0 = mem_len; + ahw->pci_len0 = mem_len; } else { return -EIO; } @@ -654,11 +671,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); - adapter->ahw.pci_base0 = mem_ptr0; - adapter->ahw.pci_len0 = pci_len0; - 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))); @@ -1244,8 +1256,8 @@ 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->revision >= NX_P3_A0 && pdev->revision < NX_P3_B1) { - pr_warning("%s: chip revisions between 0x%x-0x%x" + if (pdev->revision >= NX_P3_A0 && pdev->revision <= NX_P3_B1) { + pr_warning("%s: chip revisions between 0x%x-0x%x " "will not be enabled.\n", module_name(THIS_MODULE), NX_P3_A0, NX_P3_B1); return -ENODEV; @@ -1262,6 +1274,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if ((err = pci_request_regions(pdev, netxen_nic_driver_name))) goto err_out_disable_pdev; + if (NX_IS_REVISION_P3(pdev->revision)) + pci_enable_pcie_error_reporting(pdev); + pci_set_master(pdev); netdev = alloc_etherdev(sizeof(struct netxen_adapter)); @@ -1409,17 +1424,19 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) netxen_release_firmware(adapter); + if (NX_IS_REVISION_P3(pdev->revision)) + pci_disable_pcie_error_reporting(pdev); + pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_netdev(netdev); } -static int __netxen_nic_shutdown(struct pci_dev *pdev) + +static void netxen_nic_detach_func(struct netxen_adapter *adapter) { - struct netxen_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; - int retval; netif_device_detach(netdev); @@ -1438,53 +1455,22 @@ static int __netxen_nic_shutdown(struct pci_dev *pdev) nx_decr_dev_ref_cnt(adapter); clear_bit(__NX_RESETTING, &adapter->state); - - retval = pci_save_state(pdev); - if (retval) - return retval; - - if (netxen_nic_wol_supported(adapter)) { - pci_enable_wake(pdev, PCI_D3cold, 1); - pci_enable_wake(pdev, PCI_D3hot, 1); - } - - pci_disable_device(pdev); - - return 0; } -static void netxen_nic_shutdown(struct pci_dev *pdev) -{ - if (__netxen_nic_shutdown(pdev)) - return; -} -#ifdef CONFIG_PM -static int -netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) -{ - int retval; - retval = __netxen_nic_shutdown(pdev); - if (retval) - return retval; - - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int -netxen_nic_resume(struct pci_dev *pdev) +static int netxen_nic_attach_func(struct pci_dev *pdev) { struct netxen_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; int err; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - err = pci_enable_device(pdev); if (err) return err; + pci_set_power_state(pdev, PCI_D0); + pci_set_master(pdev); + pci_restore_state(pdev); + adapter->ahw.crb_win = -1; adapter->ahw.ocm_win = -1; @@ -1503,11 +1489,10 @@ netxen_nic_resume(struct pci_dev *pdev) if (err) goto err_out_detach; - netif_device_attach(netdev); - netxen_config_indev_addr(netdev, NETDEV_UP); } + netif_device_attach(netdev); netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY); return 0; @@ -1517,6 +1502,85 @@ err_out: nx_decr_dev_ref_cnt(adapter); return err; } + +static pci_ers_result_t netxen_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct netxen_adapter *adapter = pci_get_drvdata(pdev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + if (nx_dev_request_aer(adapter)) + return PCI_ERS_RESULT_RECOVERED; + + netxen_nic_detach_func(adapter); + + pci_disable_device(pdev); + + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t netxen_io_slot_reset(struct pci_dev *pdev) +{ + int err = 0; + + err = netxen_nic_attach_func(pdev); + + return err ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; +} + +static void netxen_io_resume(struct pci_dev *pdev) +{ + pci_cleanup_aer_uncorrect_error_status(pdev); +} + +static void netxen_nic_shutdown(struct pci_dev *pdev) +{ + struct netxen_adapter *adapter = pci_get_drvdata(pdev); + + netxen_nic_detach_func(adapter); + + if (pci_save_state(pdev)) + return; + + if (netxen_nic_wol_supported(adapter)) { + pci_enable_wake(pdev, PCI_D3cold, 1); + pci_enable_wake(pdev, PCI_D3hot, 1); + } + + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int +netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct netxen_adapter *adapter = pci_get_drvdata(pdev); + int retval; + + netxen_nic_detach_func(adapter); + + retval = pci_save_state(pdev); + if (retval) + return retval; + + if (netxen_nic_wol_supported(adapter)) { + pci_enable_wake(pdev, PCI_D3cold, 1); + pci_enable_wake(pdev, PCI_D3hot, 1); + } + + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int +netxen_nic_resume(struct pci_dev *pdev) +{ + return netxen_nic_attach_func(pdev); +} #endif static int netxen_nic_open(struct net_device *netdev) @@ -2104,20 +2168,49 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter) return count; } -static void +static int +nx_dev_request_aer(struct netxen_adapter *adapter) +{ + u32 state; + int ret = -EINVAL; + + if (netxen_api_lock(adapter)) + return ret; + + state = NXRD32(adapter, NX_CRB_DEV_STATE); + + if (state == NX_DEV_NEED_AER) + ret = 0; + else if (state == NX_DEV_READY) { + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_AER); + ret = 0; + } + + netxen_api_unlock(adapter); + return ret; +} + +static int nx_dev_request_reset(struct netxen_adapter *adapter) { u32 state; + int ret = -EINVAL; if (netxen_api_lock(adapter)) - return; + return ret; state = NXRD32(adapter, NX_CRB_DEV_STATE); - if (state != NX_DEV_INITALIZING) + if (state == NX_DEV_NEED_RESET) + ret = 0; + else if (state != NX_DEV_INITALIZING && state != NX_DEV_NEED_AER) { NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET); + ret = 0; + } netxen_api_unlock(adapter); + + return ret; } static int @@ -2271,17 +2364,29 @@ netxen_check_health(struct netxen_adapter *adapter) u32 state, heartbit; struct net_device *netdev = adapter->netdev; + state = NXRD32(adapter, NX_CRB_DEV_STATE); + if (state == NX_DEV_NEED_AER) + return 0; + if (netxen_nic_check_temp(adapter)) goto detach; if (adapter->need_fw_reset) { - nx_dev_request_reset(adapter); + if (nx_dev_request_reset(adapter)) + return 0; goto detach; } - state = NXRD32(adapter, NX_CRB_DEV_STATE); - if (state == NX_DEV_NEED_RESET) - goto detach; + /* NX_DEV_NEED_RESET, this state can be marked in two cases + * 1. Tx timeout 2. Fw hang + * Send request to destroy context in case of tx timeout only + * and doesn't required in case of Fw hang + */ + if (state == NX_DEV_NEED_RESET) { + adapter->need_fw_reset = 1; + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + goto detach; + } if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) return 0; @@ -2290,12 +2395,17 @@ netxen_check_health(struct netxen_adapter *adapter) if (heartbit != adapter->heartbit) { adapter->heartbit = heartbit; adapter->fw_fail_cnt = 0; + if (adapter->need_fw_reset) + goto detach; return 0; } if (++adapter->fw_fail_cnt < FW_FAIL_THRESH) return 0; + if (nx_dev_request_reset(adapter)) + return 0; + clear_bit(__NX_FW_ATTACHED, &adapter->state); dev_info(&netdev->dev, "firmware hang detected\n"); @@ -2498,7 +2608,7 @@ netxen_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr, return size; } -ssize_t netxen_sysfs_write_mem(struct kobject *kobj, +static ssize_t netxen_sysfs_write_mem(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t offset, size_t size) { @@ -2725,6 +2835,12 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event) { } #endif +static struct pci_error_handlers netxen_err_handler = { + .error_detected = netxen_io_error_detected, + .slot_reset = netxen_io_slot_reset, + .resume = netxen_io_resume, +}; + static struct pci_driver netxen_driver = { .name = netxen_nic_driver_name, .id_table = netxen_pci_tbl, @@ -2734,7 +2850,8 @@ static struct pci_driver netxen_driver = { .suspend = netxen_nic_suspend, .resume = netxen_nic_resume, #endif - .shutdown = netxen_nic_shutdown + .shutdown = netxen_nic_shutdown, + .err_handler = &netxen_err_handler }; static int __init netxen_init_module(void) |