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