diff options
author | Ron Mercer <ron.mercer@qlogic.com> | 2009-03-02 03:07:32 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-03 01:45:24 -0500 |
commit | bcc2cb3b97e37317c301309d7052bb61e6cce2c4 (patch) | |
tree | e1eed42ab44980713cc6b8d38e917e0d27ff9bcd /drivers/net/qlge/qlge_mpi.c | |
parent | cdca8d02ea4229c2ccf3c27fb537b150843f67c9 (diff) |
qlge: Add support for getting/setting port config.
This patch adds functionality to get and set port parameters.
Currently it is used to set maximum TX/RX frame sizes. This process is
also capable of setting:
1) Pause type: Standard or Priority based.
2) Loop back mode.
3) Enable Jumbo frame mode (included here...)
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlge/qlge_mpi.c')
-rw-r--r-- | drivers/net/qlge/qlge_mpi.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 11102bec36b2..ef610c674dfb 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c | |||
@@ -138,6 +138,27 @@ end: | |||
138 | return status; | 138 | return status; |
139 | } | 139 | } |
140 | 140 | ||
141 | /* Process an inter-device event completion. | ||
142 | * If good, signal the caller's completion. | ||
143 | */ | ||
144 | static int ql_idc_cmplt_aen(struct ql_adapter *qdev) | ||
145 | { | ||
146 | int status; | ||
147 | struct mbox_params *mbcp = &qdev->idc_mbc; | ||
148 | mbcp->out_count = 4; | ||
149 | status = ql_get_mb_sts(qdev, mbcp); | ||
150 | if (status) { | ||
151 | QPRINTK(qdev, DRV, ERR, | ||
152 | "Could not read MPI, resetting RISC!\n"); | ||
153 | ql_queue_fw_error(qdev); | ||
154 | } else | ||
155 | /* Wake up the sleeping mpi_idc_work thread that is | ||
156 | * waiting for this event. | ||
157 | */ | ||
158 | complete(&qdev->ide_completion); | ||
159 | |||
160 | return status; | ||
161 | } | ||
141 | static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) | 162 | static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) |
142 | { | 163 | { |
143 | mbcp->out_count = 2; | 164 | mbcp->out_count = 2; |
@@ -241,6 +262,16 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) | |||
241 | status = ql_get_mb_sts(qdev, mbcp); | 262 | status = ql_get_mb_sts(qdev, mbcp); |
242 | return status; | 263 | return status; |
243 | 264 | ||
265 | /* Process and inbound IDC event. | ||
266 | * This will happen when we're trying to | ||
267 | * change tx/rx max frame size, change pause | ||
268 | * paramters or loopback mode. | ||
269 | */ | ||
270 | case AEN_IDC_CMPLT: | ||
271 | case AEN_IDC_EXT: | ||
272 | status = ql_idc_cmplt_aen(qdev); | ||
273 | break; | ||
274 | |||
244 | case AEN_LINK_UP: | 275 | case AEN_LINK_UP: |
245 | ql_link_up(qdev, mbcp); | 276 | ql_link_up(qdev, mbcp); |
246 | break; | 277 | break; |
@@ -391,6 +422,182 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev) | |||
391 | return status; | 422 | return status; |
392 | } | 423 | } |
393 | 424 | ||
425 | /* Get link settings and maximum frame size settings | ||
426 | * for the current port. | ||
427 | * Most likely will block. | ||
428 | */ | ||
429 | static int ql_mb_set_port_cfg(struct ql_adapter *qdev) | ||
430 | { | ||
431 | struct mbox_params mbc; | ||
432 | struct mbox_params *mbcp = &mbc; | ||
433 | int status = 0; | ||
434 | |||
435 | memset(mbcp, 0, sizeof(struct mbox_params)); | ||
436 | |||
437 | mbcp->in_count = 3; | ||
438 | mbcp->out_count = 1; | ||
439 | |||
440 | mbcp->mbox_in[0] = MB_CMD_SET_PORT_CFG; | ||
441 | mbcp->mbox_in[1] = qdev->link_config; | ||
442 | mbcp->mbox_in[2] = qdev->max_frame_size; | ||
443 | |||
444 | |||
445 | status = ql_mailbox_command(qdev, mbcp); | ||
446 | if (status) | ||
447 | return status; | ||
448 | |||
449 | if (mbcp->mbox_out[0] == MB_CMD_STS_INTRMDT) { | ||
450 | QPRINTK(qdev, DRV, ERR, | ||
451 | "Port Config sent, wait for IDC.\n"); | ||
452 | } else if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | ||
453 | QPRINTK(qdev, DRV, ERR, | ||
454 | "Failed Set Port Configuration.\n"); | ||
455 | status = -EIO; | ||
456 | } | ||
457 | return status; | ||
458 | } | ||
459 | |||
460 | /* Get link settings and maximum frame size settings | ||
461 | * for the current port. | ||
462 | * Most likely will block. | ||
463 | */ | ||
464 | static int ql_mb_get_port_cfg(struct ql_adapter *qdev) | ||
465 | { | ||
466 | struct mbox_params mbc; | ||
467 | struct mbox_params *mbcp = &mbc; | ||
468 | int status = 0; | ||
469 | |||
470 | memset(mbcp, 0, sizeof(struct mbox_params)); | ||
471 | |||
472 | mbcp->in_count = 1; | ||
473 | mbcp->out_count = 3; | ||
474 | |||
475 | mbcp->mbox_in[0] = MB_CMD_GET_PORT_CFG; | ||
476 | |||
477 | status = ql_mailbox_command(qdev, mbcp); | ||
478 | if (status) | ||
479 | return status; | ||
480 | |||
481 | if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | ||
482 | QPRINTK(qdev, DRV, ERR, | ||
483 | "Failed Get Port Configuration.\n"); | ||
484 | status = -EIO; | ||
485 | } else { | ||
486 | QPRINTK(qdev, DRV, DEBUG, | ||
487 | "Passed Get Port Configuration.\n"); | ||
488 | qdev->link_config = mbcp->mbox_out[1]; | ||
489 | qdev->max_frame_size = mbcp->mbox_out[2]; | ||
490 | } | ||
491 | return status; | ||
492 | } | ||
493 | |||
494 | /* IDC - Inter Device Communication... | ||
495 | * Some firmware commands require consent of adjacent FCOE | ||
496 | * function. This function waits for the OK, or a | ||
497 | * counter-request for a little more time.i | ||
498 | * The firmware will complete the request if the other | ||
499 | * function doesn't respond. | ||
500 | */ | ||
501 | static int ql_idc_wait(struct ql_adapter *qdev) | ||
502 | { | ||
503 | int status = -ETIMEDOUT; | ||
504 | long wait_time = 1 * HZ; | ||
505 | struct mbox_params *mbcp = &qdev->idc_mbc; | ||
506 | do { | ||
507 | /* Wait here for the command to complete | ||
508 | * via the IDC process. | ||
509 | */ | ||
510 | wait_time = | ||
511 | wait_for_completion_timeout(&qdev->ide_completion, | ||
512 | wait_time); | ||
513 | if (!wait_time) { | ||
514 | QPRINTK(qdev, DRV, ERR, | ||
515 | "IDC Timeout.\n"); | ||
516 | break; | ||
517 | } | ||
518 | /* Now examine the response from the IDC process. | ||
519 | * We might have a good completion or a request for | ||
520 | * more wait time. | ||
521 | */ | ||
522 | if (mbcp->mbox_out[0] == AEN_IDC_EXT) { | ||
523 | QPRINTK(qdev, DRV, ERR, | ||
524 | "IDC Time Extension from function.\n"); | ||
525 | wait_time += (mbcp->mbox_out[1] >> 8) & 0x0000000f; | ||
526 | } else if (mbcp->mbox_out[0] == AEN_IDC_CMPLT) { | ||
527 | QPRINTK(qdev, DRV, ERR, | ||
528 | "IDC Success.\n"); | ||
529 | status = 0; | ||
530 | break; | ||
531 | } else { | ||
532 | QPRINTK(qdev, DRV, ERR, | ||
533 | "IDC: Invalid State 0x%.04x.\n", | ||
534 | mbcp->mbox_out[0]); | ||
535 | status = -EIO; | ||
536 | break; | ||
537 | } | ||
538 | } while (wait_time); | ||
539 | |||
540 | return status; | ||
541 | } | ||
542 | |||
543 | /* API called in work thread context to set new TX/RX | ||
544 | * maximum frame size values to match MTU. | ||
545 | */ | ||
546 | static int ql_set_port_cfg(struct ql_adapter *qdev) | ||
547 | { | ||
548 | int status; | ||
549 | status = ql_mb_set_port_cfg(qdev); | ||
550 | if (status) | ||
551 | return status; | ||
552 | status = ql_idc_wait(qdev); | ||
553 | return status; | ||
554 | } | ||
555 | |||
556 | /* The following routines are worker threads that process | ||
557 | * events that may sleep waiting for completion. | ||
558 | */ | ||
559 | |||
560 | /* This thread gets the maximum TX and RX frame size values | ||
561 | * from the firmware and, if necessary, changes them to match | ||
562 | * the MTU setting. | ||
563 | */ | ||
564 | void ql_mpi_port_cfg_work(struct work_struct *work) | ||
565 | { | ||
566 | struct ql_adapter *qdev = | ||
567 | container_of(work, struct ql_adapter, mpi_port_cfg_work.work); | ||
568 | struct net_device *ndev = qdev->ndev; | ||
569 | int status; | ||
570 | |||
571 | status = ql_mb_get_port_cfg(qdev); | ||
572 | if (status) { | ||
573 | QPRINTK(qdev, DRV, ERR, | ||
574 | "Bug: Failed to get port config data.\n"); | ||
575 | goto err; | ||
576 | } | ||
577 | |||
578 | if (ndev->mtu <= 2500) | ||
579 | goto end; | ||
580 | else if (qdev->link_config & CFG_JUMBO_FRAME_SIZE && | ||
581 | qdev->max_frame_size == | ||
582 | CFG_DEFAULT_MAX_FRAME_SIZE) | ||
583 | goto end; | ||
584 | |||
585 | qdev->link_config |= CFG_JUMBO_FRAME_SIZE; | ||
586 | qdev->max_frame_size = CFG_DEFAULT_MAX_FRAME_SIZE; | ||
587 | status = ql_set_port_cfg(qdev); | ||
588 | if (status) { | ||
589 | QPRINTK(qdev, DRV, ERR, | ||
590 | "Bug: Failed to set port config data.\n"); | ||
591 | goto err; | ||
592 | } | ||
593 | end: | ||
594 | clear_bit(QL_PORT_CFG, &qdev->flags); | ||
595 | return; | ||
596 | err: | ||
597 | ql_queue_fw_error(qdev); | ||
598 | goto end; | ||
599 | } | ||
600 | |||
394 | void ql_mpi_work(struct work_struct *work) | 601 | void ql_mpi_work(struct work_struct *work) |
395 | { | 602 | { |
396 | struct ql_adapter *qdev = | 603 | struct ql_adapter *qdev = |
@@ -414,5 +621,7 @@ void ql_mpi_reset_work(struct work_struct *work) | |||
414 | { | 621 | { |
415 | struct ql_adapter *qdev = | 622 | struct ql_adapter *qdev = |
416 | container_of(work, struct ql_adapter, mpi_reset_work.work); | 623 | container_of(work, struct ql_adapter, mpi_reset_work.work); |
624 | cancel_delayed_work_sync(&qdev->mpi_work); | ||
625 | cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); | ||
417 | ql_soft_reset_mpi_risc(qdev); | 626 | ql_soft_reset_mpi_risc(qdev); |
418 | } | 627 | } |