diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index ab24e46006959cf3fd8a7d1ceaae25603fe18105..cabe1b8927220fb0d8f60da44cd9790c2f166f37 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -52,6 +52,10 @@ #define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */ #define OC_DEVICE_ID4 0xe228 /* Device id for VF in Lancer */ #define OC_DEVICE_ID5 0x720 /* Device Id for Skyhawk cards */ +#define OC_SUBSYS_DEVICE_ID1 0xE602 +#define OC_SUBSYS_DEVICE_ID2 0xE642 +#define OC_SUBSYS_DEVICE_ID3 0xE612 +#define OC_SUBSYS_DEVICE_ID4 0xE652 static inline char *nic_name(struct pci_dev *pdev) { @@ -365,7 +369,6 @@ struct be_adapter { bool fw_timeout; u32 port_num; bool promiscuous; - bool wol; u32 function_mode; u32 function_caps; u32 rx_fc; /* Rx flow control */ @@ -386,6 +389,8 @@ struct be_adapter { u32 sli_family; u8 hba_port_num; u16 pvid; + u8 wol_cap; + bool wol; }; #define be_physfn(adapter) (!adapter->is_virtfn) @@ -549,9 +554,28 @@ static inline bool be_error(struct be_adapter *adapter) return adapter->eeh_err || adapter->ue_detected || adapter->fw_timeout; } +static inline bool be_is_wol_excluded(struct be_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + if (!be_physfn(adapter)) + return true; + + switch (pdev->subsystem_device) { + case OC_SUBSYS_DEVICE_ID1: + case OC_SUBSYS_DEVICE_ID2: + case OC_SUBSYS_DEVICE_ID3: + case OC_SUBSYS_DEVICE_ID4: + return true; + default: + return false; + } +} + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); extern void be_link_status_update(struct be_adapter *adapter, u8 link_status); extern void be_parse_stats(struct be_adapter *adapter); extern int be_load_fw(struct be_adapter *adapter, u8 *func); +extern bool be_is_wol_supported(struct be_adapter *adapter); #endif /* BE_H */ diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 398fb5ca0fe21f2554b72e933ff20774a7b9ee26..d72c2b46963c82d5e5e8cebb43dfe925843c22f3 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2418,3 +2418,58 @@ int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, spin_unlock_bh(&adapter->mcc_lock); return status; } + +int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_acpi_wol_magic_config_v1 *req; + int status; + int payload_len = sizeof(*req); + struct be_dma_mem cmd; + + memset(&cmd, 0, sizeof(struct be_dma_mem)); + cmd.size = sizeof(struct be_cmd_resp_acpi_wol_magic_config_v1); + cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, + &cmd.dma); + if (!cmd.va) { + dev_err(&adapter->pdev->dev, + "Memory allocation failure\n"); + return -ENOMEM; + } + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = cmd.va; + + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, + OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, + payload_len, wrb, &cmd); + + req->hdr.version = 1; + req->query_options = BE_GET_WOL_CAP; + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_acpi_wol_magic_config_v1 *resp; + resp = (struct be_cmd_resp_acpi_wol_magic_config_v1 *) cmd.va; + + /* the command could succeed misleadingly on old f/w + * which is not aware of the V1 version. fake an error. */ + if (resp->hdr.response_length < payload_len) { + status = -1; + goto err; + } + adapter->wol_cap = resp->wol_settings; + } +err: + mutex_unlock(&adapter->mbox_lock); + pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); + return status; +} diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 687c42071411c94dee96a0227c3dcba7db62fdd5..345d49eeadc83580848563f604921539da6b01e1 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1206,6 +1206,33 @@ struct be_cmd_req_acpi_wol_magic_config{ u8 rsvd2[2]; } __packed; +struct be_cmd_req_acpi_wol_magic_config_v1 { + struct be_cmd_req_hdr hdr; + u8 rsvd0[2]; + u8 query_options; + u8 rsvd1[5]; + u32 rsvd2[288]; + u8 magic_mac[6]; + u8 rsvd3[22]; +} __packed; + +struct be_cmd_resp_acpi_wol_magic_config_v1 { + struct be_cmd_resp_hdr hdr; + u8 rsvd0[2]; + u8 wol_settings; + u8 rsvd1[5]; + u32 rsvd2[295]; +} __packed; + +#define BE_GET_WOL_CAP 2 + +#define BE_WOL_CAP 0x1 +#define BE_PME_D0_CAP 0x8 +#define BE_PME_D1_CAP 0x10 +#define BE_PME_D2_CAP 0x20 +#define BE_PME_D3HOT_CAP 0x40 +#define BE_PME_D3COLD_CAP 0x80 + /********************** LoopBack test *********************/ struct be_cmd_req_loopback_test { struct be_cmd_req_hdr hdr; @@ -1590,4 +1617,5 @@ extern int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain, bool *pmac_id_active, u32 *pmac_id, u8 *mac); extern int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, u8 mac_count, u32 domain); +extern int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter); diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 30ce17806916703fc4c90b47f0db0df998d2bfda..c1ff73cb0e6283fec963df11eb1676c282bbf3a8 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -600,26 +600,16 @@ be_set_phys_id(struct net_device *netdev, return 0; } -static bool -be_is_wol_supported(struct be_adapter *adapter) -{ - if (!be_physfn(adapter)) - return false; - else - return true; -} static void be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct be_adapter *adapter = netdev_priv(netdev); - if (be_is_wol_supported(adapter)) - wol->supported = WAKE_MAGIC; - - if (adapter->wol) - wol->wolopts = WAKE_MAGIC; - else + if (be_is_wol_supported(adapter)) { + wol->supported |= WAKE_MAGIC; + wol->wolopts |= WAKE_MAGIC; + } else wol->wolopts = 0; memset(&wol->sopass, 0, sizeof(wol->sopass)); } @@ -630,9 +620,14 @@ be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) struct be_adapter *adapter = netdev_priv(netdev); if (wol->wolopts & ~WAKE_MAGIC) - return -EINVAL; + return -EOPNOTSUPP; + + if (!be_is_wol_supported(adapter)) { + dev_warn(&adapter->pdev->dev, "WOL not supported\n"); + return -EOPNOTSUPP; + } - if ((wol->wolopts & WAKE_MAGIC) && be_is_wol_supported(adapter)) + if (wol->wolopts & WAKE_MAGIC) adapter->wol = true; else adapter->wol = false; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index e3822788f532f916434e4f1326cf63c290bf8b10..050e3ebd4fb30b424453aef541b20b32bada4769 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3244,6 +3244,12 @@ static void __devexit be_remove(struct pci_dev *pdev) free_netdev(adapter->netdev); } +bool be_is_wol_supported(struct be_adapter *adapter) +{ + return ((adapter->wol_cap & BE_WOL_CAP) && + !be_is_wol_excluded(adapter)) ? true : false; +} + static int be_get_config(struct be_adapter *adapter) { int status; @@ -3262,6 +3268,17 @@ static int be_get_config(struct be_adapter *adapter) if (status) return status; + status = be_cmd_get_acpi_wol_cap(adapter); + if (status) { + /* in case of a failure to get wol capabillities + * check the exclusion list to determine WOL capability */ + if (!be_is_wol_excluded(adapter)) + adapter->wol_cap |= BE_WOL_CAP; + } + + if (be_is_wol_supported(adapter)) + adapter->wol = true; + return 0; }