diff options
author | Yuval Mintz <yuvalmin@broadcom.com> | 2012-03-26 16:47:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-03-27 22:41:34 -0400 |
commit | 452427b015b1b0cbbef7b6207908726837d39d57 (patch) | |
tree | 221356cb1d3447160c5ad5741cf5e5107801540e | |
parent | a2daf263107ba3eb6db33931881731fa51c95045 (diff) |
bnx2x: previous driver unload revised
The flow in which the bnx2x driver starts after a previous driver
has been terminated in an 'unclean' manner has several bugs and
FW risks, which makes it possible for the driver to fail after
boot-from-SAN or kdump.
This patch contains a revised flow which performs a safer
initialization, solving the possible crash scenarios.
Notice this patch contains lines with over 80 characters, as it
keeps print-strings in a single line.
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 40 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 464 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 4 |
8 files changed, 417 insertions, 107 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index e37161f1925..2c9ee552dff 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | |||
@@ -1173,6 +1173,13 @@ enum { | |||
1173 | }; | 1173 | }; |
1174 | 1174 | ||
1175 | 1175 | ||
1176 | struct bnx2x_prev_path_list { | ||
1177 | u8 bus; | ||
1178 | u8 slot; | ||
1179 | u8 path; | ||
1180 | struct list_head list; | ||
1181 | }; | ||
1182 | |||
1176 | struct bnx2x { | 1183 | struct bnx2x { |
1177 | /* Fields used in the tx and intr/napi performance paths | 1184 | /* Fields used in the tx and intr/napi performance paths |
1178 | * are grouped together in the beginning of the structure | 1185 | * are grouped together in the beginning of the structure |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index f1f3ca65667..44556b719e8 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | |||
@@ -1721,6 +1721,29 @@ static void bnx2x_squeeze_objects(struct bnx2x *bp) | |||
1721 | } while (0) | 1721 | } while (0) |
1722 | #endif | 1722 | #endif |
1723 | 1723 | ||
1724 | bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err) | ||
1725 | { | ||
1726 | /* build FW version dword */ | ||
1727 | u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) + | ||
1728 | (BCM_5710_FW_MINOR_VERSION << 8) + | ||
1729 | (BCM_5710_FW_REVISION_VERSION << 16) + | ||
1730 | (BCM_5710_FW_ENGINEERING_VERSION << 24); | ||
1731 | |||
1732 | /* read loaded FW from chip */ | ||
1733 | u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM); | ||
1734 | |||
1735 | DP(NETIF_MSG_IFUP, "loaded fw %x, my fw %x\n", loaded_fw, my_fw); | ||
1736 | |||
1737 | if (loaded_fw != my_fw) { | ||
1738 | if (is_err) | ||
1739 | BNX2X_ERR("bnx2x with FW %x was already loaded, which mismatches my %x FW. aborting\n", | ||
1740 | loaded_fw, my_fw); | ||
1741 | return false; | ||
1742 | } | ||
1743 | |||
1744 | return true; | ||
1745 | } | ||
1746 | |||
1724 | /* must be called with rtnl_lock */ | 1747 | /* must be called with rtnl_lock */ |
1725 | int bnx2x_nic_load(struct bnx2x *bp, int load_mode) | 1748 | int bnx2x_nic_load(struct bnx2x *bp, int load_mode) |
1726 | { | 1749 | { |
@@ -1815,23 +1838,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) | |||
1815 | } | 1838 | } |
1816 | if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP && | 1839 | if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP && |
1817 | load_code != FW_MSG_CODE_DRV_LOAD_COMMON) { | 1840 | load_code != FW_MSG_CODE_DRV_LOAD_COMMON) { |
1818 | /* build FW version dword */ | ||
1819 | u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) + | ||
1820 | (BCM_5710_FW_MINOR_VERSION << 8) + | ||
1821 | (BCM_5710_FW_REVISION_VERSION << 16) + | ||
1822 | (BCM_5710_FW_ENGINEERING_VERSION << 24); | ||
1823 | |||
1824 | /* read loaded FW from chip */ | ||
1825 | u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM); | ||
1826 | |||
1827 | DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x", | ||
1828 | loaded_fw, my_fw); | ||
1829 | |||
1830 | /* abort nic load if version mismatch */ | 1841 | /* abort nic load if version mismatch */ |
1831 | if (my_fw != loaded_fw) { | 1842 | if (!bnx2x_test_firmware_version(bp, true)) { |
1832 | BNX2X_ERR("bnx2x with FW %x already loaded, " | ||
1833 | "which mismatches my %x FW. aborting", | ||
1834 | loaded_fw, my_fw); | ||
1835 | rc = -EBUSY; | 1843 | rc = -EBUSY; |
1836 | LOAD_ERROR_EXIT(bp, load_error2); | 1844 | LOAD_ERROR_EXIT(bp, load_error2); |
1837 | } | 1845 | } |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 8b163388659..5c27454d2ec 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | |||
@@ -431,6 +431,9 @@ void bnx2x_panic_dump(struct bnx2x *bp); | |||
431 | 431 | ||
432 | void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl); | 432 | void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl); |
433 | 433 | ||
434 | /* validate currect fw is loaded */ | ||
435 | bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err); | ||
436 | |||
434 | /* dev_close main block */ | 437 | /* dev_close main block */ |
435 | int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode); | 438 | int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode); |
436 | 439 | ||
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 5d71b7d4323..dbff5915b81 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | |||
@@ -1251,6 +1251,9 @@ struct drv_func_mb { | |||
1251 | 1251 | ||
1252 | #define DRV_MSG_CODE_LINK_STATUS_CHANGED 0x01000000 | 1252 | #define DRV_MSG_CODE_LINK_STATUS_CHANGED 0x01000000 |
1253 | 1253 | ||
1254 | #define DRV_MSG_CODE_INITIATE_FLR 0x02000000 | ||
1255 | #define REQ_BC_VER_4_INITIATE_FLR 0x00070213 | ||
1256 | |||
1254 | #define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000 | 1257 | #define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000 |
1255 | #define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000 | 1258 | #define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000 |
1256 | #define BIOS_MSG_CODE_VIRT_MAC_PRIM 0xff030000 | 1259 | #define BIOS_MSG_CODE_VIRT_MAC_PRIM 0xff030000 |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index beb4cdbdb6e..efa557b76ac 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #define ETH_MAX_PACKET_SIZE 1500 | 35 | #define ETH_MAX_PACKET_SIZE 1500 |
36 | #define ETH_MAX_JUMBO_PACKET_SIZE 9600 | 36 | #define ETH_MAX_JUMBO_PACKET_SIZE 9600 |
37 | #define MDIO_ACCESS_TIMEOUT 1000 | 37 | #define MDIO_ACCESS_TIMEOUT 1000 |
38 | #define BMAC_CONTROL_RX_ENABLE 2 | ||
39 | #define WC_LANE_MAX 4 | 38 | #define WC_LANE_MAX 4 |
40 | #define I2C_SWITCH_WIDTH 2 | 39 | #define I2C_SWITCH_WIDTH 2 |
41 | #define I2C_BSC0 0 | 40 | #define I2C_BSC0 0 |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h index 7ba557a610d..763535ee483 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h | |||
@@ -89,6 +89,8 @@ | |||
89 | #define PFC_BRB_FULL_LB_XON_THRESHOLD 250 | 89 | #define PFC_BRB_FULL_LB_XON_THRESHOLD 250 |
90 | 90 | ||
91 | #define MAXVAL(a, b) (((a) > (b)) ? (a) : (b)) | 91 | #define MAXVAL(a, b) (((a) > (b)) ? (a) : (b)) |
92 | |||
93 | #define BMAC_CONTROL_RX_ENABLE 2 | ||
92 | /***********************************************************/ | 94 | /***********************************************************/ |
93 | /* Structs */ | 95 | /* Structs */ |
94 | /***********************************************************/ | 96 | /***********************************************************/ |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index f7f9aa80726..e077d250872 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/prefetch.h> | 52 | #include <linux/prefetch.h> |
53 | #include <linux/zlib.h> | 53 | #include <linux/zlib.h> |
54 | #include <linux/io.h> | 54 | #include <linux/io.h> |
55 | #include <linux/semaphore.h> | ||
55 | #include <linux/stringify.h> | 56 | #include <linux/stringify.h> |
56 | #include <linux/vmalloc.h> | 57 | #include <linux/vmalloc.h> |
57 | 58 | ||
@@ -211,6 +212,10 @@ static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = { | |||
211 | 212 | ||
212 | MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl); | 213 | MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl); |
213 | 214 | ||
215 | /* Global resources for unloading a previously loaded device */ | ||
216 | #define BNX2X_PREV_WAIT_NEEDED 1 | ||
217 | static DEFINE_SEMAPHORE(bnx2x_prev_sem); | ||
218 | static LIST_HEAD(bnx2x_prev_list); | ||
214 | /**************************************************************************** | 219 | /**************************************************************************** |
215 | * General service functions | 220 | * General service functions |
216 | ****************************************************************************/ | 221 | ****************************************************************************/ |
@@ -8812,109 +8817,371 @@ static inline void bnx2x_undi_int_disable(struct bnx2x *bp) | |||
8812 | bnx2x_undi_int_disable_e1h(bp); | 8817 | bnx2x_undi_int_disable_e1h(bp); |
8813 | } | 8818 | } |
8814 | 8819 | ||
8815 | static void __devinit bnx2x_undi_unload(struct bnx2x *bp) | 8820 | static void __devinit bnx2x_prev_unload_close_mac(struct bnx2x *bp) |
8816 | { | 8821 | { |
8817 | u32 val; | 8822 | u32 val, base_addr, offset, mask, reset_reg; |
8823 | bool mac_stopped = false; | ||
8824 | u8 port = BP_PORT(bp); | ||
8818 | 8825 | ||
8819 | /* possibly another driver is trying to reset the chip */ | 8826 | reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2); |
8820 | bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET); | ||
8821 | 8827 | ||
8822 | /* check if doorbell queue is reset */ | 8828 | if (!CHIP_IS_E3(bp)) { |
8823 | if (REG_RD(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET) | 8829 | val = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port * 4); |
8824 | & MISC_REGISTERS_RESET_REG_1_RST_DORQ) { | 8830 | mask = MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port; |
8831 | if ((mask & reset_reg) && val) { | ||
8832 | u32 wb_data[2]; | ||
8833 | BNX2X_DEV_INFO("Disable bmac Rx\n"); | ||
8834 | base_addr = BP_PORT(bp) ? NIG_REG_INGRESS_BMAC1_MEM | ||
8835 | : NIG_REG_INGRESS_BMAC0_MEM; | ||
8836 | offset = CHIP_IS_E2(bp) ? BIGMAC2_REGISTER_BMAC_CONTROL | ||
8837 | : BIGMAC_REGISTER_BMAC_CONTROL; | ||
8825 | 8838 | ||
8826 | /* | 8839 | /* |
8827 | * Check if it is the UNDI driver | 8840 | * use rd/wr since we cannot use dmae. This is safe |
8841 | * since MCP won't access the bus due to the request | ||
8842 | * to unload, and no function on the path can be | ||
8843 | * loaded at this time. | ||
8844 | */ | ||
8845 | wb_data[0] = REG_RD(bp, base_addr + offset); | ||
8846 | wb_data[1] = REG_RD(bp, base_addr + offset + 0x4); | ||
8847 | wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE; | ||
8848 | REG_WR(bp, base_addr + offset, wb_data[0]); | ||
8849 | REG_WR(bp, base_addr + offset + 0x4, wb_data[1]); | ||
8850 | |||
8851 | } | ||
8852 | BNX2X_DEV_INFO("Disable emac Rx\n"); | ||
8853 | REG_WR(bp, NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4, 0); | ||
8854 | |||
8855 | mac_stopped = true; | ||
8856 | } else { | ||
8857 | if (reset_reg & MISC_REGISTERS_RESET_REG_2_XMAC) { | ||
8858 | BNX2X_DEV_INFO("Disable xmac Rx\n"); | ||
8859 | base_addr = BP_PORT(bp) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; | ||
8860 | val = REG_RD(bp, base_addr + XMAC_REG_PFC_CTRL_HI); | ||
8861 | REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI, | ||
8862 | val & ~(1 << 1)); | ||
8863 | REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI, | ||
8864 | val | (1 << 1)); | ||
8865 | REG_WR(bp, base_addr + XMAC_REG_CTRL, 0); | ||
8866 | mac_stopped = true; | ||
8867 | } | ||
8868 | mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port; | ||
8869 | if (mask & reset_reg) { | ||
8870 | BNX2X_DEV_INFO("Disable umac Rx\n"); | ||
8871 | base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0; | ||
8872 | REG_WR(bp, base_addr + UMAC_REG_COMMAND_CONFIG, 0); | ||
8873 | mac_stopped = true; | ||
8874 | } | ||
8875 | } | ||
8876 | |||
8877 | if (mac_stopped) | ||
8878 | msleep(20); | ||
8879 | |||
8880 | } | ||
8881 | |||
8882 | #define BNX2X_PREV_UNDI_PROD_ADDR(p) (BAR_TSTRORM_INTMEM + 0x1508 + ((p) << 4)) | ||
8883 | #define BNX2X_PREV_UNDI_RCQ(val) ((val) & 0xffff) | ||
8884 | #define BNX2X_PREV_UNDI_BD(val) ((val) >> 16 & 0xffff) | ||
8885 | #define BNX2X_PREV_UNDI_PROD(rcq, bd) ((bd) << 16 | (rcq)) | ||
8886 | |||
8887 | static void __devinit bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 port, | ||
8888 | u8 inc) | ||
8889 | { | ||
8890 | u16 rcq, bd; | ||
8891 | u32 tmp_reg = REG_RD(bp, BNX2X_PREV_UNDI_PROD_ADDR(port)); | ||
8892 | |||
8893 | rcq = BNX2X_PREV_UNDI_RCQ(tmp_reg) + inc; | ||
8894 | bd = BNX2X_PREV_UNDI_BD(tmp_reg) + inc; | ||
8895 | |||
8896 | tmp_reg = BNX2X_PREV_UNDI_PROD(rcq, bd); | ||
8897 | REG_WR(bp, BNX2X_PREV_UNDI_PROD_ADDR(port), tmp_reg); | ||
8898 | |||
8899 | BNX2X_DEV_INFO("UNDI producer [%d] rings bd -> 0x%04x, rcq -> 0x%04x\n", | ||
8900 | port, bd, rcq); | ||
8901 | } | ||
8902 | |||
8903 | static int __devinit bnx2x_prev_mcp_done(struct bnx2x *bp) | ||
8904 | { | ||
8905 | u32 rc = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0); | ||
8906 | if (!rc) { | ||
8907 | BNX2X_ERR("MCP response failure, aborting\n"); | ||
8908 | return -EBUSY; | ||
8909 | } | ||
8910 | |||
8911 | return 0; | ||
8912 | } | ||
8913 | |||
8914 | static bool __devinit bnx2x_prev_is_path_marked(struct bnx2x *bp) | ||
8915 | { | ||
8916 | struct bnx2x_prev_path_list *tmp_list; | ||
8917 | int rc = false; | ||
8918 | |||
8919 | if (down_trylock(&bnx2x_prev_sem)) | ||
8920 | return false; | ||
8921 | |||
8922 | list_for_each_entry(tmp_list, &bnx2x_prev_list, list) { | ||
8923 | if (PCI_SLOT(bp->pdev->devfn) == tmp_list->slot && | ||
8924 | bp->pdev->bus->number == tmp_list->bus && | ||
8925 | BP_PATH(bp) == tmp_list->path) { | ||
8926 | rc = true; | ||
8927 | BNX2X_DEV_INFO("Path %d was already cleaned from previous drivers\n", | ||
8928 | BP_PATH(bp)); | ||
8929 | break; | ||
8930 | } | ||
8931 | } | ||
8932 | |||
8933 | up(&bnx2x_prev_sem); | ||
8934 | |||
8935 | return rc; | ||
8936 | } | ||
8937 | |||
8938 | static int __devinit bnx2x_prev_mark_path(struct bnx2x *bp) | ||
8939 | { | ||
8940 | struct bnx2x_prev_path_list *tmp_list; | ||
8941 | int rc; | ||
8942 | |||
8943 | tmp_list = (struct bnx2x_prev_path_list *) | ||
8944 | kmalloc(sizeof(struct bnx2x_prev_path_list), GFP_KERNEL); | ||
8945 | if (!tmp_list) { | ||
8946 | BNX2X_ERR("Failed to allocate 'bnx2x_prev_path_list'\n"); | ||
8947 | return -ENOMEM; | ||
8948 | } | ||
8949 | |||
8950 | tmp_list->bus = bp->pdev->bus->number; | ||
8951 | tmp_list->slot = PCI_SLOT(bp->pdev->devfn); | ||
8952 | tmp_list->path = BP_PATH(bp); | ||
8953 | |||
8954 | rc = down_interruptible(&bnx2x_prev_sem); | ||
8955 | if (rc) { | ||
8956 | BNX2X_ERR("Received %d when tried to take lock\n", rc); | ||
8957 | kfree(tmp_list); | ||
8958 | } else { | ||
8959 | BNX2X_DEV_INFO("Marked path [%d] - finished previous unload\n", | ||
8960 | BP_PATH(bp)); | ||
8961 | list_add(&tmp_list->list, &bnx2x_prev_list); | ||
8962 | up(&bnx2x_prev_sem); | ||
8963 | } | ||
8964 | |||
8965 | return rc; | ||
8966 | } | ||
8967 | |||
8968 | static bool __devinit bnx2x_can_flr(struct bnx2x *bp) | ||
8969 | { | ||
8970 | int pos; | ||
8971 | u32 cap; | ||
8972 | struct pci_dev *dev = bp->pdev; | ||
8973 | |||
8974 | pos = pci_pcie_cap(dev); | ||
8975 | if (!pos) | ||
8976 | return false; | ||
8977 | |||
8978 | pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap); | ||
8979 | if (!(cap & PCI_EXP_DEVCAP_FLR)) | ||
8980 | return false; | ||
8981 | |||
8982 | return true; | ||
8983 | } | ||
8984 | |||
8985 | static int __devinit bnx2x_do_flr(struct bnx2x *bp) | ||
8986 | { | ||
8987 | int i, pos; | ||
8988 | u16 status; | ||
8989 | struct pci_dev *dev = bp->pdev; | ||
8990 | |||
8991 | /* probe the capability first */ | ||
8992 | if (bnx2x_can_flr(bp)) | ||
8993 | return -ENOTTY; | ||
8994 | |||
8995 | pos = pci_pcie_cap(dev); | ||
8996 | if (!pos) | ||
8997 | return -ENOTTY; | ||
8998 | |||
8999 | /* Wait for Transaction Pending bit clean */ | ||
9000 | for (i = 0; i < 4; i++) { | ||
9001 | if (i) | ||
9002 | msleep((1 << (i - 1)) * 100); | ||
9003 | |||
9004 | pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status); | ||
9005 | if (!(status & PCI_EXP_DEVSTA_TRPND)) | ||
9006 | goto clear; | ||
9007 | } | ||
9008 | |||
9009 | dev_err(&dev->dev, | ||
9010 | "transaction is not cleared; proceeding with reset anyway\n"); | ||
9011 | |||
9012 | clear: | ||
9013 | if (bp->common.bc_ver < REQ_BC_VER_4_INITIATE_FLR) { | ||
9014 | BNX2X_ERR("FLR not supported by BC_VER: 0x%x\n", | ||
9015 | bp->common.bc_ver); | ||
9016 | return -EINVAL; | ||
9017 | } | ||
9018 | |||
9019 | bnx2x_fw_command(bp, DRV_MSG_CODE_INITIATE_FLR, 0); | ||
9020 | |||
9021 | return 0; | ||
9022 | } | ||
9023 | |||
9024 | static int __devinit bnx2x_prev_unload_uncommon(struct bnx2x *bp) | ||
9025 | { | ||
9026 | int rc; | ||
9027 | |||
9028 | BNX2X_DEV_INFO("Uncommon unload Flow\n"); | ||
9029 | |||
9030 | /* Test if previous unload process was already finished for this path */ | ||
9031 | if (bnx2x_prev_is_path_marked(bp)) | ||
9032 | return bnx2x_prev_mcp_done(bp); | ||
9033 | |||
9034 | /* If function has FLR capabilities, and existing FW version matches | ||
9035 | * the one required, then FLR will be sufficient to clean any residue | ||
9036 | * left by previous driver | ||
9037 | */ | ||
9038 | if (bnx2x_test_firmware_version(bp, false) && bnx2x_can_flr(bp)) | ||
9039 | return bnx2x_do_flr(bp); | ||
9040 | |||
9041 | /* Close the MCP request, return failure*/ | ||
9042 | rc = bnx2x_prev_mcp_done(bp); | ||
9043 | if (!rc) | ||
9044 | rc = BNX2X_PREV_WAIT_NEEDED; | ||
9045 | |||
9046 | return rc; | ||
9047 | } | ||
9048 | |||
9049 | static int __devinit bnx2x_prev_unload_common(struct bnx2x *bp) | ||
9050 | { | ||
9051 | u32 reset_reg, tmp_reg = 0, rc; | ||
9052 | /* It is possible a previous function received 'common' answer, | ||
9053 | * but hasn't loaded yet, therefore creating a scenario of | ||
9054 | * multiple functions receiving 'common' on the same path. | ||
9055 | */ | ||
9056 | BNX2X_DEV_INFO("Common unload Flow\n"); | ||
9057 | |||
9058 | if (bnx2x_prev_is_path_marked(bp)) | ||
9059 | return bnx2x_prev_mcp_done(bp); | ||
9060 | |||
9061 | reset_reg = REG_RD(bp, MISC_REG_RESET_REG_1); | ||
9062 | |||
9063 | /* Reset should be performed after BRB is emptied */ | ||
9064 | if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_BRB1) { | ||
9065 | u32 timer_count = 1000; | ||
9066 | bool prev_undi = false; | ||
9067 | |||
9068 | /* Close the MAC Rx to prevent BRB from filling up */ | ||
9069 | bnx2x_prev_unload_close_mac(bp); | ||
9070 | |||
9071 | /* Check if the UNDI driver was previously loaded | ||
8828 | * UNDI driver initializes CID offset for normal bell to 0x7 | 9072 | * UNDI driver initializes CID offset for normal bell to 0x7 |
8829 | */ | 9073 | */ |
8830 | val = REG_RD(bp, DORQ_REG_NORM_CID_OFST); | 9074 | reset_reg = REG_RD(bp, MISC_REG_RESET_REG_1); |
8831 | if (val == 0x7) { | 9075 | if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_DORQ) { |
8832 | u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; | 9076 | tmp_reg = REG_RD(bp, DORQ_REG_NORM_CID_OFST); |
8833 | /* save our pf_num */ | 9077 | if (tmp_reg == 0x7) { |
8834 | int orig_pf_num = bp->pf_num; | 9078 | BNX2X_DEV_INFO("UNDI previously loaded\n"); |
8835 | int port; | 9079 | prev_undi = true; |
8836 | u32 swap_en, swap_val, value; | 9080 | /* clear the UNDI indication */ |
8837 | 9081 | REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0); | |
8838 | /* clear the UNDI indication */ | ||
8839 | REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0); | ||
8840 | |||
8841 | BNX2X_DEV_INFO("UNDI is active! reset device\n"); | ||
8842 | |||
8843 | /* try unload UNDI on port 0 */ | ||
8844 | bp->pf_num = 0; | ||
8845 | bp->fw_seq = | ||
8846 | (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) & | ||
8847 | DRV_MSG_SEQ_NUMBER_MASK); | ||
8848 | reset_code = bnx2x_fw_command(bp, reset_code, 0); | ||
8849 | |||
8850 | /* if UNDI is loaded on the other port */ | ||
8851 | if (reset_code != FW_MSG_CODE_DRV_UNLOAD_COMMON) { | ||
8852 | |||
8853 | /* send "DONE" for previous unload */ | ||
8854 | bnx2x_fw_command(bp, | ||
8855 | DRV_MSG_CODE_UNLOAD_DONE, 0); | ||
8856 | |||
8857 | /* unload UNDI on port 1 */ | ||
8858 | bp->pf_num = 1; | ||
8859 | bp->fw_seq = | ||
8860 | (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) & | ||
8861 | DRV_MSG_SEQ_NUMBER_MASK); | ||
8862 | reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; | ||
8863 | |||
8864 | bnx2x_fw_command(bp, reset_code, 0); | ||
8865 | } | 9082 | } |
9083 | } | ||
9084 | /* wait until BRB is empty */ | ||
9085 | tmp_reg = REG_RD(bp, BRB1_REG_NUM_OF_FULL_BLOCKS); | ||
9086 | while (timer_count) { | ||
9087 | u32 prev_brb = tmp_reg; | ||
8866 | 9088 | ||
8867 | bnx2x_undi_int_disable(bp); | 9089 | tmp_reg = REG_RD(bp, BRB1_REG_NUM_OF_FULL_BLOCKS); |
8868 | port = BP_PORT(bp); | 9090 | if (!tmp_reg) |
8869 | 9091 | break; | |
8870 | /* close input traffic and wait for it */ | ||
8871 | /* Do not rcv packets to BRB */ | ||
8872 | REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_DRV_MASK : | ||
8873 | NIG_REG_LLH0_BRB1_DRV_MASK), 0x0); | ||
8874 | /* Do not direct rcv packets that are not for MCP to | ||
8875 | * the BRB */ | ||
8876 | REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP : | ||
8877 | NIG_REG_LLH0_BRB1_NOT_MCP), 0x0); | ||
8878 | /* clear AEU */ | ||
8879 | REG_WR(bp, (port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : | ||
8880 | MISC_REG_AEU_MASK_ATTN_FUNC_0), 0); | ||
8881 | msleep(10); | ||
8882 | |||
8883 | /* save NIG port swap info */ | ||
8884 | swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); | ||
8885 | swap_en = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); | ||
8886 | /* reset device */ | ||
8887 | REG_WR(bp, | ||
8888 | GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, | ||
8889 | 0xd3ffffff); | ||
8890 | |||
8891 | value = 0x1400; | ||
8892 | if (CHIP_IS_E3(bp)) { | ||
8893 | value |= MISC_REGISTERS_RESET_REG_2_MSTAT0; | ||
8894 | value |= MISC_REGISTERS_RESET_REG_2_MSTAT1; | ||
8895 | } | ||
8896 | 9092 | ||
8897 | REG_WR(bp, | 9093 | BNX2X_DEV_INFO("BRB still has 0x%08x\n", tmp_reg); |
8898 | GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, | ||
8899 | value); | ||
8900 | 9094 | ||
8901 | /* take the NIG out of reset and restore swap values */ | 9095 | /* reset timer as long as BRB actually gets emptied */ |
8902 | REG_WR(bp, | 9096 | if (prev_brb > tmp_reg) |
8903 | GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, | 9097 | timer_count = 1000; |
8904 | MISC_REGISTERS_RESET_REG_1_RST_NIG); | 9098 | else |
8905 | REG_WR(bp, NIG_REG_PORT_SWAP, swap_val); | 9099 | timer_count--; |
8906 | REG_WR(bp, NIG_REG_STRAP_OVERRIDE, swap_en); | ||
8907 | 9100 | ||
8908 | /* send unload done to the MCP */ | 9101 | /* If UNDI resides in memory, manually increment it */ |
8909 | bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0); | 9102 | if (prev_undi) |
9103 | bnx2x_prev_unload_undi_inc(bp, BP_PORT(bp), 1); | ||
8910 | 9104 | ||
8911 | /* restore our func and fw_seq */ | 9105 | udelay(10); |
8912 | bp->pf_num = orig_pf_num; | ||
8913 | } | 9106 | } |
9107 | |||
9108 | if (!timer_count) | ||
9109 | BNX2X_ERR("Failed to empty BRB, hope for the best\n"); | ||
9110 | |||
8914 | } | 9111 | } |
8915 | 9112 | ||
8916 | /* now it's safe to release the lock */ | 9113 | /* No packets are in the pipeline, path is ready for reset */ |
8917 | bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET); | 9114 | bnx2x_reset_common(bp); |
9115 | |||
9116 | rc = bnx2x_prev_mark_path(bp); | ||
9117 | if (rc) { | ||
9118 | bnx2x_prev_mcp_done(bp); | ||
9119 | return rc; | ||
9120 | } | ||
9121 | |||
9122 | return bnx2x_prev_mcp_done(bp); | ||
9123 | } | ||
9124 | |||
9125 | static int __devinit bnx2x_prev_unload(struct bnx2x *bp) | ||
9126 | { | ||
9127 | int time_counter = 10; | ||
9128 | u32 rc, fw, hw_lock_reg, hw_lock_val; | ||
9129 | BNX2X_DEV_INFO("Entering Previous Unload Flow\n"); | ||
9130 | |||
9131 | /* Release previously held locks */ | ||
9132 | hw_lock_reg = (BP_FUNC(bp) <= 5) ? | ||
9133 | (MISC_REG_DRIVER_CONTROL_1 + BP_FUNC(bp) * 8) : | ||
9134 | (MISC_REG_DRIVER_CONTROL_7 + (BP_FUNC(bp) - 6) * 8); | ||
9135 | |||
9136 | hw_lock_val = (REG_RD(bp, hw_lock_reg)); | ||
9137 | if (hw_lock_val) { | ||
9138 | if (hw_lock_val & HW_LOCK_RESOURCE_NVRAM) { | ||
9139 | BNX2X_DEV_INFO("Release Previously held NVRAM lock\n"); | ||
9140 | REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, | ||
9141 | (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << BP_PORT(bp))); | ||
9142 | } | ||
9143 | |||
9144 | BNX2X_DEV_INFO("Release Previously held hw lock\n"); | ||
9145 | REG_WR(bp, hw_lock_reg, 0xffffffff); | ||
9146 | } else | ||
9147 | BNX2X_DEV_INFO("No need to release hw/nvram locks\n"); | ||
9148 | |||
9149 | if (MCPR_ACCESS_LOCK_LOCK & REG_RD(bp, MCP_REG_MCPR_ACCESS_LOCK)) { | ||
9150 | BNX2X_DEV_INFO("Release previously held alr\n"); | ||
9151 | REG_WR(bp, MCP_REG_MCPR_ACCESS_LOCK, 0); | ||
9152 | } | ||
9153 | |||
9154 | |||
9155 | do { | ||
9156 | /* Lock MCP using an unload request */ | ||
9157 | fw = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS, 0); | ||
9158 | if (!fw) { | ||
9159 | BNX2X_ERR("MCP response failure, aborting\n"); | ||
9160 | rc = -EBUSY; | ||
9161 | break; | ||
9162 | } | ||
9163 | |||
9164 | if (fw == FW_MSG_CODE_DRV_UNLOAD_COMMON) { | ||
9165 | rc = bnx2x_prev_unload_common(bp); | ||
9166 | break; | ||
9167 | } | ||
9168 | |||
9169 | /* non-common reply from MCP night require looping */ | ||
9170 | rc = bnx2x_prev_unload_uncommon(bp); | ||
9171 | if (rc != BNX2X_PREV_WAIT_NEEDED) | ||
9172 | break; | ||
9173 | |||
9174 | msleep(20); | ||
9175 | } while (--time_counter); | ||
9176 | |||
9177 | if (!time_counter || rc) { | ||
9178 | BNX2X_ERR("Failed unloading previous driver, aborting\n"); | ||
9179 | rc = -EBUSY; | ||
9180 | } | ||
9181 | |||
9182 | BNX2X_DEV_INFO("Finished Previous Unload Flow [%d]\n", rc); | ||
9183 | |||
9184 | return rc; | ||
8918 | } | 9185 | } |
8919 | 9186 | ||
8920 | static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) | 9187 | static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) |
@@ -10100,8 +10367,16 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) | |||
10100 | func = BP_FUNC(bp); | 10367 | func = BP_FUNC(bp); |
10101 | 10368 | ||
10102 | /* need to reset chip if undi was active */ | 10369 | /* need to reset chip if undi was active */ |
10103 | if (!BP_NOMCP(bp)) | 10370 | if (!BP_NOMCP(bp)) { |
10104 | bnx2x_undi_unload(bp); | 10371 | /* init fw_seq */ |
10372 | bp->fw_seq = | ||
10373 | SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) & | ||
10374 | DRV_MSG_SEQ_NUMBER_MASK; | ||
10375 | BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); | ||
10376 | |||
10377 | bnx2x_prev_unload(bp); | ||
10378 | } | ||
10379 | |||
10105 | 10380 | ||
10106 | if (CHIP_REV_IS_FPGA(bp)) | 10381 | if (CHIP_REV_IS_FPGA(bp)) |
10107 | dev_err(&bp->pdev->dev, "FPGA detected\n"); | 10382 | dev_err(&bp->pdev->dev, "FPGA detected\n"); |
@@ -11431,9 +11706,18 @@ static int __init bnx2x_init(void) | |||
11431 | 11706 | ||
11432 | static void __exit bnx2x_cleanup(void) | 11707 | static void __exit bnx2x_cleanup(void) |
11433 | { | 11708 | { |
11709 | struct list_head *pos, *q; | ||
11434 | pci_unregister_driver(&bnx2x_pci_driver); | 11710 | pci_unregister_driver(&bnx2x_pci_driver); |
11435 | 11711 | ||
11436 | destroy_workqueue(bnx2x_wq); | 11712 | destroy_workqueue(bnx2x_wq); |
11713 | |||
11714 | /* Free globablly allocated resources */ | ||
11715 | list_for_each_safe(pos, q, &bnx2x_prev_list) { | ||
11716 | struct bnx2x_prev_path_list *tmp = | ||
11717 | list_entry(pos, struct bnx2x_prev_path_list, list); | ||
11718 | list_del(pos); | ||
11719 | kfree(tmp); | ||
11720 | } | ||
11437 | } | 11721 | } |
11438 | 11722 | ||
11439 | void bnx2x_notify_link_changed(struct bnx2x *bp) | 11723 | void bnx2x_notify_link_changed(struct bnx2x *bp) |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index fd7fb458184..ab0a250f95f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h | |||
@@ -987,6 +987,7 @@ | |||
987 | * clear; 1 = set. Data valid only in addresses 0-4. all the rest are zero. */ | 987 | * clear; 1 = set. Data valid only in addresses 0-4. all the rest are zero. */ |
988 | #define IGU_REG_WRITE_DONE_PENDING 0x130480 | 988 | #define IGU_REG_WRITE_DONE_PENDING 0x130480 |
989 | #define MCP_A_REG_MCPR_SCRATCH 0x3a0000 | 989 | #define MCP_A_REG_MCPR_SCRATCH 0x3a0000 |
990 | #define MCP_REG_MCPR_ACCESS_LOCK 0x8009c | ||
990 | #define MCP_REG_MCPR_CPU_PROGRAM_COUNTER 0x8501c | 991 | #define MCP_REG_MCPR_CPU_PROGRAM_COUNTER 0x8501c |
991 | #define MCP_REG_MCPR_GP_INPUTS 0x800c0 | 992 | #define MCP_REG_MCPR_GP_INPUTS 0x800c0 |
992 | #define MCP_REG_MCPR_GP_OENABLE 0x800c8 | 993 | #define MCP_REG_MCPR_GP_OENABLE 0x800c8 |
@@ -1686,6 +1687,7 @@ | |||
1686 | [10] rst_dbg; [11] rst_misc_core; [12] rst_dbue (UART); [13] | 1687 | [10] rst_dbg; [11] rst_misc_core; [12] rst_dbue (UART); [13] |
1687 | Pci_resetmdio_n; [14] rst_emac0_hard_core; [15] rst_emac1_hard_core; 16] | 1688 | Pci_resetmdio_n; [14] rst_emac0_hard_core; [15] rst_emac1_hard_core; 16] |
1688 | rst_pxp_rq_rd_wr; 31:17] reserved */ | 1689 | rst_pxp_rq_rd_wr; 31:17] reserved */ |
1690 | #define MISC_REG_RESET_REG_1 0xa580 | ||
1689 | #define MISC_REG_RESET_REG_2 0xa590 | 1691 | #define MISC_REG_RESET_REG_2 0xa590 |
1690 | /* [RW 20] 20 bit GRC address where the scratch-pad of the MCP that is | 1692 | /* [RW 20] 20 bit GRC address where the scratch-pad of the MCP that is |
1691 | shared with the driver resides */ | 1693 | shared with the driver resides */ |
@@ -5606,6 +5608,7 @@ | |||
5606 | /* [RC 32] Parity register #0 read clear */ | 5608 | /* [RC 32] Parity register #0 read clear */ |
5607 | #define XSEM_REG_XSEM_PRTY_STS_CLR_0 0x280128 | 5609 | #define XSEM_REG_XSEM_PRTY_STS_CLR_0 0x280128 |
5608 | #define XSEM_REG_XSEM_PRTY_STS_CLR_1 0x280138 | 5610 | #define XSEM_REG_XSEM_PRTY_STS_CLR_1 0x280138 |
5611 | #define MCPR_ACCESS_LOCK_LOCK (1L<<31) | ||
5609 | #define MCPR_NVM_ACCESS_ENABLE_EN (1L<<0) | 5612 | #define MCPR_NVM_ACCESS_ENABLE_EN (1L<<0) |
5610 | #define MCPR_NVM_ACCESS_ENABLE_WR_EN (1L<<1) | 5613 | #define MCPR_NVM_ACCESS_ENABLE_WR_EN (1L<<1) |
5611 | #define MCPR_NVM_ADDR_NVM_ADDR_VALUE (0xffffffL<<0) | 5614 | #define MCPR_NVM_ADDR_NVM_ADDR_VALUE (0xffffffL<<0) |
@@ -5732,6 +5735,7 @@ | |||
5732 | #define MISC_REGISTERS_GPIO_PORT_SHIFT 4 | 5735 | #define MISC_REGISTERS_GPIO_PORT_SHIFT 4 |
5733 | #define MISC_REGISTERS_GPIO_SET_POS 8 | 5736 | #define MISC_REGISTERS_GPIO_SET_POS 8 |
5734 | #define MISC_REGISTERS_RESET_REG_1_CLEAR 0x588 | 5737 | #define MISC_REGISTERS_RESET_REG_1_CLEAR 0x588 |
5738 | #define MISC_REGISTERS_RESET_REG_1_RST_BRB1 (0x1<<0) | ||
5735 | #define MISC_REGISTERS_RESET_REG_1_RST_DORQ (0x1<<19) | 5739 | #define MISC_REGISTERS_RESET_REG_1_RST_DORQ (0x1<<19) |
5736 | #define MISC_REGISTERS_RESET_REG_1_RST_HC (0x1<<29) | 5740 | #define MISC_REGISTERS_RESET_REG_1_RST_HC (0x1<<29) |
5737 | #define MISC_REGISTERS_RESET_REG_1_RST_NIG (0x1<<7) | 5741 | #define MISC_REGISTERS_RESET_REG_1_RST_NIG (0x1<<7) |