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:
parent
7a4b21b7d1
commit
14d39648cb
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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, ¶m);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -193,6 +193,8 @@ struct qede_dev {
|
|||
u16 vxlan_dst_port;
|
||||
u16 geneve_dst_port;
|
||||
|
||||
bool wol_enabled;
|
||||
|
||||
struct qede_rdma_dev rdma_info;
|
||||
};
|
||||
|
||||
|
|
|
@ -483,6 +483,45 @@ static void qede_get_drvinfo(struct net_device *ndev,
|
|||
strlcpy(info->bus_info, pci_name(edev->pdev), sizeof(info->bus_info));
|
||||
}
|
||||
|
||||
static void qede_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct qede_dev *edev = netdev_priv(ndev);
|
||||
|
||||
if (edev->dev_info.common.wol_support) {
|
||||
wol->supported = WAKE_MAGIC;
|
||||
wol->wolopts = edev->wol_enabled ? WAKE_MAGIC : 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int qede_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct qede_dev *edev = netdev_priv(ndev);
|
||||
bool wol_requested;
|
||||
int rc;
|
||||
|
||||
if (wol->wolopts & ~WAKE_MAGIC) {
|
||||
DP_INFO(edev,
|
||||
"Can't support WoL options other than magic-packet\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wol_requested = !!(wol->wolopts & WAKE_MAGIC);
|
||||
if (wol_requested == edev->wol_enabled)
|
||||
return 0;
|
||||
|
||||
/* Need to actually change configuration */
|
||||
if (!edev->dev_info.common.wol_support) {
|
||||
DP_INFO(edev, "Device doesn't support WoL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = edev->ops->common->update_wol(edev->cdev, wol_requested);
|
||||
if (!rc)
|
||||
edev->wol_enabled = wol_requested;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static u32 qede_get_msglevel(struct net_device *ndev)
|
||||
{
|
||||
struct qede_dev *edev = netdev_priv(ndev);
|
||||
|
@ -1449,6 +1488,8 @@ static const struct ethtool_ops qede_ethtool_ops = {
|
|||
.get_drvinfo = qede_get_drvinfo,
|
||||
.get_regs_len = qede_get_regs_len,
|
||||
.get_regs = qede_get_regs,
|
||||
.get_wol = qede_get_wol,
|
||||
.set_wol = qede_set_wol,
|
||||
.get_msglevel = qede_get_msglevel,
|
||||
.set_msglevel = qede_set_msglevel,
|
||||
.nway_reset = qede_nway_reset,
|
||||
|
|
|
@ -95,6 +95,7 @@ static int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id);
|
|||
#define TX_TIMEOUT (5 * HZ)
|
||||
|
||||
static void qede_remove(struct pci_dev *pdev);
|
||||
static void qede_shutdown(struct pci_dev *pdev);
|
||||
static int qede_alloc_rx_buffer(struct qede_dev *edev,
|
||||
struct qede_rx_queue *rxq);
|
||||
static void qede_link_update(void *dev, struct qed_link_output *link);
|
||||
|
@ -166,6 +167,7 @@ static struct pci_driver qede_pci_driver = {
|
|||
.id_table = qede_pci_tbl,
|
||||
.probe = qede_probe,
|
||||
.remove = qede_remove,
|
||||
.shutdown = qede_shutdown,
|
||||
#ifdef CONFIG_QED_SRIOV
|
||||
.sriov_configure = qede_sriov_configure,
|
||||
#endif
|
||||
|
@ -2705,6 +2707,8 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode)
|
|||
|
||||
/* Use global ops since we've freed edev */
|
||||
qed_ops->common->slowpath_stop(cdev);
|
||||
if (system_state == SYSTEM_POWER_OFF)
|
||||
return;
|
||||
qed_ops->common->remove(cdev);
|
||||
|
||||
dev_info(&pdev->dev, "Ending qede_remove successfully\n");
|
||||
|
@ -2715,6 +2719,11 @@ static void qede_remove(struct pci_dev *pdev)
|
|||
__qede_remove(pdev, QEDE_REMOVE_NORMAL);
|
||||
}
|
||||
|
||||
static void qede_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
__qede_remove(pdev, QEDE_REMOVE_NORMAL);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* START OF LOAD / UNLOAD
|
||||
* -------------------------------------------------------------------------
|
||||
|
|
|
@ -268,6 +268,8 @@ struct qed_dev_info {
|
|||
bool tx_switching;
|
||||
bool rdma_supported;
|
||||
u16 mtu;
|
||||
|
||||
bool wol_support;
|
||||
};
|
||||
|
||||
enum qed_sb_type {
|
||||
|
@ -591,6 +593,14 @@ struct qed_common_ops {
|
|||
*
|
||||
*/
|
||||
int (*update_mtu)(struct qed_dev *cdev, u16 mtu);
|
||||
|
||||
/**
|
||||
* @brief update_wol - update of changes in the WoL configuration
|
||||
*
|
||||
* @param cdev
|
||||
* @param enabled - true iff WoL should be enabled.
|
||||
*/
|
||||
int (*update_wol) (struct qed_dev *cdev, bool enabled);
|
||||
};
|
||||
|
||||
#define MASK_FIELD(_name, _value) \
|
||||
|
|
Loading…
Reference in New Issue