mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 03:10:12 +00:00
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>
This commit is contained in:
parent
d8eb59dc8b
commit
bc083ce98e
4 changed files with 172 additions and 0 deletions
|
@ -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);
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
|
|
Loading…
Reference in a new issue