qed*: Add support for WoL

Signed-off-by: Yuval Mintz <Yuval.Mintz@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Mintz, Yuval
2016-10-31 07:14:23 +02:00
committed by David S. Miller
parent 7a4b21b7d1
commit 14d39648cb
9 changed files with 176 additions and 5 deletions

View File

@@ -195,6 +195,11 @@ enum qed_dev_cap {
QED_DEV_CAP_ROCE,
};
enum qed_wol_support {
QED_WOL_SUPPORT_NONE,
QED_WOL_SUPPORT_PME,
};
struct qed_hw_info {
/* PCI personality */
enum qed_pci_personality personality;
@@ -227,6 +232,8 @@ struct qed_hw_info {
u32 hw_mode;
unsigned long device_capabilities;
u16 mtu;
enum qed_wol_support b_wol_support;
};
struct qed_hw_cid_data {
@@ -539,7 +546,9 @@ struct qed_dev {
u8 mcp_rev;
u8 boot_mode;
u8 wol;
/* WoL related configurations */
u8 wol_config;
u8 wol_mac[ETH_ALEN];
u32 int_mode;
enum qed_coalescing_mode int_coalescing_mode;

View File

@@ -1364,8 +1364,24 @@ int qed_hw_reset(struct qed_dev *cdev)
{
int rc = 0;
u32 unload_resp, unload_param;
u32 wol_param;
int i;
switch (cdev->wol_config) {
case QED_OV_WOL_DISABLED:
wol_param = DRV_MB_PARAM_UNLOAD_WOL_DISABLED;
break;
case QED_OV_WOL_ENABLED:
wol_param = DRV_MB_PARAM_UNLOAD_WOL_ENABLED;
break;
default:
DP_NOTICE(cdev,
"Unknown WoL configuration %02x\n", cdev->wol_config);
/* Fallthrough */
case QED_OV_WOL_DEFAULT:
wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP;
}
for_each_hwfn(cdev, i) {
struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
@@ -1394,8 +1410,7 @@ int qed_hw_reset(struct qed_dev *cdev)
/* Send unload command to MCP */
rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
DRV_MSG_CODE_UNLOAD_REQ,
DRV_MB_PARAM_UNLOAD_WOL_MCP,
DRV_MSG_CODE_UNLOAD_REQ, wol_param,
&unload_resp, &unload_param);
if (rc) {
DP_NOTICE(p_hwfn, "qed_hw_reset: UNLOAD_REQ failed\n");

View File

@@ -8601,6 +8601,7 @@ struct public_drv_mb {
#define DRV_MSG_CODE_BIST_TEST 0x001e0000
#define DRV_MSG_CODE_SET_LED_MODE 0x00200000
#define DRV_MSG_CODE_OS_WOL 0x002e0000
#define DRV_MSG_SEQ_NUMBER_MASK 0x0000ffff
@@ -8697,6 +8698,9 @@ struct public_drv_mb {
#define FW_MSG_CODE_NVM_OK 0x00010000
#define FW_MSG_CODE_OK 0x00160000
#define FW_MSG_CODE_OS_WOL_SUPPORTED 0x00800000
#define FW_MSG_CODE_OS_WOL_NOT_SUPPORTED 0x00810000
#define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff
u32 fw_mb_param;

View File

@@ -221,6 +221,10 @@ int qed_fill_dev_info(struct qed_dev *cdev,
dev_info->fw_eng = FW_ENGINEERING_VERSION;
dev_info->mf_mode = cdev->mf_mode;
dev_info->tx_switching = true;
if (QED_LEADING_HWFN(cdev)->hw_info.b_wol_support ==
QED_WOL_SUPPORT_PME)
dev_info->wol_support = true;
} else {
qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major,
&dev_info->fw_minor, &dev_info->fw_rev,
@@ -1433,6 +1437,30 @@ static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode)
return status;
}
static int qed_update_wol(struct qed_dev *cdev, bool enabled)
{
struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
struct qed_ptt *ptt;
int rc = 0;
if (IS_VF(cdev))
return 0;
ptt = qed_ptt_acquire(hwfn);
if (!ptt)
return -EAGAIN;
rc = qed_mcp_ov_update_wol(hwfn, ptt, enabled ? QED_OV_WOL_ENABLED
: QED_OV_WOL_DISABLED);
if (rc)
goto out;
rc = qed_mcp_ov_update_current_config(hwfn, ptt, QED_OV_CLIENT_DRV);
out:
qed_ptt_release(hwfn, ptt);
return rc;
}
static int qed_update_drv_state(struct qed_dev *cdev, bool active)
{
struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
@@ -1541,6 +1569,7 @@ const struct qed_common_ops qed_common_ops_pass = {
.update_drv_state = &qed_update_drv_state,
.update_mac = &qed_update_mac,
.update_mtu = &qed_update_mtu,
.update_wol = &qed_update_wol,
};
void qed_get_protocol_stats(struct qed_dev *cdev,

View File

@@ -330,6 +330,7 @@ static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn,
struct qed_mcp_mb_params *p_mb_params)
{
u32 union_data_addr;
int rc;
/* MCP not initialized */
@@ -375,11 +376,32 @@ int qed_mcp_cmd(struct qed_hwfn *p_hwfn,
u32 *o_mcp_param)
{
struct qed_mcp_mb_params mb_params;
union drv_union_data data_src;
int rc;
memset(&mb_params, 0, sizeof(mb_params));
memset(&data_src, 0, sizeof(data_src));
mb_params.cmd = cmd;
mb_params.param = param;
/* In case of UNLOAD_DONE, set the primary MAC */
if ((cmd == DRV_MSG_CODE_UNLOAD_DONE) &&
(p_hwfn->cdev->wol_config == QED_OV_WOL_ENABLED)) {
u8 *p_mac = p_hwfn->cdev->wol_mac;
data_src.wol_mac.mac_upper = p_mac[0] << 8 | p_mac[1];
data_src.wol_mac.mac_lower = p_mac[2] << 24 | p_mac[3] << 16 |
p_mac[4] << 8 | p_mac[5];
DP_VERBOSE(p_hwfn,
(QED_MSG_SP | NETIF_MSG_IFDOWN),
"Setting WoL MAC: %pM --> [%08x,%08x]\n",
p_mac, data_src.wol_mac.mac_upper,
data_src.wol_mac.mac_lower);
mb_params.p_data_src = &data_src;
}
rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
if (rc)
return rc;
@@ -1058,6 +1080,9 @@ int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn,
info->mac[3] = (u8)(shmem_info.mac_lower >> 16);
info->mac[4] = (u8)(shmem_info.mac_lower >> 8);
info->mac[5] = (u8)(shmem_info.mac_lower);
/* Store primary MAC for later possible WoL */
memcpy(&p_hwfn->cdev->wol_mac, info->mac, ETH_ALEN);
} else {
DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n");
}
@@ -1071,13 +1096,28 @@ int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn,
info->mtu = (u16)shmem_info.mtu_size;
p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_NONE;
p_hwfn->cdev->wol_config = (u8)QED_OV_WOL_DEFAULT;
if (qed_mcp_is_init(p_hwfn)) {
u32 resp = 0, param = 0;
int rc;
rc = qed_mcp_cmd(p_hwfn, p_ptt,
DRV_MSG_CODE_OS_WOL, 0, &resp, &param);
if (rc)
return rc;
if (resp == FW_MSG_CODE_OS_WOL_SUPPORTED)
p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_PME;
}
DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_IFUP),
"Read configuration from shmem: pause_on_host %02x protocol %02x BW [%02x - %02x] MAC %02x:%02x:%02x:%02x:%02x:%02x wwn port %llx node %llx ovlan %04x\n",
"Read configuration from shmem: pause_on_host %02x protocol %02x BW [%02x - %02x] MAC %02x:%02x:%02x:%02x:%02x:%02x wwn port %llx node %llx ovlan %04x wol %02x\n",
info->pause_on_host, info->protocol,
info->bandwidth_min, info->bandwidth_max,
info->mac[0], info->mac[1], info->mac[2],
info->mac[3], info->mac[4], info->mac[5],
info->wwn_port, info->wwn_node, info->ovlan);
info->wwn_port, info->wwn_node,
info->ovlan, (u8)p_hwfn->hw_info.b_wol_support);
return 0;
}
@@ -1322,6 +1362,9 @@ int qed_mcp_ov_update_mac(struct qed_hwfn *p_hwfn,
if (rc)
DP_ERR(p_hwfn, "Failed to send mac address, rc = %d\n", rc);
/* Store primary MAC for later possible WoL */
memcpy(p_hwfn->cdev->wol_mac, mac, ETH_ALEN);
return rc;
}
@@ -1332,6 +1375,12 @@ int qed_mcp_ov_update_wol(struct qed_hwfn *p_hwfn,
u32 drv_mb_param;
int rc;
if (p_hwfn->hw_info.b_wol_support == QED_WOL_SUPPORT_NONE) {
DP_VERBOSE(p_hwfn, QED_MSG_SP,
"Can't change WoL configuration when WoL isn't supported\n");
return -EINVAL;
}
switch (wol) {
case QED_OV_WOL_DEFAULT:
drv_mb_param = DRV_MB_PARAM_WOL_DEFAULT;
@@ -1352,6 +1401,9 @@ int qed_mcp_ov_update_wol(struct qed_hwfn *p_hwfn,
if (rc)
DP_ERR(p_hwfn, "Failed to send wol mode, rc = %d\n", rc);
/* Store the WoL update for a future unload */
p_hwfn->cdev->wol_config = (u8)wol;
return rc;
}