Commit bc083ce9 authored by Ron Mercer's avatar Ron Mercer Committed by David S. Miller

qlge: Add ethtool wake on LAN function.

Signed-off-by: default avatarRon Mercer <ron.mercer@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d8eb59dc
...@@ -796,6 +796,7 @@ enum { ...@@ -796,6 +796,7 @@ enum {
MB_WOL_BCAST = (1 << 5), MB_WOL_BCAST = (1 << 5),
MB_WOL_LINK_UP = (1 << 6), MB_WOL_LINK_UP = (1 << 6),
MB_WOL_LINK_DOWN = (1 << 7), MB_WOL_LINK_DOWN = (1 << 7),
MB_WOL_MODE_ON = (1 << 16), /* Wake on Lan Mode on */
MB_CMD_SET_WOL_FLTR = 0x00000111, /* Wake On Lan Filter */ MB_CMD_SET_WOL_FLTR = 0x00000111, /* Wake On Lan Filter */
MB_CMD_CLEAR_WOL_FLTR = 0x00000112, /* Wake On Lan Filter */ MB_CMD_CLEAR_WOL_FLTR = 0x00000112, /* Wake On Lan Filter */
MB_CMD_SET_WOL_MAGIC = 0x00000113, /* Wake On Lan Magic Packet */ 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,6 +1647,9 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev);
int ql_cam_route_initialize(struct ql_adapter *qdev); int ql_cam_route_initialize(struct ql_adapter *qdev);
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
int ql_mb_about_fw(struct ql_adapter *qdev); int ql_mb_about_fw(struct ql_adapter *qdev);
int ql_wol(struct ql_adapter *qdev);
int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol);
int ql_mb_wol_mode(struct ql_adapter *qdev, u32 wol);
int ql_mb_set_led_cfg(struct ql_adapter *qdev, u32 led_config); int ql_mb_set_led_cfg(struct ql_adapter *qdev, u32 led_config);
int ql_mb_get_led_cfg(struct ql_adapter *qdev); int ql_mb_get_led_cfg(struct ql_adapter *qdev);
void ql_link_on(struct ql_adapter *qdev); void ql_link_on(struct ql_adapter *qdev);
......
...@@ -371,6 +371,36 @@ static void ql_get_drvinfo(struct net_device *ndev, ...@@ -371,6 +371,36 @@ static void ql_get_drvinfo(struct net_device *ndev,
drvinfo->eedump_len = 0; drvinfo->eedump_len = 0;
} }
static void ql_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
{
struct ql_adapter *qdev = netdev_priv(ndev);
/* What we support. */
wol->supported = WAKE_MAGIC;
/* What we've currently got set. */
wol->wolopts = qdev->wol;
}
static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
{
struct ql_adapter *qdev = netdev_priv(ndev);
int status;
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
qdev->wol = wol->wolopts;
QPRINTK(qdev, DRV, INFO, "Set wol option 0x%x on %s\n",
qdev->wol, ndev->name);
if (!qdev->wol) {
u32 wol = 0;
status = ql_mb_wol_mode(qdev, wol);
QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n",
(status == 0) ? "cleared sucessfully" : "clear failed",
wol, qdev->ndev->name);
}
return 0;
}
static int ql_phys_id(struct net_device *ndev, u32 data) static int ql_phys_id(struct net_device *ndev, u32 data)
{ {
...@@ -523,6 +553,8 @@ static void ql_set_msglevel(struct net_device *ndev, u32 value) ...@@ -523,6 +553,8 @@ static void ql_set_msglevel(struct net_device *ndev, u32 value)
const struct ethtool_ops qlge_ethtool_ops = { const struct ethtool_ops qlge_ethtool_ops = {
.get_settings = ql_get_settings, .get_settings = ql_get_settings,
.get_drvinfo = ql_get_drvinfo, .get_drvinfo = ql_get_drvinfo,
.get_wol = ql_get_wol,
.set_wol = ql_set_wol,
.get_msglevel = ql_get_msglevel, .get_msglevel = ql_get_msglevel,
.set_msglevel = ql_set_msglevel, .set_msglevel = ql_set_msglevel,
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
......
...@@ -3335,6 +3335,22 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) ...@@ -3335,6 +3335,22 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
* the same MAC address. * the same MAC address.
*/ */
ql_write32(qdev, RST_FO, RST_FO_RR_MASK | RST_FO_RR_RCV_FUNC_CQ); ql_write32(qdev, RST_FO, RST_FO_RR_MASK | RST_FO_RR_RCV_FUNC_CQ);
/* Reroute all packets to our Interface.
* They may have been routed to MPI firmware
* due to WOL.
*/
value = ql_read32(qdev, MGMT_RCV_CFG);
value &= ~MGMT_RCV_CFG_RM;
mask = 0xffff0000;
/* Sticky reg needs clearing due to WOL. */
ql_write32(qdev, MGMT_RCV_CFG, mask);
ql_write32(qdev, MGMT_RCV_CFG, mask | value);
/* Default WOL is enable on Mezz cards */
if (qdev->pdev->subsystem_device == 0x0068 ||
qdev->pdev->subsystem_device == 0x0180)
qdev->wol = WAKE_MAGIC;
/* Start up the rx queues. */ /* Start up the rx queues. */
for (i = 0; i < qdev->rx_ring_count; i++) { for (i = 0; i < qdev->rx_ring_count; i++) {
...@@ -3449,6 +3465,55 @@ static void ql_display_dev_info(struct net_device *ndev) ...@@ -3449,6 +3465,55 @@ static void ql_display_dev_info(struct net_device *ndev)
QPRINTK(qdev, PROBE, INFO, "MAC address %pM\n", ndev->dev_addr); QPRINTK(qdev, PROBE, INFO, "MAC address %pM\n", ndev->dev_addr);
} }
int ql_wol(struct ql_adapter *qdev)
{
int status = 0;
u32 wol = MB_WOL_DISABLE;
/* The CAM is still intact after a reset, but if we
* are doing WOL, then we may need to program the
* routing regs. We would also need to issue the mailbox
* commands to instruct the MPI what to do per the ethtool
* settings.
*/
if (qdev->wol & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY | WAKE_UCAST |
WAKE_MCAST | WAKE_BCAST)) {
QPRINTK(qdev, IFDOWN, ERR,
"Unsupported WOL paramter. qdev->wol = 0x%x.\n",
qdev->wol);
return -EINVAL;
}
if (qdev->wol & WAKE_MAGIC) {
status = ql_mb_wol_set_magic(qdev, 1);
if (status) {
QPRINTK(qdev, IFDOWN, ERR,
"Failed to set magic packet on %s.\n",
qdev->ndev->name);
return status;
} else
QPRINTK(qdev, DRV, INFO,
"Enabled magic packet successfully on %s.\n",
qdev->ndev->name);
wol |= MB_WOL_MAGIC_PKT;
}
if (qdev->wol) {
/* Reroute all packets to Management Interface */
ql_write32(qdev, MGMT_RCV_CFG, (MGMT_RCV_CFG_RM |
(MGMT_RCV_CFG_RM << 16)));
wol |= MB_WOL_MODE_ON;
status = ql_mb_wol_mode(qdev, wol);
QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n",
(status == 0) ? "Sucessfully set" : "Failed", wol,
qdev->ndev->name);
}
return status;
}
static int ql_adapter_down(struct ql_adapter *qdev) static int ql_adapter_down(struct ql_adapter *qdev)
{ {
int i, status = 0; int i, status = 0;
...@@ -4285,6 +4350,7 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state) ...@@ -4285,6 +4350,7 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state)
return err; return err;
} }
ql_wol(qdev);
err = pci_save_state(pdev); err = pci_save_state(pdev);
if (err) if (err)
return err; return err;
......
...@@ -702,6 +702,76 @@ int ql_mb_get_port_cfg(struct ql_adapter *qdev) ...@@ -702,6 +702,76 @@ int ql_mb_get_port_cfg(struct ql_adapter *qdev)
return status; return status;
} }
int ql_mb_wol_mode(struct ql_adapter *qdev, u32 wol)
{
struct mbox_params mbc;
struct mbox_params *mbcp = &mbc;
int status;
memset(mbcp, 0, sizeof(struct mbox_params));
mbcp->in_count = 2;
mbcp->out_count = 1;
mbcp->mbox_in[0] = MB_CMD_SET_WOL_MODE;
mbcp->mbox_in[1] = wol;
status = ql_mailbox_command(qdev, mbcp);
if (status)
return status;
if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
QPRINTK(qdev, DRV, ERR,
"Failed to set WOL mode.\n");
status = -EIO;
}
return status;
}
int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol)
{
struct mbox_params mbc;
struct mbox_params *mbcp = &mbc;
int status;
u8 *addr = qdev->ndev->dev_addr;
memset(mbcp, 0, sizeof(struct mbox_params));
mbcp->in_count = 8;
mbcp->out_count = 1;
mbcp->mbox_in[0] = MB_CMD_SET_WOL_MAGIC;
if (enable_wol) {
mbcp->mbox_in[1] = (u32)addr[0];
mbcp->mbox_in[2] = (u32)addr[1];
mbcp->mbox_in[3] = (u32)addr[2];
mbcp->mbox_in[4] = (u32)addr[3];
mbcp->mbox_in[5] = (u32)addr[4];
mbcp->mbox_in[6] = (u32)addr[5];
mbcp->mbox_in[7] = 0;
} else {
mbcp->mbox_in[1] = 0;
mbcp->mbox_in[2] = 1;
mbcp->mbox_in[3] = 1;
mbcp->mbox_in[4] = 1;
mbcp->mbox_in[5] = 1;
mbcp->mbox_in[6] = 1;
mbcp->mbox_in[7] = 0;
}
status = ql_mailbox_command(qdev, mbcp);
if (status)
return status;
if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
QPRINTK(qdev, DRV, ERR,
"Failed to set WOL mode.\n");
status = -EIO;
}
return status;
}
/* IDC - Inter Device Communication... /* IDC - Inter Device Communication...
* Some firmware commands require consent of adjacent FCOE * Some firmware commands require consent of adjacent FCOE
* function. This function waits for the OK, or a * function. This function waits for the OK, or a
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment