Commit | Line | Data |
---|---|---|
c4e84bde RM |
1 | #include "qlge.h" |
2 | ||
ca0413b6 RM |
3 | static void ql_display_mb_sts(struct ql_adapter *qdev, |
4 | struct mbox_params *mbcp) | |
5 | { | |
6 | int i; | |
7 | static char *err_sts[] = { | |
8 | "Command Complete", | |
9 | "Command Not Supported", | |
10 | "Host Interface Error", | |
11 | "Checksum Error", | |
12 | "Unused Completion Status", | |
13 | "Test Failed", | |
14 | "Command Parameter Error"}; | |
15 | ||
16 | QPRINTK(qdev, DRV, DEBUG, "%s.\n", | |
17 | err_sts[mbcp->mbox_out[0] & 0x0000000f]); | |
18 | for (i = 0; i < mbcp->out_count; i++) | |
19 | QPRINTK(qdev, DRV, DEBUG, "mbox_out[%d] = 0x%.08x.\n", | |
20 | i, mbcp->mbox_out[i]); | |
21 | } | |
22 | ||
a2e809bb | 23 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data) |
c4e84bde RM |
24 | { |
25 | int status; | |
26 | /* wait for reg to come ready */ | |
27 | status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR); | |
28 | if (status) | |
29 | goto exit; | |
30 | /* set up for reg read */ | |
31 | ql_write32(qdev, PROC_ADDR, reg | PROC_ADDR_R); | |
32 | /* wait for reg to come ready */ | |
33 | status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR); | |
34 | if (status) | |
35 | goto exit; | |
36 | /* get the data */ | |
37 | *data = ql_read32(qdev, PROC_DATA); | |
38 | exit: | |
39 | return status; | |
40 | } | |
41 | ||
a2e809bb RM |
42 | int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data) |
43 | { | |
44 | int status = 0; | |
45 | /* wait for reg to come ready */ | |
46 | status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR); | |
47 | if (status) | |
48 | goto exit; | |
49 | /* write the data to the data reg */ | |
50 | ql_write32(qdev, PROC_DATA, data); | |
51 | /* trigger the write */ | |
52 | ql_write32(qdev, PROC_ADDR, reg); | |
53 | /* wait for reg to come ready */ | |
54 | status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR); | |
55 | if (status) | |
56 | goto exit; | |
57 | exit: | |
58 | return status; | |
59 | } | |
60 | ||
61 | int ql_soft_reset_mpi_risc(struct ql_adapter *qdev) | |
62 | { | |
63 | int status; | |
64 | status = ql_write_mpi_reg(qdev, 0x00001010, 1); | |
65 | return status; | |
66 | } | |
67 | ||
2f22d22e | 68 | static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) |
c4e84bde RM |
69 | { |
70 | int i, status; | |
71 | ||
72 | status = ql_sem_spinlock(qdev, SEM_PROC_REG_MASK); | |
73 | if (status) | |
74 | return -EBUSY; | |
75 | for (i = 0; i < mbcp->out_count; i++) { | |
76 | status = | |
a2e809bb | 77 | ql_read_mpi_reg(qdev, qdev->mailbox_out + i, |
c4e84bde RM |
78 | &mbcp->mbox_out[i]); |
79 | if (status) { | |
80 | QPRINTK(qdev, DRV, ERR, "Failed mailbox read.\n"); | |
81 | break; | |
82 | } | |
83 | } | |
84 | ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */ | |
85 | return status; | |
86 | } | |
87 | ||
ca0413b6 RM |
88 | /* Wait for a single mailbox command to complete. |
89 | * Returns zero on success. | |
90 | */ | |
91 | static int ql_wait_mbx_cmd_cmplt(struct ql_adapter *qdev) | |
92 | { | |
365da872 | 93 | int count = 100; |
ca0413b6 RM |
94 | u32 value; |
95 | ||
96 | do { | |
97 | value = ql_read32(qdev, STS); | |
98 | if (value & STS_PI) | |
99 | return 0; | |
365da872 | 100 | mdelay(UDELAY_DELAY); /* 100ms */ |
ca0413b6 RM |
101 | } while (--count); |
102 | return -ETIMEDOUT; | |
103 | } | |
104 | ||
105 | /* Execute a single mailbox command. | |
106 | * Caller must hold PROC_ADDR semaphore. | |
107 | */ | |
108 | static int ql_exec_mb_cmd(struct ql_adapter *qdev, struct mbox_params *mbcp) | |
109 | { | |
110 | int i, status; | |
111 | ||
112 | /* | |
113 | * Make sure there's nothing pending. | |
114 | * This shouldn't happen. | |
115 | */ | |
116 | if (ql_read32(qdev, CSR) & CSR_HRI) | |
117 | return -EIO; | |
118 | ||
119 | status = ql_sem_spinlock(qdev, SEM_PROC_REG_MASK); | |
120 | if (status) | |
121 | return status; | |
122 | ||
123 | /* | |
124 | * Fill the outbound mailboxes. | |
125 | */ | |
126 | for (i = 0; i < mbcp->in_count; i++) { | |
127 | status = ql_write_mpi_reg(qdev, qdev->mailbox_in + i, | |
128 | mbcp->mbox_in[i]); | |
129 | if (status) | |
130 | goto end; | |
131 | } | |
132 | /* | |
133 | * Wake up the MPI firmware. | |
134 | */ | |
135 | ql_write32(qdev, CSR, CSR_CMD_SET_H2R_INT); | |
136 | end: | |
137 | ql_sem_unlock(qdev, SEM_PROC_REG_MASK); | |
138 | return status; | |
139 | } | |
140 | ||
2ee1e272 RM |
141 | /* We are being asked by firmware to accept |
142 | * a change to the port. This is only | |
143 | * a change to max frame sizes (Tx/Rx), pause | |
144 | * paramters, or loopback mode. We wake up a worker | |
145 | * to handler processing this since a mailbox command | |
146 | * will need to be sent to ACK the request. | |
147 | */ | |
148 | static int ql_idc_req_aen(struct ql_adapter *qdev) | |
149 | { | |
150 | int status; | |
151 | struct mbox_params *mbcp = &qdev->idc_mbc; | |
152 | ||
153 | QPRINTK(qdev, DRV, ERR, "Enter!\n"); | |
154 | /* Get the status data and start up a thread to | |
155 | * handle the request. | |
156 | */ | |
157 | mbcp = &qdev->idc_mbc; | |
158 | mbcp->out_count = 4; | |
159 | status = ql_get_mb_sts(qdev, mbcp); | |
160 | if (status) { | |
161 | QPRINTK(qdev, DRV, ERR, | |
162 | "Could not read MPI, resetting ASIC!\n"); | |
163 | ql_queue_asic_error(qdev); | |
164 | } else { | |
165 | /* Begin polled mode early so | |
166 | * we don't get another interrupt | |
167 | * when we leave mpi_worker. | |
168 | */ | |
169 | ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16)); | |
170 | queue_delayed_work(qdev->workqueue, &qdev->mpi_idc_work, 0); | |
171 | } | |
172 | return status; | |
173 | } | |
174 | ||
bcc2cb3b RM |
175 | /* Process an inter-device event completion. |
176 | * If good, signal the caller's completion. | |
177 | */ | |
178 | static int ql_idc_cmplt_aen(struct ql_adapter *qdev) | |
179 | { | |
180 | int status; | |
181 | struct mbox_params *mbcp = &qdev->idc_mbc; | |
182 | mbcp->out_count = 4; | |
183 | status = ql_get_mb_sts(qdev, mbcp); | |
184 | if (status) { | |
185 | QPRINTK(qdev, DRV, ERR, | |
186 | "Could not read MPI, resetting RISC!\n"); | |
187 | ql_queue_fw_error(qdev); | |
188 | } else | |
189 | /* Wake up the sleeping mpi_idc_work thread that is | |
190 | * waiting for this event. | |
191 | */ | |
192 | complete(&qdev->ide_completion); | |
193 | ||
194 | return status; | |
195 | } | |
5700abe9 | 196 | |
c4e84bde RM |
197 | static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) |
198 | { | |
5700abe9 | 199 | int status; |
c4e84bde RM |
200 | mbcp->out_count = 2; |
201 | ||
5700abe9 RM |
202 | status = ql_get_mb_sts(qdev, mbcp); |
203 | if (status) { | |
204 | QPRINTK(qdev, DRV, ERR, | |
205 | "%s: Could not get mailbox status.\n", __func__); | |
206 | return; | |
207 | } | |
c4e84bde RM |
208 | |
209 | qdev->link_status = mbcp->mbox_out[1]; | |
210 | QPRINTK(qdev, DRV, ERR, "Link Up.\n"); | |
5700abe9 | 211 | |
2ee1e272 RM |
212 | /* If we're coming back from an IDC event |
213 | * then set up the CAM and frame routing. | |
214 | */ | |
215 | if (test_bit(QL_CAM_RT_SET, &qdev->flags)) { | |
216 | status = ql_cam_route_initialize(qdev); | |
217 | if (status) { | |
218 | QPRINTK(qdev, IFUP, ERR, | |
219 | "Failed to init CAM/Routing tables.\n"); | |
220 | return; | |
221 | } else | |
222 | clear_bit(QL_CAM_RT_SET, &qdev->flags); | |
223 | } | |
224 | ||
225 | /* Queue up a worker to check the frame | |
226 | * size information, and fix it if it's not | |
227 | * to our liking. | |
228 | */ | |
229 | if (!test_bit(QL_PORT_CFG, &qdev->flags)) { | |
230 | QPRINTK(qdev, DRV, ERR, "Queue Port Config Worker!\n"); | |
231 | set_bit(QL_PORT_CFG, &qdev->flags); | |
232 | /* Begin polled mode early so | |
233 | * we don't get another interrupt | |
234 | * when we leave mpi_worker dpc. | |
235 | */ | |
236 | ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16)); | |
237 | queue_delayed_work(qdev->workqueue, | |
238 | &qdev->mpi_port_cfg_work, 0); | |
239 | } | |
240 | ||
5700abe9 | 241 | netif_carrier_on(qdev->ndev); |
c4e84bde RM |
242 | } |
243 | ||
244 | static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp) | |
245 | { | |
11d9fe68 RM |
246 | int status; |
247 | ||
c4e84bde RM |
248 | mbcp->out_count = 3; |
249 | ||
11d9fe68 RM |
250 | status = ql_get_mb_sts(qdev, mbcp); |
251 | if (status) | |
252 | QPRINTK(qdev, DRV, ERR, "Link down AEN broken!\n"); | |
c4e84bde | 253 | |
11d9fe68 | 254 | netif_carrier_off(qdev->ndev); |
c4e84bde RM |
255 | } |
256 | ||
eae6b58f RM |
257 | static int ql_sfp_in(struct ql_adapter *qdev, struct mbox_params *mbcp) |
258 | { | |
259 | int status; | |
260 | ||
261 | mbcp->out_count = 5; | |
262 | ||
263 | status = ql_get_mb_sts(qdev, mbcp); | |
264 | if (status) | |
265 | QPRINTK(qdev, DRV, ERR, "SFP in AEN broken!\n"); | |
266 | else | |
267 | QPRINTK(qdev, DRV, ERR, "SFP insertion detected.\n"); | |
268 | ||
269 | return status; | |
270 | } | |
271 | ||
272 | static int ql_sfp_out(struct ql_adapter *qdev, struct mbox_params *mbcp) | |
273 | { | |
274 | int status; | |
275 | ||
276 | mbcp->out_count = 1; | |
277 | ||
278 | status = ql_get_mb_sts(qdev, mbcp); | |
279 | if (status) | |
280 | QPRINTK(qdev, DRV, ERR, "SFP out AEN broken!\n"); | |
281 | else | |
282 | QPRINTK(qdev, DRV, ERR, "SFP removal detected.\n"); | |
283 | ||
284 | return status; | |
285 | } | |
286 | ||
fc1f9ea5 RM |
287 | static int ql_aen_lost(struct ql_adapter *qdev, struct mbox_params *mbcp) |
288 | { | |
289 | int status; | |
290 | ||
291 | mbcp->out_count = 6; | |
292 | ||
293 | status = ql_get_mb_sts(qdev, mbcp); | |
294 | if (status) | |
295 | QPRINTK(qdev, DRV, ERR, "Lost AEN broken!\n"); | |
296 | else { | |
297 | int i; | |
298 | QPRINTK(qdev, DRV, ERR, "Lost AEN detected.\n"); | |
299 | for (i = 0; i < mbcp->out_count; i++) | |
300 | QPRINTK(qdev, DRV, ERR, "mbox_out[%d] = 0x%.08x.\n", | |
301 | i, mbcp->mbox_out[i]); | |
302 | ||
303 | } | |
304 | ||
305 | return status; | |
306 | } | |
307 | ||
c4e84bde RM |
308 | static void ql_init_fw_done(struct ql_adapter *qdev, struct mbox_params *mbcp) |
309 | { | |
f56b54f5 RM |
310 | int status; |
311 | ||
c4e84bde RM |
312 | mbcp->out_count = 2; |
313 | ||
f56b54f5 RM |
314 | status = ql_get_mb_sts(qdev, mbcp); |
315 | if (status) { | |
c4e84bde | 316 | QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n"); |
f56b54f5 RM |
317 | } else { |
318 | QPRINTK(qdev, DRV, ERR, "Firmware Revision = 0x%.08x.\n", | |
319 | mbcp->mbox_out[1]); | |
320 | status = ql_cam_route_initialize(qdev); | |
321 | if (status) | |
322 | QPRINTK(qdev, IFUP, ERR, | |
323 | "Failed to init CAM/Routing tables.\n"); | |
c4e84bde | 324 | } |
c4e84bde RM |
325 | } |
326 | ||
125844ea RM |
327 | /* Process an async event and clear it unless it's an |
328 | * error condition. | |
329 | * This can get called iteratively from the mpi_work thread | |
330 | * when events arrive via an interrupt. | |
331 | * It also gets called when a mailbox command is polling for | |
332 | * it's completion. */ | |
333 | static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) | |
334 | { | |
335 | int status; | |
ca0413b6 | 336 | int orig_count = mbcp->out_count; |
125844ea RM |
337 | |
338 | /* Just get mailbox zero for now. */ | |
339 | mbcp->out_count = 1; | |
340 | status = ql_get_mb_sts(qdev, mbcp); | |
341 | if (status) { | |
342 | QPRINTK(qdev, DRV, ERR, | |
343 | "Could not read MPI, resetting ASIC!\n"); | |
344 | ql_queue_asic_error(qdev); | |
345 | goto end; | |
346 | } | |
347 | ||
348 | switch (mbcp->mbox_out[0]) { | |
349 | ||
ca0413b6 RM |
350 | /* This case is only active when we arrive here |
351 | * as a result of issuing a mailbox command to | |
352 | * the firmware. | |
353 | */ | |
354 | case MB_CMD_STS_INTRMDT: | |
355 | case MB_CMD_STS_GOOD: | |
356 | case MB_CMD_STS_INVLD_CMD: | |
357 | case MB_CMD_STS_XFC_ERR: | |
358 | case MB_CMD_STS_CSUM_ERR: | |
359 | case MB_CMD_STS_ERR: | |
360 | case MB_CMD_STS_PARAM_ERR: | |
361 | /* We can only get mailbox status if we're polling from an | |
362 | * unfinished command. Get the rest of the status data and | |
363 | * return back to the caller. | |
364 | * We only end up here when we're polling for a mailbox | |
365 | * command completion. | |
366 | */ | |
367 | mbcp->out_count = orig_count; | |
368 | status = ql_get_mb_sts(qdev, mbcp); | |
369 | return status; | |
370 | ||
2ee1e272 RM |
371 | /* We are being asked by firmware to accept |
372 | * a change to the port. This is only | |
373 | * a change to max frame sizes (Tx/Rx), pause | |
374 | * paramters, or loopback mode. | |
375 | */ | |
376 | case AEN_IDC_REQ: | |
377 | status = ql_idc_req_aen(qdev); | |
378 | break; | |
379 | ||
bcc2cb3b RM |
380 | /* Process and inbound IDC event. |
381 | * This will happen when we're trying to | |
382 | * change tx/rx max frame size, change pause | |
383 | * paramters or loopback mode. | |
384 | */ | |
385 | case AEN_IDC_CMPLT: | |
386 | case AEN_IDC_EXT: | |
387 | status = ql_idc_cmplt_aen(qdev); | |
388 | break; | |
389 | ||
125844ea RM |
390 | case AEN_LINK_UP: |
391 | ql_link_up(qdev, mbcp); | |
392 | break; | |
393 | ||
394 | case AEN_LINK_DOWN: | |
395 | ql_link_down(qdev, mbcp); | |
396 | break; | |
397 | ||
398 | case AEN_FW_INIT_DONE: | |
f56b54f5 RM |
399 | /* If we're in process on executing the firmware, |
400 | * then convert the status to normal mailbox status. | |
401 | */ | |
402 | if (mbcp->mbox_in[0] == MB_CMD_EX_FW) { | |
403 | mbcp->out_count = orig_count; | |
404 | status = ql_get_mb_sts(qdev, mbcp); | |
405 | mbcp->mbox_out[0] = MB_CMD_STS_GOOD; | |
406 | return status; | |
407 | } | |
125844ea RM |
408 | ql_init_fw_done(qdev, mbcp); |
409 | break; | |
410 | ||
eae6b58f RM |
411 | case AEN_AEN_SFP_IN: |
412 | ql_sfp_in(qdev, mbcp); | |
413 | break; | |
414 | ||
415 | case AEN_AEN_SFP_OUT: | |
416 | ql_sfp_out(qdev, mbcp); | |
417 | break; | |
418 | ||
7c92191c RM |
419 | /* This event can arrive at boot time or after an |
420 | * MPI reset if the firmware failed to initialize. | |
421 | */ | |
125844ea | 422 | case AEN_FW_INIT_FAIL: |
7c92191c RM |
423 | /* If we're in process on executing the firmware, |
424 | * then convert the status to normal mailbox status. | |
425 | */ | |
426 | if (mbcp->mbox_in[0] == MB_CMD_EX_FW) { | |
427 | mbcp->out_count = orig_count; | |
428 | status = ql_get_mb_sts(qdev, mbcp); | |
429 | mbcp->mbox_out[0] = MB_CMD_STS_ERR; | |
430 | return status; | |
431 | } | |
432 | QPRINTK(qdev, DRV, ERR, | |
433 | "Firmware initialization failed.\n"); | |
434 | status = -EIO; | |
435 | ql_queue_fw_error(qdev); | |
436 | break; | |
437 | ||
125844ea | 438 | case AEN_SYS_ERR: |
bb667670 RM |
439 | QPRINTK(qdev, DRV, ERR, |
440 | "System Error.\n"); | |
125844ea | 441 | ql_queue_fw_error(qdev); |
bb667670 | 442 | status = -EIO; |
125844ea RM |
443 | break; |
444 | ||
fc1f9ea5 RM |
445 | case AEN_AEN_LOST: |
446 | ql_aen_lost(qdev, mbcp); | |
447 | break; | |
448 | ||
125844ea RM |
449 | default: |
450 | QPRINTK(qdev, DRV, ERR, | |
451 | "Unsupported AE %.08x.\n", mbcp->mbox_out[0]); | |
452 | /* Clear the MPI firmware status. */ | |
453 | } | |
454 | end: | |
455 | ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); | |
709ac4f4 RM |
456 | /* Restore the original mailbox count to |
457 | * what the caller asked for. This can get | |
458 | * changed when a mailbox command is waiting | |
459 | * for a response and an AEN arrives and | |
460 | * is handled. | |
461 | * */ | |
462 | mbcp->out_count = orig_count; | |
125844ea RM |
463 | return status; |
464 | } | |
465 | ||
ca0413b6 RM |
466 | /* Execute a single mailbox command. |
467 | * mbcp is a pointer to an array of u32. Each | |
468 | * element in the array contains the value for it's | |
469 | * respective mailbox register. | |
470 | */ | |
471 | static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp) | |
472 | { | |
473 | int status, count; | |
474 | ||
475 | mutex_lock(&qdev->mpi_mutex); | |
476 | ||
477 | /* Begin polled mode for MPI */ | |
478 | ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16)); | |
479 | ||
480 | /* Load the mailbox registers and wake up MPI RISC. */ | |
481 | status = ql_exec_mb_cmd(qdev, mbcp); | |
482 | if (status) | |
483 | goto end; | |
484 | ||
485 | ||
486 | /* If we're generating a system error, then there's nothing | |
487 | * to wait for. | |
488 | */ | |
489 | if (mbcp->mbox_in[0] == MB_CMD_MAKE_SYS_ERR) | |
490 | goto end; | |
491 | ||
492 | /* Wait for the command to complete. We loop | |
493 | * here because some AEN might arrive while | |
494 | * we're waiting for the mailbox command to | |
495 | * complete. If more than 5 arrive then we can | |
496 | * assume something is wrong. */ | |
497 | count = 5; | |
498 | do { | |
499 | /* Wait for the interrupt to come in. */ | |
500 | status = ql_wait_mbx_cmd_cmplt(qdev); | |
501 | if (status) | |
502 | goto end; | |
503 | ||
504 | /* Process the event. If it's an AEN, it | |
505 | * will be handled in-line or a worker | |
506 | * will be spawned. If it's our completion | |
507 | * we will catch it below. | |
508 | */ | |
509 | status = ql_mpi_handler(qdev, mbcp); | |
510 | if (status) | |
511 | goto end; | |
512 | ||
513 | /* It's either the completion for our mailbox | |
514 | * command complete or an AEN. If it's our | |
515 | * completion then get out. | |
516 | */ | |
517 | if (((mbcp->mbox_out[0] & 0x0000f000) == | |
518 | MB_CMD_STS_GOOD) || | |
519 | ((mbcp->mbox_out[0] & 0x0000f000) == | |
520 | MB_CMD_STS_INTRMDT)) | |
521 | break; | |
522 | } while (--count); | |
523 | ||
524 | if (!count) { | |
525 | QPRINTK(qdev, DRV, ERR, | |
526 | "Timed out waiting for mailbox complete.\n"); | |
527 | status = -ETIMEDOUT; | |
528 | goto end; | |
529 | } | |
530 | ||
531 | /* Now we can clear the interrupt condition | |
532 | * and look at our status. | |
533 | */ | |
534 | ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); | |
535 | ||
536 | if (((mbcp->mbox_out[0] & 0x0000f000) != | |
537 | MB_CMD_STS_GOOD) && | |
538 | ((mbcp->mbox_out[0] & 0x0000f000) != | |
539 | MB_CMD_STS_INTRMDT)) { | |
540 | ql_display_mb_sts(qdev, mbcp); | |
541 | status = -EIO; | |
542 | } | |
543 | end: | |
544 | mutex_unlock(&qdev->mpi_mutex); | |
545 | /* End polled mode for MPI */ | |
546 | ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI); | |
547 | return status; | |
548 | } | |
549 | ||
cfec0cbc RM |
550 | |
551 | /* Get MPI firmware version. This will be used for | |
552 | * driver banner and for ethtool info. | |
553 | * Returns zero on success. | |
554 | */ | |
555 | int ql_mb_about_fw(struct ql_adapter *qdev) | |
556 | { | |
557 | struct mbox_params mbc; | |
558 | struct mbox_params *mbcp = &mbc; | |
559 | int status = 0; | |
560 | ||
561 | memset(mbcp, 0, sizeof(struct mbox_params)); | |
562 | ||
563 | mbcp->in_count = 1; | |
564 | mbcp->out_count = 3; | |
565 | ||
566 | mbcp->mbox_in[0] = MB_CMD_ABOUT_FW; | |
567 | ||
568 | status = ql_mailbox_command(qdev, mbcp); | |
569 | if (status) | |
570 | return status; | |
571 | ||
572 | if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | |
573 | QPRINTK(qdev, DRV, ERR, | |
574 | "Failed about firmware command\n"); | |
575 | status = -EIO; | |
576 | } | |
577 | ||
578 | /* Store the firmware version */ | |
579 | qdev->fw_rev_id = mbcp->mbox_out[1]; | |
580 | ||
581 | return status; | |
582 | } | |
583 | ||
ca0413b6 RM |
584 | /* Get functional state for MPI firmware. |
585 | * Returns zero on success. | |
586 | */ | |
587 | int ql_mb_get_fw_state(struct ql_adapter *qdev) | |
588 | { | |
589 | struct mbox_params mbc; | |
590 | struct mbox_params *mbcp = &mbc; | |
591 | int status = 0; | |
592 | ||
593 | memset(mbcp, 0, sizeof(struct mbox_params)); | |
594 | ||
595 | mbcp->in_count = 1; | |
596 | mbcp->out_count = 2; | |
597 | ||
598 | mbcp->mbox_in[0] = MB_CMD_GET_FW_STATE; | |
599 | ||
600 | status = ql_mailbox_command(qdev, mbcp); | |
601 | if (status) | |
602 | return status; | |
603 | ||
604 | if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | |
605 | QPRINTK(qdev, DRV, ERR, | |
606 | "Failed Get Firmware State.\n"); | |
607 | status = -EIO; | |
608 | } | |
609 | ||
610 | /* If bit zero is set in mbx 1 then the firmware is | |
611 | * running, but not initialized. This should never | |
612 | * happen. | |
613 | */ | |
614 | if (mbcp->mbox_out[1] & 1) { | |
615 | QPRINTK(qdev, DRV, ERR, | |
616 | "Firmware waiting for initialization.\n"); | |
617 | status = -EIO; | |
618 | } | |
619 | ||
620 | return status; | |
621 | } | |
622 | ||
2ee1e272 RM |
623 | /* Send and ACK mailbox command to the firmware to |
624 | * let it continue with the change. | |
625 | */ | |
626 | int ql_mb_idc_ack(struct ql_adapter *qdev) | |
627 | { | |
628 | struct mbox_params mbc; | |
629 | struct mbox_params *mbcp = &mbc; | |
630 | int status = 0; | |
631 | ||
632 | memset(mbcp, 0, sizeof(struct mbox_params)); | |
633 | ||
634 | mbcp->in_count = 5; | |
635 | mbcp->out_count = 1; | |
636 | ||
637 | mbcp->mbox_in[0] = MB_CMD_IDC_ACK; | |
638 | mbcp->mbox_in[1] = qdev->idc_mbc.mbox_out[1]; | |
639 | mbcp->mbox_in[2] = qdev->idc_mbc.mbox_out[2]; | |
640 | mbcp->mbox_in[3] = qdev->idc_mbc.mbox_out[3]; | |
641 | mbcp->mbox_in[4] = qdev->idc_mbc.mbox_out[4]; | |
642 | ||
643 | status = ql_mailbox_command(qdev, mbcp); | |
644 | if (status) | |
645 | return status; | |
646 | ||
647 | if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | |
648 | QPRINTK(qdev, DRV, ERR, | |
649 | "Failed IDC ACK send.\n"); | |
650 | status = -EIO; | |
651 | } | |
652 | return status; | |
653 | } | |
654 | ||
bcc2cb3b RM |
655 | /* Get link settings and maximum frame size settings |
656 | * for the current port. | |
657 | * Most likely will block. | |
658 | */ | |
659 | static int ql_mb_set_port_cfg(struct ql_adapter *qdev) | |
660 | { | |
661 | struct mbox_params mbc; | |
662 | struct mbox_params *mbcp = &mbc; | |
663 | int status = 0; | |
664 | ||
665 | memset(mbcp, 0, sizeof(struct mbox_params)); | |
666 | ||
667 | mbcp->in_count = 3; | |
668 | mbcp->out_count = 1; | |
669 | ||
670 | mbcp->mbox_in[0] = MB_CMD_SET_PORT_CFG; | |
671 | mbcp->mbox_in[1] = qdev->link_config; | |
672 | mbcp->mbox_in[2] = qdev->max_frame_size; | |
673 | ||
674 | ||
675 | status = ql_mailbox_command(qdev, mbcp); | |
676 | if (status) | |
677 | return status; | |
678 | ||
679 | if (mbcp->mbox_out[0] == MB_CMD_STS_INTRMDT) { | |
680 | QPRINTK(qdev, DRV, ERR, | |
681 | "Port Config sent, wait for IDC.\n"); | |
682 | } else if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | |
683 | QPRINTK(qdev, DRV, ERR, | |
684 | "Failed Set Port Configuration.\n"); | |
685 | status = -EIO; | |
686 | } | |
687 | return status; | |
688 | } | |
689 | ||
690 | /* Get link settings and maximum frame size settings | |
691 | * for the current port. | |
692 | * Most likely will block. | |
693 | */ | |
694 | static int ql_mb_get_port_cfg(struct ql_adapter *qdev) | |
695 | { | |
696 | struct mbox_params mbc; | |
697 | struct mbox_params *mbcp = &mbc; | |
698 | int status = 0; | |
699 | ||
700 | memset(mbcp, 0, sizeof(struct mbox_params)); | |
701 | ||
702 | mbcp->in_count = 1; | |
703 | mbcp->out_count = 3; | |
704 | ||
705 | mbcp->mbox_in[0] = MB_CMD_GET_PORT_CFG; | |
706 | ||
707 | status = ql_mailbox_command(qdev, mbcp); | |
708 | if (status) | |
709 | return status; | |
710 | ||
711 | if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | |
712 | QPRINTK(qdev, DRV, ERR, | |
713 | "Failed Get Port Configuration.\n"); | |
714 | status = -EIO; | |
715 | } else { | |
716 | QPRINTK(qdev, DRV, DEBUG, | |
717 | "Passed Get Port Configuration.\n"); | |
718 | qdev->link_config = mbcp->mbox_out[1]; | |
719 | qdev->max_frame_size = mbcp->mbox_out[2]; | |
720 | } | |
721 | return status; | |
722 | } | |
723 | ||
724 | /* IDC - Inter Device Communication... | |
725 | * Some firmware commands require consent of adjacent FCOE | |
726 | * function. This function waits for the OK, or a | |
727 | * counter-request for a little more time.i | |
728 | * The firmware will complete the request if the other | |
729 | * function doesn't respond. | |
730 | */ | |
731 | static int ql_idc_wait(struct ql_adapter *qdev) | |
732 | { | |
733 | int status = -ETIMEDOUT; | |
734 | long wait_time = 1 * HZ; | |
735 | struct mbox_params *mbcp = &qdev->idc_mbc; | |
736 | do { | |
737 | /* Wait here for the command to complete | |
738 | * via the IDC process. | |
739 | */ | |
740 | wait_time = | |
741 | wait_for_completion_timeout(&qdev->ide_completion, | |
742 | wait_time); | |
743 | if (!wait_time) { | |
744 | QPRINTK(qdev, DRV, ERR, | |
745 | "IDC Timeout.\n"); | |
746 | break; | |
747 | } | |
748 | /* Now examine the response from the IDC process. | |
749 | * We might have a good completion or a request for | |
750 | * more wait time. | |
751 | */ | |
752 | if (mbcp->mbox_out[0] == AEN_IDC_EXT) { | |
753 | QPRINTK(qdev, DRV, ERR, | |
754 | "IDC Time Extension from function.\n"); | |
755 | wait_time += (mbcp->mbox_out[1] >> 8) & 0x0000000f; | |
756 | } else if (mbcp->mbox_out[0] == AEN_IDC_CMPLT) { | |
757 | QPRINTK(qdev, DRV, ERR, | |
758 | "IDC Success.\n"); | |
759 | status = 0; | |
760 | break; | |
761 | } else { | |
762 | QPRINTK(qdev, DRV, ERR, | |
763 | "IDC: Invalid State 0x%.04x.\n", | |
764 | mbcp->mbox_out[0]); | |
765 | status = -EIO; | |
766 | break; | |
767 | } | |
768 | } while (wait_time); | |
769 | ||
770 | return status; | |
771 | } | |
772 | ||
773 | /* API called in work thread context to set new TX/RX | |
774 | * maximum frame size values to match MTU. | |
775 | */ | |
776 | static int ql_set_port_cfg(struct ql_adapter *qdev) | |
777 | { | |
778 | int status; | |
779 | status = ql_mb_set_port_cfg(qdev); | |
780 | if (status) | |
781 | return status; | |
782 | status = ql_idc_wait(qdev); | |
783 | return status; | |
784 | } | |
785 | ||
786 | /* The following routines are worker threads that process | |
787 | * events that may sleep waiting for completion. | |
788 | */ | |
789 | ||
790 | /* This thread gets the maximum TX and RX frame size values | |
791 | * from the firmware and, if necessary, changes them to match | |
792 | * the MTU setting. | |
793 | */ | |
794 | void ql_mpi_port_cfg_work(struct work_struct *work) | |
795 | { | |
796 | struct ql_adapter *qdev = | |
797 | container_of(work, struct ql_adapter, mpi_port_cfg_work.work); | |
bcc2cb3b RM |
798 | int status; |
799 | ||
800 | status = ql_mb_get_port_cfg(qdev); | |
801 | if (status) { | |
802 | QPRINTK(qdev, DRV, ERR, | |
803 | "Bug: Failed to get port config data.\n"); | |
804 | goto err; | |
805 | } | |
806 | ||
c8269b21 | 807 | if (qdev->link_config & CFG_JUMBO_FRAME_SIZE && |
bcc2cb3b RM |
808 | qdev->max_frame_size == |
809 | CFG_DEFAULT_MAX_FRAME_SIZE) | |
810 | goto end; | |
811 | ||
812 | qdev->link_config |= CFG_JUMBO_FRAME_SIZE; | |
813 | qdev->max_frame_size = CFG_DEFAULT_MAX_FRAME_SIZE; | |
814 | status = ql_set_port_cfg(qdev); | |
815 | if (status) { | |
816 | QPRINTK(qdev, DRV, ERR, | |
817 | "Bug: Failed to set port config data.\n"); | |
818 | goto err; | |
819 | } | |
820 | end: | |
821 | clear_bit(QL_PORT_CFG, &qdev->flags); | |
822 | return; | |
823 | err: | |
824 | ql_queue_fw_error(qdev); | |
825 | goto end; | |
826 | } | |
827 | ||
2ee1e272 RM |
828 | /* Process an inter-device request. This is issues by |
829 | * the firmware in response to another function requesting | |
830 | * a change to the port. We set a flag to indicate a change | |
831 | * has been made and then send a mailbox command ACKing | |
832 | * the change request. | |
833 | */ | |
834 | void ql_mpi_idc_work(struct work_struct *work) | |
835 | { | |
836 | struct ql_adapter *qdev = | |
837 | container_of(work, struct ql_adapter, mpi_idc_work.work); | |
838 | int status; | |
839 | struct mbox_params *mbcp = &qdev->idc_mbc; | |
840 | u32 aen; | |
841 | ||
842 | aen = mbcp->mbox_out[1] >> 16; | |
843 | ||
844 | switch (aen) { | |
845 | default: | |
846 | QPRINTK(qdev, DRV, ERR, | |
847 | "Bug: Unhandled IDC action.\n"); | |
848 | break; | |
849 | case MB_CMD_PORT_RESET: | |
850 | case MB_CMD_SET_PORT_CFG: | |
851 | case MB_CMD_STOP_FW: | |
852 | netif_carrier_off(qdev->ndev); | |
853 | /* Signal the resulting link up AEN | |
854 | * that the frame routing and mac addr | |
855 | * needs to be set. | |
856 | * */ | |
857 | set_bit(QL_CAM_RT_SET, &qdev->flags); | |
858 | status = ql_mb_idc_ack(qdev); | |
859 | if (status) { | |
860 | QPRINTK(qdev, DRV, ERR, | |
861 | "Bug: No pending IDC!\n"); | |
862 | } | |
863 | } | |
864 | } | |
865 | ||
c4e84bde RM |
866 | void ql_mpi_work(struct work_struct *work) |
867 | { | |
868 | struct ql_adapter *qdev = | |
869 | container_of(work, struct ql_adapter, mpi_work.work); | |
870 | struct mbox_params mbc; | |
871 | struct mbox_params *mbcp = &mbc; | |
d6f58c2e | 872 | int err = 0; |
c4e84bde | 873 | |
125844ea | 874 | mutex_lock(&qdev->mpi_mutex); |
c4e84bde | 875 | |
125844ea RM |
876 | while (ql_read32(qdev, STS) & STS_PI) { |
877 | memset(mbcp, 0, sizeof(struct mbox_params)); | |
878 | mbcp->out_count = 1; | |
d6f58c2e RM |
879 | /* Don't continue if an async event |
880 | * did not complete properly. | |
881 | */ | |
882 | err = ql_mpi_handler(qdev, mbcp); | |
883 | if (err) | |
884 | break; | |
c4e84bde | 885 | } |
125844ea RM |
886 | |
887 | mutex_unlock(&qdev->mpi_mutex); | |
c4e84bde RM |
888 | ql_enable_completion_interrupt(qdev, 0); |
889 | } | |
890 | ||
891 | void ql_mpi_reset_work(struct work_struct *work) | |
892 | { | |
893 | struct ql_adapter *qdev = | |
894 | container_of(work, struct ql_adapter, mpi_reset_work.work); | |
bcc2cb3b RM |
895 | cancel_delayed_work_sync(&qdev->mpi_work); |
896 | cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); | |
2ee1e272 | 897 | cancel_delayed_work_sync(&qdev->mpi_idc_work); |
a2e809bb | 898 | ql_soft_reset_mpi_risc(qdev); |
c4e84bde | 899 | } |