diff options
author | Ron Mercer <ron.mercer@qlogic.com> | 2009-10-21 07:07:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-10-22 00:45:40 -0400 |
commit | bc083ce98eeb42205e99495481c8616d30916f6e (patch) | |
tree | b6111dd22d2d3a9102362b2e2a6b75e8aa928b74 /drivers | |
parent | d8eb59dc8b9e77bb4fa5420ff80142759ad5cd7b (diff) |
qlge: Add ethtool wake on LAN function.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/qlge/qlge.h | 4 | ||||
-rw-r--r-- | drivers/net/qlge/qlge_ethtool.c | 32 | ||||
-rw-r--r-- | drivers/net/qlge/qlge_main.c | 66 | ||||
-rw-r--r-- | drivers/net/qlge/qlge_mpi.c | 70 |
4 files changed, 172 insertions, 0 deletions
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index a5bb3a536538..ba2977699204 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h | |||
@@ -796,6 +796,7 @@ enum { | |||
796 | MB_WOL_BCAST = (1 << 5), | 796 | MB_WOL_BCAST = (1 << 5), |
797 | MB_WOL_LINK_UP = (1 << 6), | 797 | MB_WOL_LINK_UP = (1 << 6), |
798 | MB_WOL_LINK_DOWN = (1 << 7), | 798 | MB_WOL_LINK_DOWN = (1 << 7), |
799 | MB_WOL_MODE_ON = (1 << 16), /* Wake on Lan Mode on */ | ||
799 | MB_CMD_SET_WOL_FLTR = 0x00000111, /* Wake On Lan Filter */ | 800 | MB_CMD_SET_WOL_FLTR = 0x00000111, /* Wake On Lan Filter */ |
800 | MB_CMD_CLEAR_WOL_FLTR = 0x00000112, /* Wake On Lan Filter */ | 801 | MB_CMD_CLEAR_WOL_FLTR = 0x00000112, /* Wake On Lan Filter */ |
801 | MB_CMD_SET_WOL_MAGIC = 0x00000113, /* Wake On Lan Magic Packet */ | 802 | MB_CMD_SET_WOL_MAGIC = 0x00000113, /* Wake On Lan Magic Packet */ |
@@ -1646,6 +1647,9 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev); | |||
1646 | int ql_cam_route_initialize(struct ql_adapter *qdev); | 1647 | int ql_cam_route_initialize(struct ql_adapter *qdev); |
1647 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); | 1648 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); |
1648 | int ql_mb_about_fw(struct ql_adapter *qdev); | 1649 | int ql_mb_about_fw(struct ql_adapter *qdev); |
1650 | int ql_wol(struct ql_adapter *qdev); | ||
1651 | int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol); | ||
1652 | int ql_mb_wol_mode(struct ql_adapter *qdev, u32 wol); | ||
1649 | int ql_mb_set_led_cfg(struct ql_adapter *qdev, u32 led_config); | 1653 | int ql_mb_set_led_cfg(struct ql_adapter *qdev, u32 led_config); |
1650 | int ql_mb_get_led_cfg(struct ql_adapter *qdev); | 1654 | int ql_mb_get_led_cfg(struct ql_adapter *qdev); |
1651 | void ql_link_on(struct ql_adapter *qdev); | 1655 | void ql_link_on(struct ql_adapter *qdev); |
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 0c0549bc7bde..019f35fb10c1 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c | |||
@@ -371,6 +371,36 @@ static void ql_get_drvinfo(struct net_device *ndev, | |||
371 | drvinfo->eedump_len = 0; | 371 | drvinfo->eedump_len = 0; |
372 | } | 372 | } |
373 | 373 | ||
374 | static void ql_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) | ||
375 | { | ||
376 | struct ql_adapter *qdev = netdev_priv(ndev); | ||
377 | /* What we support. */ | ||
378 | wol->supported = WAKE_MAGIC; | ||
379 | /* What we've currently got set. */ | ||
380 | wol->wolopts = qdev->wol; | ||
381 | } | ||
382 | |||
383 | static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) | ||
384 | { | ||
385 | struct ql_adapter *qdev = netdev_priv(ndev); | ||
386 | int status; | ||
387 | |||
388 | if (wol->wolopts & ~WAKE_MAGIC) | ||
389 | return -EINVAL; | ||
390 | qdev->wol = wol->wolopts; | ||
391 | |||
392 | QPRINTK(qdev, DRV, INFO, "Set wol option 0x%x on %s\n", | ||
393 | qdev->wol, ndev->name); | ||
394 | if (!qdev->wol) { | ||
395 | u32 wol = 0; | ||
396 | status = ql_mb_wol_mode(qdev, wol); | ||
397 | QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n", | ||
398 | (status == 0) ? "cleared sucessfully" : "clear failed", | ||
399 | wol, qdev->ndev->name); | ||
400 | } | ||
401 | |||
402 | return 0; | ||
403 | } | ||
374 | 404 | ||
375 | static int ql_phys_id(struct net_device *ndev, u32 data) | 405 | static int ql_phys_id(struct net_device *ndev, u32 data) |
376 | { | 406 | { |
@@ -523,6 +553,8 @@ static void ql_set_msglevel(struct net_device *ndev, u32 value) | |||
523 | const struct ethtool_ops qlge_ethtool_ops = { | 553 | const struct ethtool_ops qlge_ethtool_ops = { |
524 | .get_settings = ql_get_settings, | 554 | .get_settings = ql_get_settings, |
525 | .get_drvinfo = ql_get_drvinfo, | 555 | .get_drvinfo = ql_get_drvinfo, |
556 | .get_wol = ql_get_wol, | ||
557 | .set_wol = ql_set_wol, | ||
526 | .get_msglevel = ql_get_msglevel, | 558 | .get_msglevel = ql_get_msglevel, |
527 | .set_msglevel = ql_set_msglevel, | 559 | .set_msglevel = ql_set_msglevel, |
528 | .get_link = ethtool_op_get_link, | 560 | .get_link = ethtool_op_get_link, |
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 34242fbcadff..dd0ea0277550 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c | |||
@@ -3335,6 +3335,22 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) | |||
3335 | * the same MAC address. | 3335 | * the same MAC address. |
3336 | */ | 3336 | */ |
3337 | ql_write32(qdev, RST_FO, RST_FO_RR_MASK | RST_FO_RR_RCV_FUNC_CQ); | 3337 | ql_write32(qdev, RST_FO, RST_FO_RR_MASK | RST_FO_RR_RCV_FUNC_CQ); |
3338 | /* Reroute all packets to our Interface. | ||
3339 | * They may have been routed to MPI firmware | ||
3340 | * due to WOL. | ||
3341 | */ | ||
3342 | value = ql_read32(qdev, MGMT_RCV_CFG); | ||
3343 | value &= ~MGMT_RCV_CFG_RM; | ||
3344 | mask = 0xffff0000; | ||
3345 | |||
3346 | /* Sticky reg needs clearing due to WOL. */ | ||
3347 | ql_write32(qdev, MGMT_RCV_CFG, mask); | ||
3348 | ql_write32(qdev, MGMT_RCV_CFG, mask | value); | ||
3349 | |||
3350 | /* Default WOL is enable on Mezz cards */ | ||
3351 | if (qdev->pdev->subsystem_device == 0x0068 || | ||
3352 | qdev->pdev->subsystem_device == 0x0180) | ||
3353 | qdev->wol = WAKE_MAGIC; | ||
3338 | 3354 | ||
3339 | /* Start up the rx queues. */ | 3355 | /* Start up the rx queues. */ |
3340 | for (i = 0; i < qdev->rx_ring_count; i++) { | 3356 | for (i = 0; i < qdev->rx_ring_count; i++) { |
@@ -3449,6 +3465,55 @@ static void ql_display_dev_info(struct net_device *ndev) | |||
3449 | QPRINTK(qdev, PROBE, INFO, "MAC address %pM\n", ndev->dev_addr); | 3465 | QPRINTK(qdev, PROBE, INFO, "MAC address %pM\n", ndev->dev_addr); |
3450 | } | 3466 | } |
3451 | 3467 | ||
3468 | int ql_wol(struct ql_adapter *qdev) | ||
3469 | { | ||
3470 | int status = 0; | ||
3471 | u32 wol = MB_WOL_DISABLE; | ||
3472 | |||
3473 | /* The CAM is still intact after a reset, but if we | ||
3474 | * are doing WOL, then we may need to program the | ||
3475 | * routing regs. We would also need to issue the mailbox | ||
3476 | * commands to instruct the MPI what to do per the ethtool | ||
3477 | * settings. | ||
3478 | */ | ||
3479 | |||
3480 | if (qdev->wol & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY | WAKE_UCAST | | ||
3481 | WAKE_MCAST | WAKE_BCAST)) { | ||
3482 | QPRINTK(qdev, IFDOWN, ERR, | ||
3483 | "Unsupported WOL paramter. qdev->wol = 0x%x.\n", | ||
3484 | qdev->wol); | ||
3485 | return -EINVAL; | ||
3486 | } | ||
3487 | |||
3488 | if (qdev->wol & WAKE_MAGIC) { | ||
3489 | status = ql_mb_wol_set_magic(qdev, 1); | ||
3490 | if (status) { | ||
3491 | QPRINTK(qdev, IFDOWN, ERR, | ||
3492 | "Failed to set magic packet on %s.\n", | ||
3493 | qdev->ndev->name); | ||
3494 | return status; | ||
3495 | } else | ||
3496 | QPRINTK(qdev, DRV, INFO, | ||
3497 | "Enabled magic packet successfully on %s.\n", | ||
3498 | qdev->ndev->name); | ||
3499 | |||
3500 | wol |= MB_WOL_MAGIC_PKT; | ||
3501 | } | ||
3502 | |||
3503 | if (qdev->wol) { | ||
3504 | /* Reroute all packets to Management Interface */ | ||
3505 | ql_write32(qdev, MGMT_RCV_CFG, (MGMT_RCV_CFG_RM | | ||
3506 | (MGMT_RCV_CFG_RM << 16))); | ||
3507 | wol |= MB_WOL_MODE_ON; | ||
3508 | status = ql_mb_wol_mode(qdev, wol); | ||
3509 | QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n", | ||
3510 | (status == 0) ? "Sucessfully set" : "Failed", wol, | ||
3511 | qdev->ndev->name); | ||
3512 | } | ||
3513 | |||
3514 | return status; | ||
3515 | } | ||
3516 | |||
3452 | static int ql_adapter_down(struct ql_adapter *qdev) | 3517 | static int ql_adapter_down(struct ql_adapter *qdev) |
3453 | { | 3518 | { |
3454 | int i, status = 0; | 3519 | int i, status = 0; |
@@ -4285,6 +4350,7 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state) | |||
4285 | return err; | 4350 | return err; |
4286 | } | 4351 | } |
4287 | 4352 | ||
4353 | ql_wol(qdev); | ||
4288 | err = pci_save_state(pdev); | 4354 | err = pci_save_state(pdev); |
4289 | if (err) | 4355 | if (err) |
4290 | return err; | 4356 | return err; |
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 14d76f13d1db..80b68539c5aa 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c | |||
@@ -702,6 +702,76 @@ int ql_mb_get_port_cfg(struct ql_adapter *qdev) | |||
702 | return status; | 702 | return status; |
703 | } | 703 | } |
704 | 704 | ||
705 | int ql_mb_wol_mode(struct ql_adapter *qdev, u32 wol) | ||
706 | { | ||
707 | struct mbox_params mbc; | ||
708 | struct mbox_params *mbcp = &mbc; | ||
709 | int status; | ||
710 | |||
711 | memset(mbcp, 0, sizeof(struct mbox_params)); | ||
712 | |||
713 | mbcp->in_count = 2; | ||
714 | mbcp->out_count = 1; | ||
715 | |||
716 | mbcp->mbox_in[0] = MB_CMD_SET_WOL_MODE; | ||
717 | mbcp->mbox_in[1] = wol; | ||
718 | |||
719 | |||
720 | status = ql_mailbox_command(qdev, mbcp); | ||
721 | if (status) | ||
722 | return status; | ||
723 | |||
724 | if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | ||
725 | QPRINTK(qdev, DRV, ERR, | ||
726 | "Failed to set WOL mode.\n"); | ||
727 | status = -EIO; | ||
728 | } | ||
729 | return status; | ||
730 | } | ||
731 | |||
732 | int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol) | ||
733 | { | ||
734 | struct mbox_params mbc; | ||
735 | struct mbox_params *mbcp = &mbc; | ||
736 | int status; | ||
737 | u8 *addr = qdev->ndev->dev_addr; | ||
738 | |||
739 | memset(mbcp, 0, sizeof(struct mbox_params)); | ||
740 | |||
741 | mbcp->in_count = 8; | ||
742 | mbcp->out_count = 1; | ||
743 | |||
744 | mbcp->mbox_in[0] = MB_CMD_SET_WOL_MAGIC; | ||
745 | if (enable_wol) { | ||
746 | mbcp->mbox_in[1] = (u32)addr[0]; | ||
747 | mbcp->mbox_in[2] = (u32)addr[1]; | ||
748 | mbcp->mbox_in[3] = (u32)addr[2]; | ||
749 | mbcp->mbox_in[4] = (u32)addr[3]; | ||
750 | mbcp->mbox_in[5] = (u32)addr[4]; | ||
751 | mbcp->mbox_in[6] = (u32)addr[5]; | ||
752 | mbcp->mbox_in[7] = 0; | ||
753 | } else { | ||
754 | mbcp->mbox_in[1] = 0; | ||
755 | mbcp->mbox_in[2] = 1; | ||
756 | mbcp->mbox_in[3] = 1; | ||
757 | mbcp->mbox_in[4] = 1; | ||
758 | mbcp->mbox_in[5] = 1; | ||
759 | mbcp->mbox_in[6] = 1; | ||
760 | mbcp->mbox_in[7] = 0; | ||
761 | } | ||
762 | |||
763 | status = ql_mailbox_command(qdev, mbcp); | ||
764 | if (status) | ||
765 | return status; | ||
766 | |||
767 | if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | ||
768 | QPRINTK(qdev, DRV, ERR, | ||
769 | "Failed to set WOL mode.\n"); | ||
770 | status = -EIO; | ||
771 | } | ||
772 | return status; | ||
773 | } | ||
774 | |||
705 | /* IDC - Inter Device Communication... | 775 | /* IDC - Inter Device Communication... |
706 | * Some firmware commands require consent of adjacent FCOE | 776 | * Some firmware commands require consent of adjacent FCOE |
707 | * function. This function waits for the OK, or a | 777 | * function. This function waits for the OK, or a |