Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

qlge: Add ethtool wake on LAN function.

parent d8eb59dc
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -796,6 +796,7 @@ enum {
	MB_WOL_BCAST = (1 << 5),
	MB_WOL_LINK_UP = (1 << 6),
	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_CLEAR_WOL_FLTR = 0x00000112, /* Wake On Lan Filter */
	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_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
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_get_led_cfg(struct ql_adapter *qdev);
void ql_link_on(struct ql_adapter *qdev);
+32 −0
Original line number Diff line number Diff line
@@ -371,6 +371,36 @@ static void ql_get_drvinfo(struct net_device *ndev,
	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)
{
@@ -523,6 +553,8 @@ static void ql_set_msglevel(struct net_device *ndev, u32 value)
const struct ethtool_ops qlge_ethtool_ops = {
	.get_settings = ql_get_settings,
	.get_drvinfo = ql_get_drvinfo,
	.get_wol = ql_get_wol,
	.set_wol = ql_set_wol,
	.get_msglevel = ql_get_msglevel,
	.set_msglevel = ql_set_msglevel,
	.get_link = ethtool_op_get_link,
+66 −0
Original line number Diff line number Diff line
@@ -3335,6 +3335,22 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
	 * the same MAC address.
	 */
	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. */
	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);
}

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)
{
	int i, status = 0;
@@ -4285,6 +4350,7 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state)
			return err;
	}

	ql_wol(qdev);
	err = pci_save_state(pdev);
	if (err)
		return err;
+70 −0
Original line number Diff line number Diff line
@@ -702,6 +702,76 @@ int ql_mb_get_port_cfg(struct ql_adapter *qdev)
	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...
 * Some firmware commands require consent of adjacent FCOE
 * function.  This function waits for the OK, or a