aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/qlge/qlge_mpi.c
diff options
context:
space:
mode:
authorRon Mercer <ron.mercer@qlogic.com>2009-03-03 07:10:33 -0500
committerDavid S. Miller <davem@davemloft.net>2009-03-04 02:50:47 -0500
commit2ee1e272d1661d7846da753248a4141ad5f16d69 (patch)
tree0e2f80fc7b36a85d1ac4f19b2f0955cddc56a858 /drivers/net/qlge/qlge_mpi.c
parent5700abe94794cd548d9cb8bfb7e00eb7a8bedb60 (diff)
qlge: Add worker-handler for firmware events.
This worker and it's supporting routines are used for IDC 'inter-device-communication' events that require an ACK mailbox command be sent to allow completion of the request. These requests are originated by another function wanting to change some common port paramters. Typical example would be: 1) Change max TX/RX frame size allowed. 2) Change pause parameters. 3) Change loopback mode. 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.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 3b4b494387aa..9f1fe542e271 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -138,6 +138,40 @@ end:
138 return status; 138 return status;
139} 139}
140 140
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 */
148static 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
141/* Process an inter-device event completion. 175/* Process an inter-device event completion.
142 * If good, signal the caller's completion. 176 * If good, signal the caller's completion.
143 */ 177 */
@@ -175,6 +209,35 @@ static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp)
175 qdev->link_status = mbcp->mbox_out[1]; 209 qdev->link_status = mbcp->mbox_out[1];
176 QPRINTK(qdev, DRV, ERR, "Link Up.\n"); 210 QPRINTK(qdev, DRV, ERR, "Link Up.\n");
177 211
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
178 netif_carrier_on(qdev->ndev); 241 netif_carrier_on(qdev->ndev);
179} 242}
180 243
@@ -283,6 +346,15 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
283 status = ql_get_mb_sts(qdev, mbcp); 346 status = ql_get_mb_sts(qdev, mbcp);
284 return status; 347 return status;
285 348
349 /* We are being asked by firmware to accept
350 * a change to the port. This is only
351 * a change to max frame sizes (Tx/Rx), pause
352 * paramters, or loopback mode.
353 */
354 case AEN_IDC_REQ:
355 status = ql_idc_req_aen(qdev);
356 break;
357
286 /* Process and inbound IDC event. 358 /* Process and inbound IDC event.
287 * This will happen when we're trying to 359 * This will happen when we're trying to
288 * change tx/rx max frame size, change pause 360 * change tx/rx max frame size, change pause
@@ -451,6 +523,38 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev)
451 return status; 523 return status;
452} 524}
453 525
526/* Send and ACK mailbox command to the firmware to
527 * let it continue with the change.
528 */
529int ql_mb_idc_ack(struct ql_adapter *qdev)
530{
531 struct mbox_params mbc;
532 struct mbox_params *mbcp = &mbc;
533 int status = 0;
534
535 memset(mbcp, 0, sizeof(struct mbox_params));
536
537 mbcp->in_count = 5;
538 mbcp->out_count = 1;
539
540 mbcp->mbox_in[0] = MB_CMD_IDC_ACK;
541 mbcp->mbox_in[1] = qdev->idc_mbc.mbox_out[1];
542 mbcp->mbox_in[2] = qdev->idc_mbc.mbox_out[2];
543 mbcp->mbox_in[3] = qdev->idc_mbc.mbox_out[3];
544 mbcp->mbox_in[4] = qdev->idc_mbc.mbox_out[4];
545
546 status = ql_mailbox_command(qdev, mbcp);
547 if (status)
548 return status;
549
550 if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
551 QPRINTK(qdev, DRV, ERR,
552 "Failed IDC ACK send.\n");
553 status = -EIO;
554 }
555 return status;
556}
557
454/* Get link settings and maximum frame size settings 558/* Get link settings and maximum frame size settings
455 * for the current port. 559 * for the current port.
456 * Most likely will block. 560 * Most likely will block.
@@ -627,6 +731,44 @@ err:
627 goto end; 731 goto end;
628} 732}
629 733
734/* Process an inter-device request. This is issues by
735 * the firmware in response to another function requesting
736 * a change to the port. We set a flag to indicate a change
737 * has been made and then send a mailbox command ACKing
738 * the change request.
739 */
740void ql_mpi_idc_work(struct work_struct *work)
741{
742 struct ql_adapter *qdev =
743 container_of(work, struct ql_adapter, mpi_idc_work.work);
744 int status;
745 struct mbox_params *mbcp = &qdev->idc_mbc;
746 u32 aen;
747
748 aen = mbcp->mbox_out[1] >> 16;
749
750 switch (aen) {
751 default:
752 QPRINTK(qdev, DRV, ERR,
753 "Bug: Unhandled IDC action.\n");
754 break;
755 case MB_CMD_PORT_RESET:
756 case MB_CMD_SET_PORT_CFG:
757 case MB_CMD_STOP_FW:
758 netif_carrier_off(qdev->ndev);
759 /* Signal the resulting link up AEN
760 * that the frame routing and mac addr
761 * needs to be set.
762 * */
763 set_bit(QL_CAM_RT_SET, &qdev->flags);
764 status = ql_mb_idc_ack(qdev);
765 if (status) {
766 QPRINTK(qdev, DRV, ERR,
767 "Bug: No pending IDC!\n");
768 }
769 }
770}
771
630void ql_mpi_work(struct work_struct *work) 772void ql_mpi_work(struct work_struct *work)
631{ 773{
632 struct ql_adapter *qdev = 774 struct ql_adapter *qdev =
@@ -652,5 +794,6 @@ void ql_mpi_reset_work(struct work_struct *work)
652 container_of(work, struct ql_adapter, mpi_reset_work.work); 794 container_of(work, struct ql_adapter, mpi_reset_work.work);
653 cancel_delayed_work_sync(&qdev->mpi_work); 795 cancel_delayed_work_sync(&qdev->mpi_work);
654 cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); 796 cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
797 cancel_delayed_work_sync(&qdev->mpi_idc_work);
655 ql_soft_reset_mpi_risc(qdev); 798 ql_soft_reset_mpi_risc(qdev);
656} 799}