]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Yitchak Gertner <gertner@broadcom.com> |
2 | Subject: bnx2x: EEH recovery fix | |
3 | Acked-by: Karsten Keil <kkeil@novell.com> | |
4 | Reference: bnc#433875 | |
5 | ||
6 | ||
7 | When EEH detects an i/o error it resets the device thus it cannot be accessed. | |
8 | In this case the driver needs to unload its interface only with OS, kernel and | |
9 | network stack but not with the device. | |
10 | After successful recovery, the driver can load normally. | |
11 | ||
12 | Signed-off-by: Yitchak Gertner <gertner@broadcom.com> | |
13 | Signed-off-by: Eilon Greenstein <eilong@broadcom.com> | |
14 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
15 | ||
16 | ||
17 | --- | |
18 | drivers/net/bnx2x_main.c | 95 +++++++++++++++++++++++++++++++++++++++++------ | |
19 | 1 file changed, 83 insertions(+), 12 deletions(-) | |
20 | ||
21 | --- a/drivers/net/bnx2x_main.c | |
22 | +++ b/drivers/net/bnx2x_main.c | |
23 | @@ -59,8 +59,8 @@ | |
24 | #include "bnx2x.h" | |
25 | #include "bnx2x_init.h" | |
26 | ||
27 | -#define DRV_MODULE_VERSION "1.45.21" | |
28 | -#define DRV_MODULE_RELDATE "2008/09/03" | |
29 | +#define DRV_MODULE_VERSION "1.45.22" | |
30 | +#define DRV_MODULE_RELDATE "2008/09/09" | |
31 | #define BNX2X_BC_VER 0x040200 | |
32 | ||
33 | /* Time in jiffies before concluding the transmitter is hung */ | |
34 | @@ -649,15 +649,16 @@ static void bnx2x_int_disable(struct bnx | |
35 | BNX2X_ERR("BUG! proper val not read from IGU!\n"); | |
36 | } | |
37 | ||
38 | -static void bnx2x_int_disable_sync(struct bnx2x *bp) | |
39 | +static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) | |
40 | { | |
41 | int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; | |
42 | int i; | |
43 | ||
44 | /* disable interrupt handling */ | |
45 | atomic_inc(&bp->intr_sem); | |
46 | - /* prevent the HW from sending interrupts */ | |
47 | - bnx2x_int_disable(bp); | |
48 | + if (disable_hw) | |
49 | + /* prevent the HW from sending interrupts */ | |
50 | + bnx2x_int_disable(bp); | |
51 | ||
52 | /* make sure all ISRs are done */ | |
53 | if (msix) { | |
54 | @@ -6086,9 +6087,9 @@ static void bnx2x_netif_start(struct bnx | |
55 | } | |
56 | } | |
57 | ||
58 | -static void bnx2x_netif_stop(struct bnx2x *bp) | |
59 | +static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw) | |
60 | { | |
61 | - bnx2x_int_disable_sync(bp); | |
62 | + bnx2x_int_disable_sync(bp, disable_hw); | |
63 | if (netif_running(bp->dev)) { | |
64 | bnx2x_napi_disable(bp); | |
65 | netif_tx_disable(bp->dev); | |
66 | @@ -6475,7 +6476,7 @@ load_rings_free: | |
67 | for_each_queue(bp, i) | |
68 | bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); | |
69 | load_int_disable: | |
70 | - bnx2x_int_disable_sync(bp); | |
71 | + bnx2x_int_disable_sync(bp, 1); | |
72 | /* Release IRQs */ | |
73 | bnx2x_free_irq(bp); | |
74 | load_error: | |
75 | @@ -6651,7 +6652,7 @@ static int bnx2x_nic_unload(struct bnx2x | |
76 | bp->rx_mode = BNX2X_RX_MODE_NONE; | |
77 | bnx2x_set_storm_rx_mode(bp); | |
78 | ||
79 | - bnx2x_netif_stop(bp); | |
80 | + bnx2x_netif_stop(bp, 1); | |
81 | if (!netif_running(bp->dev)) | |
82 | bnx2x_napi_disable(bp); | |
83 | del_timer_sync(&bp->timer); | |
84 | @@ -8796,7 +8797,7 @@ static int bnx2x_test_loopback(struct bn | |
85 | if (!netif_running(bp->dev)) | |
86 | return BNX2X_LOOPBACK_FAILED; | |
87 | ||
88 | - bnx2x_netif_stop(bp); | |
89 | + bnx2x_netif_stop(bp, 1); | |
90 | ||
91 | if (bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up)) { | |
92 | DP(NETIF_MSG_PROBE, "MAC loopback failed\n"); | |
93 | @@ -10351,6 +10352,74 @@ static int bnx2x_resume(struct pci_dev * | |
94 | return rc; | |
95 | } | |
96 | ||
97 | +static int bnx2x_eeh_nic_unload(struct bnx2x *bp) | |
98 | +{ | |
99 | + int i; | |
100 | + | |
101 | + bp->state = BNX2X_STATE_ERROR; | |
102 | + | |
103 | + bp->rx_mode = BNX2X_RX_MODE_NONE; | |
104 | + | |
105 | + bnx2x_netif_stop(bp, 0); | |
106 | + | |
107 | + del_timer_sync(&bp->timer); | |
108 | + bp->stats_state = STATS_STATE_DISABLED; | |
109 | + DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n"); | |
110 | + | |
111 | + /* Release IRQs */ | |
112 | + bnx2x_free_irq(bp); | |
113 | + | |
114 | + if (CHIP_IS_E1(bp)) { | |
115 | + struct mac_configuration_cmd *config = | |
116 | + bnx2x_sp(bp, mcast_config); | |
117 | + | |
118 | + for (i = 0; i < config->hdr.length_6b; i++) | |
119 | + CAM_INVALIDATE(config->config_table[i]); | |
120 | + } | |
121 | + | |
122 | + /* Free SKBs, SGEs, TPA pool and driver internals */ | |
123 | + bnx2x_free_skbs(bp); | |
124 | + for_each_queue(bp, i) | |
125 | + bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); | |
126 | + bnx2x_free_mem(bp); | |
127 | + | |
128 | + bp->state = BNX2X_STATE_CLOSED; | |
129 | + | |
130 | + netif_carrier_off(bp->dev); | |
131 | + | |
132 | + return 0; | |
133 | +} | |
134 | + | |
135 | +static void bnx2x_eeh_recover(struct bnx2x *bp) | |
136 | +{ | |
137 | + u32 val; | |
138 | + | |
139 | + mutex_init(&bp->port.phy_mutex); | |
140 | + | |
141 | + bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); | |
142 | + bp->link_params.shmem_base = bp->common.shmem_base; | |
143 | + BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base); | |
144 | + | |
145 | + if (!bp->common.shmem_base || | |
146 | + (bp->common.shmem_base < 0xA0000) || | |
147 | + (bp->common.shmem_base >= 0xC0000)) { | |
148 | + BNX2X_DEV_INFO("MCP not active\n"); | |
149 | + bp->flags |= NO_MCP_FLAG; | |
150 | + return; | |
151 | + } | |
152 | + | |
153 | + val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]); | |
154 | + if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) | |
155 | + != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) | |
156 | + BNX2X_ERR("BAD MCP validity signature\n"); | |
157 | + | |
158 | + if (!BP_NOMCP(bp)) { | |
159 | + bp->fw_seq = (SHMEM_RD(bp, func_mb[BP_FUNC(bp)].drv_mb_header) | |
160 | + & DRV_MSG_SEQ_NUMBER_MASK); | |
161 | + BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); | |
162 | + } | |
163 | +} | |
164 | + | |
165 | /** | |
166 | * bnx2x_io_error_detected - called when PCI error is detected | |
167 | * @pdev: Pointer to PCI device | |
168 | @@ -10370,7 +10439,7 @@ static pci_ers_result_t bnx2x_io_error_d | |
169 | netif_device_detach(dev); | |
170 | ||
171 | if (netif_running(dev)) | |
172 | - bnx2x_nic_unload(bp, UNLOAD_CLOSE); | |
173 | + bnx2x_eeh_nic_unload(bp); | |
174 | ||
175 | pci_disable_device(pdev); | |
176 | ||
177 | @@ -10425,8 +10494,10 @@ static void bnx2x_io_resume(struct pci_d | |
178 | ||
179 | rtnl_lock(); | |
180 | ||
181 | + bnx2x_eeh_recover(bp); | |
182 | + | |
183 | if (netif_running(dev)) | |
184 | - bnx2x_nic_load(bp, LOAD_OPEN); | |
185 | + bnx2x_nic_load(bp, LOAD_NORMAL); | |
186 | ||
187 | netif_device_attach(dev); | |
188 |