diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c')
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c | 1332 |
1 files changed, 0 insertions, 1332 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c deleted file mode 100644 index de79cde233d..00000000000 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c +++ /dev/null | |||
@@ -1,1332 +0,0 @@ | |||
1 | /* | ||
2 | * QLogic qlcnic NIC Driver | ||
3 | * Copyright (c) 2009-2010 QLogic Corporation | ||
4 | * | ||
5 | * See LICENSE.qlcnic for copyright and licensing details. | ||
6 | */ | ||
7 | |||
8 | #include <linux/netdevice.h> | ||
9 | #include <linux/delay.h> | ||
10 | #include <linux/slab.h> | ||
11 | #include <linux/if_vlan.h> | ||
12 | #include "qlcnic.h" | ||
13 | |||
14 | struct crb_addr_pair { | ||
15 | u32 addr; | ||
16 | u32 data; | ||
17 | }; | ||
18 | |||
19 | #define QLCNIC_MAX_CRB_XFORM 60 | ||
20 | static unsigned int crb_addr_xform[QLCNIC_MAX_CRB_XFORM]; | ||
21 | |||
22 | #define crb_addr_transform(name) \ | ||
23 | (crb_addr_xform[QLCNIC_HW_PX_MAP_CRB_##name] = \ | ||
24 | QLCNIC_HW_CRB_HUB_AGT_ADR_##name << 20) | ||
25 | |||
26 | #define QLCNIC_ADDR_ERROR (0xffffffff) | ||
27 | |||
28 | static int | ||
29 | qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter); | ||
30 | |||
31 | static void crb_addr_transform_setup(void) | ||
32 | { | ||
33 | crb_addr_transform(XDMA); | ||
34 | crb_addr_transform(TIMR); | ||
35 | crb_addr_transform(SRE); | ||
36 | crb_addr_transform(SQN3); | ||
37 | crb_addr_transform(SQN2); | ||
38 | crb_addr_transform(SQN1); | ||
39 | crb_addr_transform(SQN0); | ||
40 | crb_addr_transform(SQS3); | ||
41 | crb_addr_transform(SQS2); | ||
42 | crb_addr_transform(SQS1); | ||
43 | crb_addr_transform(SQS0); | ||
44 | crb_addr_transform(RPMX7); | ||
45 | crb_addr_transform(RPMX6); | ||
46 | crb_addr_transform(RPMX5); | ||
47 | crb_addr_transform(RPMX4); | ||
48 | crb_addr_transform(RPMX3); | ||
49 | crb_addr_transform(RPMX2); | ||
50 | crb_addr_transform(RPMX1); | ||
51 | crb_addr_transform(RPMX0); | ||
52 | crb_addr_transform(ROMUSB); | ||
53 | crb_addr_transform(SN); | ||
54 | crb_addr_transform(QMN); | ||
55 | crb_addr_transform(QMS); | ||
56 | crb_addr_transform(PGNI); | ||
57 | crb_addr_transform(PGND); | ||
58 | crb_addr_transform(PGN3); | ||
59 | crb_addr_transform(PGN2); | ||
60 | crb_addr_transform(PGN1); | ||
61 | crb_addr_transform(PGN0); | ||
62 | crb_addr_transform(PGSI); | ||
63 | crb_addr_transform(PGSD); | ||
64 | crb_addr_transform(PGS3); | ||
65 | crb_addr_transform(PGS2); | ||
66 | crb_addr_transform(PGS1); | ||
67 | crb_addr_transform(PGS0); | ||
68 | crb_addr_transform(PS); | ||
69 | crb_addr_transform(PH); | ||
70 | crb_addr_transform(NIU); | ||
71 | crb_addr_transform(I2Q); | ||
72 | crb_addr_transform(EG); | ||
73 | crb_addr_transform(MN); | ||
74 | crb_addr_transform(MS); | ||
75 | crb_addr_transform(CAS2); | ||
76 | crb_addr_transform(CAS1); | ||
77 | crb_addr_transform(CAS0); | ||
78 | crb_addr_transform(CAM); | ||
79 | crb_addr_transform(C2C1); | ||
80 | crb_addr_transform(C2C0); | ||
81 | crb_addr_transform(SMB); | ||
82 | crb_addr_transform(OCM0); | ||
83 | crb_addr_transform(I2C0); | ||
84 | } | ||
85 | |||
86 | void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter) | ||
87 | { | ||
88 | struct qlcnic_recv_context *recv_ctx; | ||
89 | struct qlcnic_host_rds_ring *rds_ring; | ||
90 | struct qlcnic_rx_buffer *rx_buf; | ||
91 | int i, ring; | ||
92 | |||
93 | recv_ctx = adapter->recv_ctx; | ||
94 | for (ring = 0; ring < adapter->max_rds_rings; ring++) { | ||
95 | rds_ring = &recv_ctx->rds_rings[ring]; | ||
96 | for (i = 0; i < rds_ring->num_desc; ++i) { | ||
97 | rx_buf = &(rds_ring->rx_buf_arr[i]); | ||
98 | if (rx_buf->skb == NULL) | ||
99 | continue; | ||
100 | |||
101 | pci_unmap_single(adapter->pdev, | ||
102 | rx_buf->dma, | ||
103 | rds_ring->dma_size, | ||
104 | PCI_DMA_FROMDEVICE); | ||
105 | |||
106 | dev_kfree_skb_any(rx_buf->skb); | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | |||
111 | void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter) | ||
112 | { | ||
113 | struct qlcnic_recv_context *recv_ctx; | ||
114 | struct qlcnic_host_rds_ring *rds_ring; | ||
115 | struct qlcnic_rx_buffer *rx_buf; | ||
116 | int i, ring; | ||
117 | |||
118 | recv_ctx = adapter->recv_ctx; | ||
119 | for (ring = 0; ring < adapter->max_rds_rings; ring++) { | ||
120 | rds_ring = &recv_ctx->rds_rings[ring]; | ||
121 | |||
122 | INIT_LIST_HEAD(&rds_ring->free_list); | ||
123 | |||
124 | rx_buf = rds_ring->rx_buf_arr; | ||
125 | for (i = 0; i < rds_ring->num_desc; i++) { | ||
126 | list_add_tail(&rx_buf->list, | ||
127 | &rds_ring->free_list); | ||
128 | rx_buf++; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter) | ||
134 | { | ||
135 | struct qlcnic_cmd_buffer *cmd_buf; | ||
136 | struct qlcnic_skb_frag *buffrag; | ||
137 | int i, j; | ||
138 | struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; | ||
139 | |||
140 | cmd_buf = tx_ring->cmd_buf_arr; | ||
141 | for (i = 0; i < tx_ring->num_desc; i++) { | ||
142 | buffrag = cmd_buf->frag_array; | ||
143 | if (buffrag->dma) { | ||
144 | pci_unmap_single(adapter->pdev, buffrag->dma, | ||
145 | buffrag->length, PCI_DMA_TODEVICE); | ||
146 | buffrag->dma = 0ULL; | ||
147 | } | ||
148 | for (j = 0; j < cmd_buf->frag_count; j++) { | ||
149 | buffrag++; | ||
150 | if (buffrag->dma) { | ||
151 | pci_unmap_page(adapter->pdev, buffrag->dma, | ||
152 | buffrag->length, | ||
153 | PCI_DMA_TODEVICE); | ||
154 | buffrag->dma = 0ULL; | ||
155 | } | ||
156 | } | ||
157 | if (cmd_buf->skb) { | ||
158 | dev_kfree_skb_any(cmd_buf->skb); | ||
159 | cmd_buf->skb = NULL; | ||
160 | } | ||
161 | cmd_buf++; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter) | ||
166 | { | ||
167 | struct qlcnic_recv_context *recv_ctx; | ||
168 | struct qlcnic_host_rds_ring *rds_ring; | ||
169 | struct qlcnic_host_tx_ring *tx_ring; | ||
170 | int ring; | ||
171 | |||
172 | recv_ctx = adapter->recv_ctx; | ||
173 | |||
174 | if (recv_ctx->rds_rings == NULL) | ||
175 | goto skip_rds; | ||
176 | |||
177 | for (ring = 0; ring < adapter->max_rds_rings; ring++) { | ||
178 | rds_ring = &recv_ctx->rds_rings[ring]; | ||
179 | vfree(rds_ring->rx_buf_arr); | ||
180 | rds_ring->rx_buf_arr = NULL; | ||
181 | } | ||
182 | kfree(recv_ctx->rds_rings); | ||
183 | |||
184 | skip_rds: | ||
185 | if (adapter->tx_ring == NULL) | ||
186 | return; | ||
187 | |||
188 | tx_ring = adapter->tx_ring; | ||
189 | vfree(tx_ring->cmd_buf_arr); | ||
190 | tx_ring->cmd_buf_arr = NULL; | ||
191 | kfree(adapter->tx_ring); | ||
192 | adapter->tx_ring = NULL; | ||
193 | } | ||
194 | |||
195 | int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter) | ||
196 | { | ||
197 | struct qlcnic_recv_context *recv_ctx; | ||
198 | struct qlcnic_host_rds_ring *rds_ring; | ||
199 | struct qlcnic_host_sds_ring *sds_ring; | ||
200 | struct qlcnic_host_tx_ring *tx_ring; | ||
201 | struct qlcnic_rx_buffer *rx_buf; | ||
202 | int ring, i, size; | ||
203 | |||
204 | struct qlcnic_cmd_buffer *cmd_buf_arr; | ||
205 | struct net_device *netdev = adapter->netdev; | ||
206 | |||
207 | size = sizeof(struct qlcnic_host_tx_ring); | ||
208 | tx_ring = kzalloc(size, GFP_KERNEL); | ||
209 | if (tx_ring == NULL) { | ||
210 | dev_err(&netdev->dev, "failed to allocate tx ring struct\n"); | ||
211 | return -ENOMEM; | ||
212 | } | ||
213 | adapter->tx_ring = tx_ring; | ||
214 | |||
215 | tx_ring->num_desc = adapter->num_txd; | ||
216 | tx_ring->txq = netdev_get_tx_queue(netdev, 0); | ||
217 | |||
218 | cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring)); | ||
219 | if (cmd_buf_arr == NULL) { | ||
220 | dev_err(&netdev->dev, "failed to allocate cmd buffer ring\n"); | ||
221 | goto err_out; | ||
222 | } | ||
223 | tx_ring->cmd_buf_arr = cmd_buf_arr; | ||
224 | |||
225 | recv_ctx = adapter->recv_ctx; | ||
226 | |||
227 | size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring); | ||
228 | rds_ring = kzalloc(size, GFP_KERNEL); | ||
229 | if (rds_ring == NULL) { | ||
230 | dev_err(&netdev->dev, "failed to allocate rds ring struct\n"); | ||
231 | goto err_out; | ||
232 | } | ||
233 | recv_ctx->rds_rings = rds_ring; | ||
234 | |||
235 | for (ring = 0; ring < adapter->max_rds_rings; ring++) { | ||
236 | rds_ring = &recv_ctx->rds_rings[ring]; | ||
237 | switch (ring) { | ||
238 | case RCV_RING_NORMAL: | ||
239 | rds_ring->num_desc = adapter->num_rxd; | ||
240 | rds_ring->dma_size = QLCNIC_P3P_RX_BUF_MAX_LEN; | ||
241 | rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN; | ||
242 | break; | ||
243 | |||
244 | case RCV_RING_JUMBO: | ||
245 | rds_ring->num_desc = adapter->num_jumbo_rxd; | ||
246 | rds_ring->dma_size = | ||
247 | QLCNIC_P3P_RX_JUMBO_BUF_MAX_LEN; | ||
248 | |||
249 | if (adapter->ahw->capabilities & | ||
250 | QLCNIC_FW_CAPABILITY_HW_LRO) | ||
251 | rds_ring->dma_size += QLCNIC_LRO_BUFFER_EXTRA; | ||
252 | |||
253 | rds_ring->skb_size = | ||
254 | rds_ring->dma_size + NET_IP_ALIGN; | ||
255 | break; | ||
256 | } | ||
257 | rds_ring->rx_buf_arr = vzalloc(RCV_BUFF_RINGSIZE(rds_ring)); | ||
258 | if (rds_ring->rx_buf_arr == NULL) { | ||
259 | dev_err(&netdev->dev, "Failed to allocate " | ||
260 | "rx buffer ring %d\n", ring); | ||
261 | goto err_out; | ||
262 | } | ||
263 | INIT_LIST_HEAD(&rds_ring->free_list); | ||
264 | /* | ||
265 | * Now go through all of them, set reference handles | ||
266 | * and put them in the queues. | ||
267 | */ | ||
268 | rx_buf = rds_ring->rx_buf_arr; | ||
269 | for (i = 0; i < rds_ring->num_desc; i++) { | ||
270 | list_add_tail(&rx_buf->list, | ||
271 | &rds_ring->free_list); | ||
272 | rx_buf->ref_handle = i; | ||
273 | rx_buf++; | ||
274 | } | ||
275 | spin_lock_init(&rds_ring->lock); | ||
276 | } | ||
277 | |||
278 | for (ring = 0; ring < adapter->max_sds_rings; ring++) { | ||
279 | sds_ring = &recv_ctx->sds_rings[ring]; | ||
280 | sds_ring->irq = adapter->msix_entries[ring].vector; | ||
281 | sds_ring->adapter = adapter; | ||
282 | sds_ring->num_desc = adapter->num_rxd; | ||
283 | |||
284 | for (i = 0; i < NUM_RCV_DESC_RINGS; i++) | ||
285 | INIT_LIST_HEAD(&sds_ring->free_list[i]); | ||
286 | } | ||
287 | |||
288 | return 0; | ||
289 | |||
290 | err_out: | ||
291 | qlcnic_free_sw_resources(adapter); | ||
292 | return -ENOMEM; | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * Utility to translate from internal Phantom CRB address | ||
297 | * to external PCI CRB address. | ||
298 | */ | ||
299 | static u32 qlcnic_decode_crb_addr(u32 addr) | ||
300 | { | ||
301 | int i; | ||
302 | u32 base_addr, offset, pci_base; | ||
303 | |||
304 | crb_addr_transform_setup(); | ||
305 | |||
306 | pci_base = QLCNIC_ADDR_ERROR; | ||
307 | base_addr = addr & 0xfff00000; | ||
308 | offset = addr & 0x000fffff; | ||
309 | |||
310 | for (i = 0; i < QLCNIC_MAX_CRB_XFORM; i++) { | ||
311 | if (crb_addr_xform[i] == base_addr) { | ||
312 | pci_base = i << 20; | ||
313 | break; | ||
314 | } | ||
315 | } | ||
316 | if (pci_base == QLCNIC_ADDR_ERROR) | ||
317 | return pci_base; | ||
318 | else | ||
319 | return pci_base + offset; | ||
320 | } | ||
321 | |||
322 | #define QLCNIC_MAX_ROM_WAIT_USEC 100 | ||
323 | |||
324 | static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter) | ||
325 | { | ||
326 | long timeout = 0; | ||
327 | long done = 0; | ||
328 | |||
329 | cond_resched(); | ||
330 | |||
331 | while (done == 0) { | ||
332 | done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS); | ||
333 | done &= 2; | ||
334 | if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) { | ||
335 | dev_err(&adapter->pdev->dev, | ||
336 | "Timeout reached waiting for rom done"); | ||
337 | return -EIO; | ||
338 | } | ||
339 | udelay(1); | ||
340 | } | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int do_rom_fast_read(struct qlcnic_adapter *adapter, | ||
345 | u32 addr, u32 *valp) | ||
346 | { | ||
347 | QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr); | ||
348 | QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); | ||
349 | QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3); | ||
350 | QLCWR32(adapter, QLCNIC_ROMUSB_ROM_INSTR_OPCODE, 0xb); | ||
351 | if (qlcnic_wait_rom_done(adapter)) { | ||
352 | dev_err(&adapter->pdev->dev, "Error waiting for rom done\n"); | ||
353 | return -EIO; | ||
354 | } | ||
355 | /* reset abyte_cnt and dummy_byte_cnt */ | ||
356 | QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 0); | ||
357 | udelay(10); | ||
358 | QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); | ||
359 | |||
360 | *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA); | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int do_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, | ||
365 | u8 *bytes, size_t size) | ||
366 | { | ||
367 | int addridx; | ||
368 | int ret = 0; | ||
369 | |||
370 | for (addridx = addr; addridx < (addr + size); addridx += 4) { | ||
371 | int v; | ||
372 | ret = do_rom_fast_read(adapter, addridx, &v); | ||
373 | if (ret != 0) | ||
374 | break; | ||
375 | *(__le32 *)bytes = cpu_to_le32(v); | ||
376 | bytes += 4; | ||
377 | } | ||
378 | |||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | int | ||
383 | qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, | ||
384 | u8 *bytes, size_t size) | ||
385 | { | ||
386 | int ret; | ||
387 | |||
388 | ret = qlcnic_rom_lock(adapter); | ||
389 | if (ret < 0) | ||
390 | return ret; | ||
391 | |||
392 | ret = do_rom_fast_read_words(adapter, addr, bytes, size); | ||
393 | |||
394 | qlcnic_rom_unlock(adapter); | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp) | ||
399 | { | ||
400 | int ret; | ||
401 | |||
402 | if (qlcnic_rom_lock(adapter) != 0) | ||
403 | return -EIO; | ||
404 | |||
405 | ret = do_rom_fast_read(adapter, addr, valp); | ||
406 | qlcnic_rom_unlock(adapter); | ||
407 | return ret; | ||
408 | } | ||
409 | |||
410 | int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter) | ||
411 | { | ||
412 | int addr, val; | ||
413 | int i, n, init_delay; | ||
414 | struct crb_addr_pair *buf; | ||
415 | unsigned offset; | ||
416 | u32 off; | ||
417 | struct pci_dev *pdev = adapter->pdev; | ||
418 | |||
419 | QLCWR32(adapter, CRB_CMDPEG_STATE, 0); | ||
420 | QLCWR32(adapter, CRB_RCVPEG_STATE, 0); | ||
421 | |||
422 | /* Halt all the indiviual PEGs and other blocks */ | ||
423 | /* disable all I2Q */ | ||
424 | QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x10, 0x0); | ||
425 | QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x14, 0x0); | ||
426 | QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x18, 0x0); | ||
427 | QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x1c, 0x0); | ||
428 | QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x20, 0x0); | ||
429 | QLCWR32(adapter, QLCNIC_CRB_I2Q + 0x24, 0x0); | ||
430 | |||
431 | /* disable all niu interrupts */ | ||
432 | QLCWR32(adapter, QLCNIC_CRB_NIU + 0x40, 0xff); | ||
433 | /* disable xge rx/tx */ | ||
434 | QLCWR32(adapter, QLCNIC_CRB_NIU + 0x70000, 0x00); | ||
435 | /* disable xg1 rx/tx */ | ||
436 | QLCWR32(adapter, QLCNIC_CRB_NIU + 0x80000, 0x00); | ||
437 | /* disable sideband mac */ | ||
438 | QLCWR32(adapter, QLCNIC_CRB_NIU + 0x90000, 0x00); | ||
439 | /* disable ap0 mac */ | ||
440 | QLCWR32(adapter, QLCNIC_CRB_NIU + 0xa0000, 0x00); | ||
441 | /* disable ap1 mac */ | ||
442 | QLCWR32(adapter, QLCNIC_CRB_NIU + 0xb0000, 0x00); | ||
443 | |||
444 | /* halt sre */ | ||
445 | val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000); | ||
446 | QLCWR32(adapter, QLCNIC_CRB_SRE + 0x1000, val & (~(0x1))); | ||
447 | |||
448 | /* halt epg */ | ||
449 | QLCWR32(adapter, QLCNIC_CRB_EPG + 0x1300, 0x1); | ||
450 | |||
451 | /* halt timers */ | ||
452 | QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x0, 0x0); | ||
453 | QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x8, 0x0); | ||
454 | QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x10, 0x0); | ||
455 | QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x18, 0x0); | ||
456 | QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x100, 0x0); | ||
457 | QLCWR32(adapter, QLCNIC_CRB_TIMER + 0x200, 0x0); | ||
458 | /* halt pegs */ | ||
459 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c, 1); | ||
460 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c, 1); | ||
461 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c, 1); | ||
462 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c, 1); | ||
463 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, 1); | ||
464 | msleep(20); | ||
465 | |||
466 | qlcnic_rom_unlock(adapter); | ||
467 | /* big hammer don't reset CAM block on reset */ | ||
468 | QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xfeffffff); | ||
469 | |||
470 | /* Init HW CRB block */ | ||
471 | if (qlcnic_rom_fast_read(adapter, 0, &n) != 0 || (n != 0xcafecafe) || | ||
472 | qlcnic_rom_fast_read(adapter, 4, &n) != 0) { | ||
473 | dev_err(&pdev->dev, "ERROR Reading crb_init area: val:%x\n", n); | ||
474 | return -EIO; | ||
475 | } | ||
476 | offset = n & 0xffffU; | ||
477 | n = (n >> 16) & 0xffffU; | ||
478 | |||
479 | if (n >= 1024) { | ||
480 | dev_err(&pdev->dev, "QLOGIC card flash not initialized.\n"); | ||
481 | return -EIO; | ||
482 | } | ||
483 | |||
484 | buf = kcalloc(n, sizeof(struct crb_addr_pair), GFP_KERNEL); | ||
485 | if (buf == NULL) { | ||
486 | dev_err(&pdev->dev, "Unable to calloc memory for rom read.\n"); | ||
487 | return -ENOMEM; | ||
488 | } | ||
489 | |||
490 | for (i = 0; i < n; i++) { | ||
491 | if (qlcnic_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 || | ||
492 | qlcnic_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) { | ||
493 | kfree(buf); | ||
494 | return -EIO; | ||
495 | } | ||
496 | |||
497 | buf[i].addr = addr; | ||
498 | buf[i].data = val; | ||
499 | } | ||
500 | |||
501 | for (i = 0; i < n; i++) { | ||
502 | |||
503 | off = qlcnic_decode_crb_addr(buf[i].addr); | ||
504 | if (off == QLCNIC_ADDR_ERROR) { | ||
505 | dev_err(&pdev->dev, "CRB init value out of range %x\n", | ||
506 | buf[i].addr); | ||
507 | continue; | ||
508 | } | ||
509 | off += QLCNIC_PCI_CRBSPACE; | ||
510 | |||
511 | if (off & 1) | ||
512 | continue; | ||
513 | |||
514 | /* skipping cold reboot MAGIC */ | ||
515 | if (off == QLCNIC_CAM_RAM(0x1fc)) | ||
516 | continue; | ||
517 | if (off == (QLCNIC_CRB_I2C0 + 0x1c)) | ||
518 | continue; | ||
519 | if (off == (ROMUSB_GLB + 0xbc)) /* do not reset PCI */ | ||
520 | continue; | ||
521 | if (off == (ROMUSB_GLB + 0xa8)) | ||
522 | continue; | ||
523 | if (off == (ROMUSB_GLB + 0xc8)) /* core clock */ | ||
524 | continue; | ||
525 | if (off == (ROMUSB_GLB + 0x24)) /* MN clock */ | ||
526 | continue; | ||
527 | if (off == (ROMUSB_GLB + 0x1c)) /* MS clock */ | ||
528 | continue; | ||
529 | if ((off & 0x0ff00000) == QLCNIC_CRB_DDR_NET) | ||
530 | continue; | ||
531 | /* skip the function enable register */ | ||
532 | if (off == QLCNIC_PCIE_REG(PCIE_SETUP_FUNCTION)) | ||
533 | continue; | ||
534 | if (off == QLCNIC_PCIE_REG(PCIE_SETUP_FUNCTION2)) | ||
535 | continue; | ||
536 | if ((off & 0x0ff00000) == QLCNIC_CRB_SMB) | ||
537 | continue; | ||
538 | |||
539 | init_delay = 1; | ||
540 | /* After writing this register, HW needs time for CRB */ | ||
541 | /* to quiet down (else crb_window returns 0xffffffff) */ | ||
542 | if (off == QLCNIC_ROMUSB_GLB_SW_RESET) | ||
543 | init_delay = 1000; | ||
544 | |||
545 | QLCWR32(adapter, off, buf[i].data); | ||
546 | |||
547 | msleep(init_delay); | ||
548 | } | ||
549 | kfree(buf); | ||
550 | |||
551 | /* Initialize protocol process engine */ | ||
552 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0xec, 0x1e); | ||
553 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0x4c, 8); | ||
554 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_I + 0x4c, 8); | ||
555 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x8, 0); | ||
556 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0xc, 0); | ||
557 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x8, 0); | ||
558 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0xc, 0); | ||
559 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x8, 0); | ||
560 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0xc, 0); | ||
561 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x8, 0); | ||
562 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0xc, 0); | ||
563 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x8, 0); | ||
564 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0xc, 0); | ||
565 | msleep(1); | ||
566 | |||
567 | QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0); | ||
568 | QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter) | ||
574 | { | ||
575 | u32 val; | ||
576 | int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT; | ||
577 | |||
578 | do { | ||
579 | val = QLCRD32(adapter, CRB_CMDPEG_STATE); | ||
580 | |||
581 | switch (val) { | ||
582 | case PHAN_INITIALIZE_COMPLETE: | ||
583 | case PHAN_INITIALIZE_ACK: | ||
584 | return 0; | ||
585 | case PHAN_INITIALIZE_FAILED: | ||
586 | goto out_err; | ||
587 | default: | ||
588 | break; | ||
589 | } | ||
590 | |||
591 | msleep(QLCNIC_CMDPEG_CHECK_DELAY); | ||
592 | |||
593 | } while (--retries); | ||
594 | |||
595 | QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED); | ||
596 | |||
597 | out_err: | ||
598 | dev_err(&adapter->pdev->dev, "Command Peg initialization not " | ||
599 | "complete, state: 0x%x.\n", val); | ||
600 | return -EIO; | ||
601 | } | ||
602 | |||
603 | static int | ||
604 | qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter) | ||
605 | { | ||
606 | u32 val; | ||
607 | int retries = QLCNIC_RCVPEG_CHECK_RETRY_COUNT; | ||
608 | |||
609 | do { | ||
610 | val = QLCRD32(adapter, CRB_RCVPEG_STATE); | ||
611 | |||
612 | if (val == PHAN_PEG_RCV_INITIALIZED) | ||
613 | return 0; | ||
614 | |||
615 | msleep(QLCNIC_RCVPEG_CHECK_DELAY); | ||
616 | |||
617 | } while (--retries); | ||
618 | |||
619 | if (!retries) { | ||
620 | dev_err(&adapter->pdev->dev, "Receive Peg initialization not " | ||
621 | "complete, state: 0x%x.\n", val); | ||
622 | return -EIO; | ||
623 | } | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | int | ||
629 | qlcnic_check_fw_status(struct qlcnic_adapter *adapter) | ||
630 | { | ||
631 | int err; | ||
632 | |||
633 | err = qlcnic_cmd_peg_ready(adapter); | ||
634 | if (err) | ||
635 | return err; | ||
636 | |||
637 | err = qlcnic_receive_peg_ready(adapter); | ||
638 | if (err) | ||
639 | return err; | ||
640 | |||
641 | QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); | ||
642 | |||
643 | return err; | ||
644 | } | ||
645 | |||
646 | int | ||
647 | qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) { | ||
648 | |||
649 | int timeo; | ||
650 | u32 val; | ||
651 | |||
652 | val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO); | ||
653 | val = QLC_DEV_GET_DRV(val, adapter->portnum); | ||
654 | if ((val & 0x3) != QLCNIC_TYPE_NIC) { | ||
655 | dev_err(&adapter->pdev->dev, | ||
656 | "Not an Ethernet NIC func=%u\n", val); | ||
657 | return -EIO; | ||
658 | } | ||
659 | adapter->ahw->physical_port = (val >> 2); | ||
660 | if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DEV_INIT_TIMEOUT, &timeo)) | ||
661 | timeo = QLCNIC_INIT_TIMEOUT_SECS; | ||
662 | |||
663 | adapter->dev_init_timeo = timeo; | ||
664 | |||
665 | if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DRV_RESET_TIMEOUT, &timeo)) | ||
666 | timeo = QLCNIC_RESET_TIMEOUT_SECS; | ||
667 | |||
668 | adapter->reset_ack_timeo = timeo; | ||
669 | |||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | static int qlcnic_get_flt_entry(struct qlcnic_adapter *adapter, u8 region, | ||
674 | struct qlcnic_flt_entry *region_entry) | ||
675 | { | ||
676 | struct qlcnic_flt_header flt_hdr; | ||
677 | struct qlcnic_flt_entry *flt_entry; | ||
678 | int i = 0, ret; | ||
679 | u32 entry_size; | ||
680 | |||
681 | memset(region_entry, 0, sizeof(struct qlcnic_flt_entry)); | ||
682 | ret = qlcnic_rom_fast_read_words(adapter, QLCNIC_FLT_LOCATION, | ||
683 | (u8 *)&flt_hdr, | ||
684 | sizeof(struct qlcnic_flt_header)); | ||
685 | if (ret) { | ||
686 | dev_warn(&adapter->pdev->dev, | ||
687 | "error reading flash layout header\n"); | ||
688 | return -EIO; | ||
689 | } | ||
690 | |||
691 | entry_size = flt_hdr.len - sizeof(struct qlcnic_flt_header); | ||
692 | flt_entry = (struct qlcnic_flt_entry *)vzalloc(entry_size); | ||
693 | if (flt_entry == NULL) { | ||
694 | dev_warn(&adapter->pdev->dev, "error allocating memory\n"); | ||
695 | return -EIO; | ||
696 | } | ||
697 | |||
698 | ret = qlcnic_rom_fast_read_words(adapter, QLCNIC_FLT_LOCATION + | ||
699 | sizeof(struct qlcnic_flt_header), | ||
700 | (u8 *)flt_entry, entry_size); | ||
701 | if (ret) { | ||
702 | dev_warn(&adapter->pdev->dev, | ||
703 | "error reading flash layout entries\n"); | ||
704 | goto err_out; | ||
705 | } | ||
706 | |||
707 | while (i < (entry_size/sizeof(struct qlcnic_flt_entry))) { | ||
708 | if (flt_entry[i].region == region) | ||
709 | break; | ||
710 | i++; | ||
711 | } | ||
712 | if (i >= (entry_size/sizeof(struct qlcnic_flt_entry))) { | ||
713 | dev_warn(&adapter->pdev->dev, | ||
714 | "region=%x not found in %d regions\n", region, i); | ||
715 | ret = -EIO; | ||
716 | goto err_out; | ||
717 | } | ||
718 | memcpy(region_entry, &flt_entry[i], sizeof(struct qlcnic_flt_entry)); | ||
719 | |||
720 | err_out: | ||
721 | vfree(flt_entry); | ||
722 | return ret; | ||
723 | } | ||
724 | |||
725 | int | ||
726 | qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter) | ||
727 | { | ||
728 | struct qlcnic_flt_entry fw_entry; | ||
729 | u32 ver = -1, min_ver; | ||
730 | int ret; | ||
731 | |||
732 | if (adapter->ahw->revision_id == QLCNIC_P3P_C0) | ||
733 | ret = qlcnic_get_flt_entry(adapter, QLCNIC_C0_FW_IMAGE_REGION, | ||
734 | &fw_entry); | ||
735 | else | ||
736 | ret = qlcnic_get_flt_entry(adapter, QLCNIC_B0_FW_IMAGE_REGION, | ||
737 | &fw_entry); | ||
738 | |||
739 | if (!ret) | ||
740 | /* 0-4:-signature, 4-8:-fw version */ | ||
741 | qlcnic_rom_fast_read(adapter, fw_entry.start_addr + 4, | ||
742 | (int *)&ver); | ||
743 | else | ||
744 | qlcnic_rom_fast_read(adapter, QLCNIC_FW_VERSION_OFFSET, | ||
745 | (int *)&ver); | ||
746 | |||
747 | ver = QLCNIC_DECODE_VERSION(ver); | ||
748 | min_ver = QLCNIC_MIN_FW_VERSION; | ||
749 | |||
750 | if (ver < min_ver) { | ||
751 | dev_err(&adapter->pdev->dev, | ||
752 | "firmware version %d.%d.%d unsupported." | ||
753 | "Min supported version %d.%d.%d\n", | ||
754 | _major(ver), _minor(ver), _build(ver), | ||
755 | _major(min_ver), _minor(min_ver), _build(min_ver)); | ||
756 | return -EINVAL; | ||
757 | } | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static int | ||
763 | qlcnic_has_mn(struct qlcnic_adapter *adapter) | ||
764 | { | ||
765 | u32 capability; | ||
766 | capability = 0; | ||
767 | |||
768 | capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY); | ||
769 | if (capability & QLCNIC_PEG_TUNE_MN_PRESENT) | ||
770 | return 1; | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | static | ||
776 | struct uni_table_desc *qlcnic_get_table_desc(const u8 *unirom, int section) | ||
777 | { | ||
778 | u32 i, entries; | ||
779 | struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0]; | ||
780 | entries = le32_to_cpu(directory->num_entries); | ||
781 | |||
782 | for (i = 0; i < entries; i++) { | ||
783 | |||
784 | u32 offs = le32_to_cpu(directory->findex) + | ||
785 | i * le32_to_cpu(directory->entry_size); | ||
786 | u32 tab_type = le32_to_cpu(*((__le32 *)&unirom[offs] + 8)); | ||
787 | |||
788 | if (tab_type == section) | ||
789 | return (struct uni_table_desc *) &unirom[offs]; | ||
790 | } | ||
791 | |||
792 | return NULL; | ||
793 | } | ||
794 | |||
795 | #define FILEHEADER_SIZE (14 * 4) | ||
796 | |||
797 | static int | ||
798 | qlcnic_validate_header(struct qlcnic_adapter *adapter) | ||
799 | { | ||
800 | const u8 *unirom = adapter->fw->data; | ||
801 | struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0]; | ||
802 | u32 entries, entry_size, tab_size, fw_file_size; | ||
803 | |||
804 | fw_file_size = adapter->fw->size; | ||
805 | |||
806 | if (fw_file_size < FILEHEADER_SIZE) | ||
807 | return -EINVAL; | ||
808 | |||
809 | entries = le32_to_cpu(directory->num_entries); | ||
810 | entry_size = le32_to_cpu(directory->entry_size); | ||
811 | tab_size = le32_to_cpu(directory->findex) + (entries * entry_size); | ||
812 | |||
813 | if (fw_file_size < tab_size) | ||
814 | return -EINVAL; | ||
815 | |||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | static int | ||
820 | qlcnic_validate_bootld(struct qlcnic_adapter *adapter) | ||
821 | { | ||
822 | struct uni_table_desc *tab_desc; | ||
823 | struct uni_data_desc *descr; | ||
824 | u32 offs, tab_size, data_size, idx; | ||
825 | const u8 *unirom = adapter->fw->data; | ||
826 | __le32 temp; | ||
827 | |||
828 | temp = *((__le32 *)&unirom[adapter->file_prd_off] + | ||
829 | QLCNIC_UNI_BOOTLD_IDX_OFF); | ||
830 | idx = le32_to_cpu(temp); | ||
831 | tab_desc = qlcnic_get_table_desc(unirom, QLCNIC_UNI_DIR_SECT_BOOTLD); | ||
832 | |||
833 | if (!tab_desc) | ||
834 | return -EINVAL; | ||
835 | |||
836 | tab_size = le32_to_cpu(tab_desc->findex) + | ||
837 | le32_to_cpu(tab_desc->entry_size) * (idx + 1); | ||
838 | |||
839 | if (adapter->fw->size < tab_size) | ||
840 | return -EINVAL; | ||
841 | |||
842 | offs = le32_to_cpu(tab_desc->findex) + | ||
843 | le32_to_cpu(tab_desc->entry_size) * idx; | ||
844 | descr = (struct uni_data_desc *)&unirom[offs]; | ||
845 | |||
846 | data_size = le32_to_cpu(descr->findex) + le32_to_cpu(descr->size); | ||
847 | |||
848 | if (adapter->fw->size < data_size) | ||
849 | return -EINVAL; | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static int | ||
855 | qlcnic_validate_fw(struct qlcnic_adapter *adapter) | ||
856 | { | ||
857 | struct uni_table_desc *tab_desc; | ||
858 | struct uni_data_desc *descr; | ||
859 | const u8 *unirom = adapter->fw->data; | ||
860 | u32 offs, tab_size, data_size, idx; | ||
861 | __le32 temp; | ||
862 | |||
863 | temp = *((__le32 *)&unirom[adapter->file_prd_off] + | ||
864 | QLCNIC_UNI_FIRMWARE_IDX_OFF); | ||
865 | idx = le32_to_cpu(temp); | ||
866 | tab_desc = qlcnic_get_table_desc(unirom, QLCNIC_UNI_DIR_SECT_FW); | ||
867 | |||
868 | if (!tab_desc) | ||
869 | return -EINVAL; | ||
870 | |||
871 | tab_size = le32_to_cpu(tab_desc->findex) + | ||
872 | le32_to_cpu(tab_desc->entry_size) * (idx + 1); | ||
873 | |||
874 | if (adapter->fw->size < tab_size) | ||
875 | return -EINVAL; | ||
876 | |||
877 | offs = le32_to_cpu(tab_desc->findex) + | ||
878 | le32_to_cpu(tab_desc->entry_size) * idx; | ||
879 | descr = (struct uni_data_desc *)&unirom[offs]; | ||
880 | data_size = le32_to_cpu(descr->findex) + le32_to_cpu(descr->size); | ||
881 | |||
882 | if (adapter->fw->size < data_size) | ||
883 | return -EINVAL; | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | |||
888 | static int | ||
889 | qlcnic_validate_product_offs(struct qlcnic_adapter *adapter) | ||
890 | { | ||
891 | struct uni_table_desc *ptab_descr; | ||
892 | const u8 *unirom = adapter->fw->data; | ||
893 | int mn_present = qlcnic_has_mn(adapter); | ||
894 | u32 entries, entry_size, tab_size, i; | ||
895 | __le32 temp; | ||
896 | |||
897 | ptab_descr = qlcnic_get_table_desc(unirom, | ||
898 | QLCNIC_UNI_DIR_SECT_PRODUCT_TBL); | ||
899 | if (!ptab_descr) | ||
900 | return -EINVAL; | ||
901 | |||
902 | entries = le32_to_cpu(ptab_descr->num_entries); | ||
903 | entry_size = le32_to_cpu(ptab_descr->entry_size); | ||
904 | tab_size = le32_to_cpu(ptab_descr->findex) + (entries * entry_size); | ||
905 | |||
906 | if (adapter->fw->size < tab_size) | ||
907 | return -EINVAL; | ||
908 | |||
909 | nomn: | ||
910 | for (i = 0; i < entries; i++) { | ||
911 | |||
912 | u32 flags, file_chiprev, offs; | ||
913 | u8 chiprev = adapter->ahw->revision_id; | ||
914 | u32 flagbit; | ||
915 | |||
916 | offs = le32_to_cpu(ptab_descr->findex) + | ||
917 | i * le32_to_cpu(ptab_descr->entry_size); | ||
918 | temp = *((__le32 *)&unirom[offs] + QLCNIC_UNI_FLAGS_OFF); | ||
919 | flags = le32_to_cpu(temp); | ||
920 | temp = *((__le32 *)&unirom[offs] + QLCNIC_UNI_CHIP_REV_OFF); | ||
921 | file_chiprev = le32_to_cpu(temp); | ||
922 | |||
923 | flagbit = mn_present ? 1 : 2; | ||
924 | |||
925 | if ((chiprev == file_chiprev) && | ||
926 | ((1ULL << flagbit) & flags)) { | ||
927 | adapter->file_prd_off = offs; | ||
928 | return 0; | ||
929 | } | ||
930 | } | ||
931 | if (mn_present) { | ||
932 | mn_present = 0; | ||
933 | goto nomn; | ||
934 | } | ||
935 | return -EINVAL; | ||
936 | } | ||
937 | |||
938 | static int | ||
939 | qlcnic_validate_unified_romimage(struct qlcnic_adapter *adapter) | ||
940 | { | ||
941 | if (qlcnic_validate_header(adapter)) { | ||
942 | dev_err(&adapter->pdev->dev, | ||
943 | "unified image: header validation failed\n"); | ||
944 | return -EINVAL; | ||
945 | } | ||
946 | |||
947 | if (qlcnic_validate_product_offs(adapter)) { | ||
948 | dev_err(&adapter->pdev->dev, | ||
949 | "unified image: product validation failed\n"); | ||
950 | return -EINVAL; | ||
951 | } | ||
952 | |||
953 | if (qlcnic_validate_bootld(adapter)) { | ||
954 | dev_err(&adapter->pdev->dev, | ||
955 | "unified image: bootld validation failed\n"); | ||
956 | return -EINVAL; | ||
957 | } | ||
958 | |||
959 | if (qlcnic_validate_fw(adapter)) { | ||
960 | dev_err(&adapter->pdev->dev, | ||
961 | "unified image: firmware validation failed\n"); | ||
962 | return -EINVAL; | ||
963 | } | ||
964 | |||
965 | return 0; | ||
966 | } | ||
967 | |||
968 | static | ||
969 | struct uni_data_desc *qlcnic_get_data_desc(struct qlcnic_adapter *adapter, | ||
970 | u32 section, u32 idx_offset) | ||
971 | { | ||
972 | const u8 *unirom = adapter->fw->data; | ||
973 | struct uni_table_desc *tab_desc; | ||
974 | u32 offs, idx; | ||
975 | __le32 temp; | ||
976 | |||
977 | temp = *((__le32 *)&unirom[adapter->file_prd_off] + idx_offset); | ||
978 | idx = le32_to_cpu(temp); | ||
979 | |||
980 | tab_desc = qlcnic_get_table_desc(unirom, section); | ||
981 | |||
982 | if (tab_desc == NULL) | ||
983 | return NULL; | ||
984 | |||
985 | offs = le32_to_cpu(tab_desc->findex) + | ||
986 | le32_to_cpu(tab_desc->entry_size) * idx; | ||
987 | |||
988 | return (struct uni_data_desc *)&unirom[offs]; | ||
989 | } | ||
990 | |||
991 | static u8 * | ||
992 | qlcnic_get_bootld_offs(struct qlcnic_adapter *adapter) | ||
993 | { | ||
994 | u32 offs = QLCNIC_BOOTLD_START; | ||
995 | struct uni_data_desc *data_desc; | ||
996 | |||
997 | data_desc = qlcnic_get_data_desc(adapter, QLCNIC_UNI_DIR_SECT_BOOTLD, | ||
998 | QLCNIC_UNI_BOOTLD_IDX_OFF); | ||
999 | |||
1000 | if (adapter->ahw->fw_type == QLCNIC_UNIFIED_ROMIMAGE) | ||
1001 | offs = le32_to_cpu(data_desc->findex); | ||
1002 | |||
1003 | return (u8 *)&adapter->fw->data[offs]; | ||
1004 | } | ||
1005 | |||
1006 | static u8 * | ||
1007 | qlcnic_get_fw_offs(struct qlcnic_adapter *adapter) | ||
1008 | { | ||
1009 | u32 offs = QLCNIC_IMAGE_START; | ||
1010 | struct uni_data_desc *data_desc; | ||
1011 | |||
1012 | data_desc = qlcnic_get_data_desc(adapter, QLCNIC_UNI_DIR_SECT_FW, | ||
1013 | QLCNIC_UNI_FIRMWARE_IDX_OFF); | ||
1014 | if (adapter->ahw->fw_type == QLCNIC_UNIFIED_ROMIMAGE) | ||
1015 | offs = le32_to_cpu(data_desc->findex); | ||
1016 | |||
1017 | return (u8 *)&adapter->fw->data[offs]; | ||
1018 | } | ||
1019 | |||
1020 | static u32 qlcnic_get_fw_size(struct qlcnic_adapter *adapter) | ||
1021 | { | ||
1022 | struct uni_data_desc *data_desc; | ||
1023 | const u8 *unirom = adapter->fw->data; | ||
1024 | |||
1025 | data_desc = qlcnic_get_data_desc(adapter, QLCNIC_UNI_DIR_SECT_FW, | ||
1026 | QLCNIC_UNI_FIRMWARE_IDX_OFF); | ||
1027 | |||
1028 | if (adapter->ahw->fw_type == QLCNIC_UNIFIED_ROMIMAGE) | ||
1029 | return le32_to_cpu(data_desc->size); | ||
1030 | else | ||
1031 | return le32_to_cpu(*(__le32 *)&unirom[QLCNIC_FW_SIZE_OFFSET]); | ||
1032 | } | ||
1033 | |||
1034 | static u32 qlcnic_get_fw_version(struct qlcnic_adapter *adapter) | ||
1035 | { | ||
1036 | struct uni_data_desc *fw_data_desc; | ||
1037 | const struct firmware *fw = adapter->fw; | ||
1038 | u32 major, minor, sub; | ||
1039 | __le32 version_offset; | ||
1040 | const u8 *ver_str; | ||
1041 | int i, ret; | ||
1042 | |||
1043 | if (adapter->ahw->fw_type != QLCNIC_UNIFIED_ROMIMAGE) { | ||
1044 | version_offset = *(__le32 *)&fw->data[QLCNIC_FW_VERSION_OFFSET]; | ||
1045 | return le32_to_cpu(version_offset); | ||
1046 | } | ||
1047 | |||
1048 | fw_data_desc = qlcnic_get_data_desc(adapter, QLCNIC_UNI_DIR_SECT_FW, | ||
1049 | QLCNIC_UNI_FIRMWARE_IDX_OFF); | ||
1050 | ver_str = fw->data + le32_to_cpu(fw_data_desc->findex) + | ||
1051 | le32_to_cpu(fw_data_desc->size) - 17; | ||
1052 | |||
1053 | for (i = 0; i < 12; i++) { | ||
1054 | if (!strncmp(&ver_str[i], "REV=", 4)) { | ||
1055 | ret = sscanf(&ver_str[i+4], "%u.%u.%u ", | ||
1056 | &major, &minor, &sub); | ||
1057 | if (ret != 3) | ||
1058 | return 0; | ||
1059 | else | ||
1060 | return major + (minor << 8) + (sub << 16); | ||
1061 | } | ||
1062 | } | ||
1063 | |||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | static u32 qlcnic_get_bios_version(struct qlcnic_adapter *adapter) | ||
1068 | { | ||
1069 | const struct firmware *fw = adapter->fw; | ||
1070 | u32 bios_ver, prd_off = adapter->file_prd_off; | ||
1071 | u8 *version_offset; | ||
1072 | __le32 temp; | ||
1073 | |||
1074 | if (adapter->ahw->fw_type != QLCNIC_UNIFIED_ROMIMAGE) { | ||
1075 | version_offset = (u8 *)&fw->data[QLCNIC_BIOS_VERSION_OFFSET]; | ||
1076 | return le32_to_cpu(*(__le32 *)version_offset); | ||
1077 | } | ||
1078 | |||
1079 | temp = *((__le32 *)(&fw->data[prd_off]) + QLCNIC_UNI_BIOS_VERSION_OFF); | ||
1080 | bios_ver = le32_to_cpu(temp); | ||
1081 | |||
1082 | return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24); | ||
1083 | } | ||
1084 | |||
1085 | static void qlcnic_rom_lock_recovery(struct qlcnic_adapter *adapter) | ||
1086 | { | ||
1087 | if (qlcnic_pcie_sem_lock(adapter, 2, QLCNIC_ROM_LOCK_ID)) | ||
1088 | dev_info(&adapter->pdev->dev, "Resetting rom_lock\n"); | ||
1089 | |||
1090 | qlcnic_pcie_sem_unlock(adapter, 2); | ||
1091 | } | ||
1092 | |||
1093 | static int | ||
1094 | qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter) | ||
1095 | { | ||
1096 | u32 heartbeat, ret = -EIO; | ||
1097 | int retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT; | ||
1098 | |||
1099 | adapter->heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); | ||
1100 | |||
1101 | do { | ||
1102 | msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS); | ||
1103 | heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER); | ||
1104 | if (heartbeat != adapter->heartbeat) { | ||
1105 | ret = QLCNIC_RCODE_SUCCESS; | ||
1106 | break; | ||
1107 | } | ||
1108 | } while (--retries); | ||
1109 | |||
1110 | return ret; | ||
1111 | } | ||
1112 | |||
1113 | int | ||
1114 | qlcnic_need_fw_reset(struct qlcnic_adapter *adapter) | ||
1115 | { | ||
1116 | if ((adapter->flags & QLCNIC_FW_HANG) || | ||
1117 | qlcnic_check_fw_hearbeat(adapter)) { | ||
1118 | qlcnic_rom_lock_recovery(adapter); | ||
1119 | return 1; | ||
1120 | } | ||
1121 | |||
1122 | if (adapter->need_fw_reset) | ||
1123 | return 1; | ||
1124 | |||
1125 | if (adapter->fw) | ||
1126 | return 1; | ||
1127 | |||
1128 | return 0; | ||
1129 | } | ||
1130 | |||
1131 | static const char *fw_name[] = { | ||
1132 | QLCNIC_UNIFIED_ROMIMAGE_NAME, | ||
1133 | QLCNIC_FLASH_ROMIMAGE_NAME, | ||
1134 | }; | ||
1135 | |||
1136 | int | ||
1137 | qlcnic_load_firmware(struct qlcnic_adapter *adapter) | ||
1138 | { | ||
1139 | __le64 *ptr64; | ||
1140 | u32 i, flashaddr, size; | ||
1141 | const struct firmware *fw = adapter->fw; | ||
1142 | struct pci_dev *pdev = adapter->pdev; | ||
1143 | |||
1144 | dev_info(&pdev->dev, "loading firmware from %s\n", | ||
1145 | fw_name[adapter->ahw->fw_type]); | ||
1146 | |||
1147 | if (fw) { | ||
1148 | u64 data; | ||
1149 | |||
1150 | size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; | ||
1151 | |||
1152 | ptr64 = (__le64 *)qlcnic_get_bootld_offs(adapter); | ||
1153 | flashaddr = QLCNIC_BOOTLD_START; | ||
1154 | |||
1155 | for (i = 0; i < size; i++) { | ||
1156 | data = le64_to_cpu(ptr64[i]); | ||
1157 | |||
1158 | if (qlcnic_pci_mem_write_2M(adapter, flashaddr, data)) | ||
1159 | return -EIO; | ||
1160 | |||
1161 | flashaddr += 8; | ||
1162 | } | ||
1163 | |||
1164 | size = qlcnic_get_fw_size(adapter) / 8; | ||
1165 | |||
1166 | ptr64 = (__le64 *)qlcnic_get_fw_offs(adapter); | ||
1167 | flashaddr = QLCNIC_IMAGE_START; | ||
1168 | |||
1169 | for (i = 0; i < size; i++) { | ||
1170 | data = le64_to_cpu(ptr64[i]); | ||
1171 | |||
1172 | if (qlcnic_pci_mem_write_2M(adapter, | ||
1173 | flashaddr, data)) | ||
1174 | return -EIO; | ||
1175 | |||
1176 | flashaddr += 8; | ||
1177 | } | ||
1178 | |||
1179 | size = qlcnic_get_fw_size(adapter) % 8; | ||
1180 | if (size) { | ||
1181 | data = le64_to_cpu(ptr64[i]); | ||
1182 | |||
1183 | if (qlcnic_pci_mem_write_2M(adapter, | ||
1184 | flashaddr, data)) | ||
1185 | return -EIO; | ||
1186 | } | ||
1187 | |||
1188 | } else { | ||
1189 | u64 data; | ||
1190 | u32 hi, lo; | ||
1191 | int ret; | ||
1192 | struct qlcnic_flt_entry bootld_entry; | ||
1193 | |||
1194 | ret = qlcnic_get_flt_entry(adapter, QLCNIC_BOOTLD_REGION, | ||
1195 | &bootld_entry); | ||
1196 | if (!ret) { | ||
1197 | size = bootld_entry.size / 8; | ||
1198 | flashaddr = bootld_entry.start_addr; | ||
1199 | } else { | ||
1200 | size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; | ||
1201 | flashaddr = QLCNIC_BOOTLD_START; | ||
1202 | dev_info(&pdev->dev, | ||
1203 | "using legacy method to get flash fw region"); | ||
1204 | } | ||
1205 | |||
1206 | for (i = 0; i < size; i++) { | ||
1207 | if (qlcnic_rom_fast_read(adapter, | ||
1208 | flashaddr, (int *)&lo) != 0) | ||
1209 | return -EIO; | ||
1210 | if (qlcnic_rom_fast_read(adapter, | ||
1211 | flashaddr + 4, (int *)&hi) != 0) | ||
1212 | return -EIO; | ||
1213 | |||
1214 | data = (((u64)hi << 32) | lo); | ||
1215 | |||
1216 | if (qlcnic_pci_mem_write_2M(adapter, | ||
1217 | flashaddr, data)) | ||
1218 | return -EIO; | ||
1219 | |||
1220 | flashaddr += 8; | ||
1221 | } | ||
1222 | } | ||
1223 | msleep(1); | ||
1224 | |||
1225 | QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x18, 0x1020); | ||
1226 | QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0x80001e); | ||
1227 | return 0; | ||
1228 | } | ||
1229 | |||
1230 | static int | ||
1231 | qlcnic_validate_firmware(struct qlcnic_adapter *adapter) | ||
1232 | { | ||
1233 | u32 val; | ||
1234 | u32 ver, bios, min_size; | ||
1235 | struct pci_dev *pdev = adapter->pdev; | ||
1236 | const struct firmware *fw = adapter->fw; | ||
1237 | u8 fw_type = adapter->ahw->fw_type; | ||
1238 | |||
1239 | if (fw_type == QLCNIC_UNIFIED_ROMIMAGE) { | ||
1240 | if (qlcnic_validate_unified_romimage(adapter)) | ||
1241 | return -EINVAL; | ||
1242 | |||
1243 | min_size = QLCNIC_UNI_FW_MIN_SIZE; | ||
1244 | } else { | ||
1245 | val = le32_to_cpu(*(__le32 *)&fw->data[QLCNIC_FW_MAGIC_OFFSET]); | ||
1246 | if (val != QLCNIC_BDINFO_MAGIC) | ||
1247 | return -EINVAL; | ||
1248 | |||
1249 | min_size = QLCNIC_FW_MIN_SIZE; | ||
1250 | } | ||
1251 | |||
1252 | if (fw->size < min_size) | ||
1253 | return -EINVAL; | ||
1254 | |||
1255 | val = qlcnic_get_fw_version(adapter); | ||
1256 | ver = QLCNIC_DECODE_VERSION(val); | ||
1257 | |||
1258 | if (ver < QLCNIC_MIN_FW_VERSION) { | ||
1259 | dev_err(&pdev->dev, | ||
1260 | "%s: firmware version %d.%d.%d unsupported\n", | ||
1261 | fw_name[fw_type], _major(ver), _minor(ver), _build(ver)); | ||
1262 | return -EINVAL; | ||
1263 | } | ||
1264 | |||
1265 | val = qlcnic_get_bios_version(adapter); | ||
1266 | qlcnic_rom_fast_read(adapter, QLCNIC_BIOS_VERSION_OFFSET, (int *)&bios); | ||
1267 | if (val != bios) { | ||
1268 | dev_err(&pdev->dev, "%s: firmware bios is incompatible\n", | ||
1269 | fw_name[fw_type]); | ||
1270 | return -EINVAL; | ||
1271 | } | ||
1272 | |||
1273 | QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC); | ||
1274 | return 0; | ||
1275 | } | ||
1276 | |||
1277 | static void | ||
1278 | qlcnic_get_next_fwtype(struct qlcnic_adapter *adapter) | ||
1279 | { | ||
1280 | u8 fw_type; | ||
1281 | |||
1282 | switch (adapter->ahw->fw_type) { | ||
1283 | case QLCNIC_UNKNOWN_ROMIMAGE: | ||
1284 | fw_type = QLCNIC_UNIFIED_ROMIMAGE; | ||
1285 | break; | ||
1286 | |||
1287 | case QLCNIC_UNIFIED_ROMIMAGE: | ||
1288 | default: | ||
1289 | fw_type = QLCNIC_FLASH_ROMIMAGE; | ||
1290 | break; | ||
1291 | } | ||
1292 | |||
1293 | adapter->ahw->fw_type = fw_type; | ||
1294 | } | ||
1295 | |||
1296 | |||
1297 | |||
1298 | void qlcnic_request_firmware(struct qlcnic_adapter *adapter) | ||
1299 | { | ||
1300 | struct pci_dev *pdev = adapter->pdev; | ||
1301 | int rc; | ||
1302 | |||
1303 | adapter->ahw->fw_type = QLCNIC_UNKNOWN_ROMIMAGE; | ||
1304 | |||
1305 | next: | ||
1306 | qlcnic_get_next_fwtype(adapter); | ||
1307 | |||
1308 | if (adapter->ahw->fw_type == QLCNIC_FLASH_ROMIMAGE) { | ||
1309 | adapter->fw = NULL; | ||
1310 | } else { | ||
1311 | rc = request_firmware(&adapter->fw, | ||
1312 | fw_name[adapter->ahw->fw_type], | ||
1313 | &pdev->dev); | ||
1314 | if (rc != 0) | ||
1315 | goto next; | ||
1316 | |||
1317 | rc = qlcnic_validate_firmware(adapter); | ||
1318 | if (rc != 0) { | ||
1319 | release_firmware(adapter->fw); | ||
1320 | msleep(1); | ||
1321 | goto next; | ||
1322 | } | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1326 | |||
1327 | void | ||
1328 | qlcnic_release_firmware(struct qlcnic_adapter *adapter) | ||
1329 | { | ||
1330 | release_firmware(adapter->fw); | ||
1331 | adapter->fw = NULL; | ||
1332 | } | ||