summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@quicinc.com>2017-07-17 18:40:05 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-07-17 18:40:05 -0700
commit89df4df1c046450be224c717da098de6c598051f (patch)
tree74a55d509a0a74932346f269ad07d717d67c3288
parenta1dcf33ce1b2ad44d9220aa0e47eb1aaf02705fe (diff)
parent0894ea1926f3a78ef075260721bdcc4b0ce1b371 (diff)
Merge "cnss2: Send WAKE MSI base data to firmware"
-rw-r--r--drivers/net/wireless/cnss2/main.c180
-rw-r--r--drivers/net/wireless/cnss2/main.h4
-rw-r--r--drivers/net/wireless/cnss2/qmi.c6
-rw-r--r--drivers/net/wireless/cnss2/wlan_firmware_service_v01.c53
-rw-r--r--drivers/net/wireless/cnss2/wlan_firmware_service_v01.h16
5 files changed, 192 insertions, 67 deletions
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index 29bfe1f4d6ed..432960afe09a 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -37,6 +37,7 @@
#define FW_READY_TIMEOUT 20000
#define FW_ASSERT_TIMEOUT 5000
#define CNSS_EVENT_PENDING 2989
+#define WAKE_MSI_NAME "WAKE"
static struct cnss_plat_data *plat_env;
@@ -537,6 +538,24 @@ int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
}
EXPORT_SYMBOL(cnss_set_fw_log_mode);
+u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+ int ret, num_vectors;
+ u32 user_base_data, base_vector;
+
+ ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
+ WAKE_MSI_NAME, &num_vectors,
+ &user_base_data, &base_vector);
+
+ if (ret) {
+ cnss_pr_err("WAKE MSI is not valid\n");
+ return 0;
+ }
+
+ return user_base_data;
+}
+
static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@@ -573,7 +592,7 @@ static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv)
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
if (!plat_priv->driver_ops) {
- cnss_pr_err("driver_ops is NULL!");
+ cnss_pr_err("driver_ops is NULL\n");
ret = -EINVAL;
goto out;
}
@@ -587,7 +606,7 @@ static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv)
goto out;
}
clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
- } else {
+ } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
ret = plat_priv->driver_ops->probe(pci_priv->pci_dev,
pci_priv->pci_device_id);
if (ret) {
@@ -605,6 +624,25 @@ out:
return ret;
}
+static int cnss_driver_call_remove(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+ if (!plat_priv->driver_ops) {
+ cnss_pr_err("driver_ops is NULL\n");
+ return -EINVAL;
+ }
+
+ if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+ plat_priv->driver_ops->shutdown(pci_priv->pci_dev);
+ } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+ plat_priv->driver_ops->remove(pci_priv->pci_dev);
+ clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+ }
+
+ return 0;
+}
+
static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@@ -626,8 +664,11 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
} else if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) {
ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
QMI_WLFW_CALIBRATION_V01);
- } else {
+ } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
ret = cnss_driver_call_probe(plat_priv);
+ } else {
+ complete(&plat_priv->power_up_complete);
}
if (ret)
@@ -668,6 +709,10 @@ static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
return "RECOVERY";
case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
return "FORCE_FW_ASSERT";
+ case CNSS_DRIVER_EVENT_POWER_UP:
+ return "POWER_UP";
+ case CNSS_DRIVER_EVENT_POWER_DOWN:
+ return "POWER_DOWN";
case CNSS_DRIVER_EVENT_MAX:
return "EVENT_MAX";
}
@@ -746,64 +791,57 @@ out:
int cnss_power_up(struct device *dev)
{
int ret = 0;
- void *bus_priv = cnss_bus_dev_to_bus_priv(dev);
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ unsigned int timeout;
- if (!bus_priv || !plat_priv)
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
return -ENODEV;
-
- if (plat_priv->device_id != QCA6174_DEVICE_ID) {
- cnss_pr_dbg("Power up is not supported for device ID 0x%lx\n",
- plat_priv->device_id);
- return 0;
}
- ret = cnss_power_on_device(plat_priv);
- if (ret) {
- cnss_pr_err("Failed to power on device, err = %d\n", ret);
- goto err_power_on;
- }
+ cnss_pr_dbg("Powering up device\n");
- ret = cnss_resume_pci_link(bus_priv);
- if (ret) {
- cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
- goto err_resume_link;
+ ret = cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_POWER_UP,
+ true, NULL);
+ if (ret)
+ goto out;
+
+ if (plat_priv->device_id == QCA6174_DEVICE_ID)
+ goto out;
+
+ timeout = cnss_get_qmi_timeout();
+
+ reinit_completion(&plat_priv->power_up_complete);
+ ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
+ msecs_to_jiffies(timeout) << 2);
+ if (!ret) {
+ cnss_pr_err("Timeout waiting for power up to complete\n");
+ ret = -EAGAIN;
+ goto out;
}
return 0;
-err_resume_link:
- cnss_power_off_device(plat_priv);
-err_power_on:
+
+out:
return ret;
}
EXPORT_SYMBOL(cnss_power_up);
int cnss_power_down(struct device *dev)
{
- int ret = 0;
- void *bus_priv = cnss_bus_dev_to_bus_priv(dev);
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
- if (!bus_priv || !plat_priv)
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
return -ENODEV;
-
- if (plat_priv->device_id != QCA6174_DEVICE_ID) {
- cnss_pr_dbg("Power down is not supported for device ID 0x%lx\n",
- plat_priv->device_id);
- return 0;
}
- cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE);
- cnss_pci_set_monitor_wake_intr(bus_priv, false);
- cnss_pci_set_auto_suspended(bus_priv, 0);
+ cnss_pr_dbg("Powering down device\n");
- ret = cnss_suspend_pci_link(bus_priv);
- if (ret)
- cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
-
- cnss_power_off_device(plat_priv);
-
- return 0;
+ return cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_POWER_DOWN,
+ true, NULL);
}
EXPORT_SYMBOL(cnss_power_down);
@@ -1024,14 +1062,11 @@ static int cnss_qca6174_shutdown(struct cnss_plat_data *plat_priv)
if (!plat_priv->driver_ops)
return -EINVAL;
- if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
- cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE);
- plat_priv->driver_ops->remove(pci_priv->pci_dev);
- cnss_pci_set_monitor_wake_intr(pci_priv, false);
- cnss_pci_set_auto_suspended(pci_priv, 0);
- } else {
- plat_priv->driver_ops->shutdown(pci_priv->pci_dev);
- }
+ cnss_driver_call_remove(plat_priv);
+
+ cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE);
+ cnss_pci_set_monitor_wake_intr(pci_priv, false);
+ cnss_pci_set_auto_suspended(pci_priv, 0);
ret = cnss_suspend_pci_link(pci_priv);
if (ret)
@@ -1039,10 +1074,7 @@ static int cnss_qca6174_shutdown(struct cnss_plat_data *plat_priv)
cnss_power_off_device(plat_priv);
- if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
- clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
- clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
- }
+ clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
return ret;
}
@@ -1134,16 +1166,13 @@ static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv)
if (!plat_priv->driver_ops)
return -EINVAL;
- if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
- cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE);
- plat_priv->driver_ops->remove(pci_priv->pci_dev);
- cnss_pci_set_monitor_wake_intr(pci_priv, false);
- cnss_pci_set_auto_suspended(pci_priv, 0);
- } else {
- plat_priv->driver_ops->shutdown(pci_priv->pci_dev);
- }
+ cnss_driver_call_remove(plat_priv);
skip_driver_remove:
+ cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE);
+ cnss_pci_set_monitor_wake_intr(pci_priv, false);
+ cnss_pci_set_auto_suspended(pci_priv, 0);
+
cnss_pci_stop_mhi(pci_priv);
ret = cnss_suspend_pci_link(pci_priv);
@@ -1154,11 +1183,7 @@ skip_driver_remove:
clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
-
- if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
- clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
- clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
- }
+ clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
return ret;
}
@@ -1661,6 +1686,22 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
return 0;
}
+static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info;
+
+ return cnss_powerup(&subsys_info->subsys_desc);
+}
+
+static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
+{
+ struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info;
+
+ cnss_shutdown(&subsys_info->subsys_desc, false);
+
+ return 0;
+}
+
static void cnss_driver_event_work(struct work_struct *work)
{
struct cnss_plat_data *plat_priv =
@@ -1728,6 +1769,12 @@ static void cnss_driver_event_work(struct work_struct *work)
case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
ret = cnss_force_fw_assert_hdlr(plat_priv);
break;
+ case CNSS_DRIVER_EVENT_POWER_UP:
+ ret = cnss_power_up_hdlr(plat_priv);
+ break;
+ case CNSS_DRIVER_EVENT_POWER_DOWN:
+ ret = cnss_power_down_hdlr(plat_priv);
+ break;
default:
cnss_pr_err("Invalid driver event type: %d",
event->type);
@@ -2226,6 +2273,8 @@ static int cnss_probe(struct platform_device *plat_dev)
cnss_pr_err("Failed to init platform device wakeup source, err = %d\n",
ret);
+ init_completion(&plat_priv->power_up_complete);
+
cnss_pr_info("Platform driver probed successfully.\n");
return 0;
@@ -2257,6 +2306,7 @@ static int cnss_remove(struct platform_device *plat_dev)
{
struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev);
+ complete_all(&plat_priv->power_up_complete);
device_init_wakeup(&plat_dev->dev, false);
unregister_pm_notifier(&cnss_pm_notifier);
del_timer(&plat_priv->fw_boot_timer);
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
index e3a8d0cccd52..a2d9a02bde20 100644
--- a/drivers/net/wireless/cnss2/main.h
+++ b/drivers/net/wireless/cnss2/main.h
@@ -126,6 +126,8 @@ enum cnss_driver_event_type {
CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
CNSS_DRIVER_EVENT_RECOVERY,
CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
+ CNSS_DRIVER_EVENT_POWER_UP,
+ CNSS_DRIVER_EVENT_POWER_DOWN,
CNSS_DRIVER_EVENT_MAX,
};
@@ -201,6 +203,7 @@ struct cnss_plat_data {
struct dentry *root_dentry;
atomic_t pm_count;
struct timer_list fw_boot_timer;
+ struct completion power_up_complete;
};
void *cnss_bus_dev_to_bus_priv(struct device *dev);
@@ -217,5 +220,6 @@ void cnss_unregister_subsys(struct cnss_plat_data *plat_priv);
int cnss_register_ramdump(struct cnss_plat_data *plat_priv);
void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv);
void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv);
+u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv);
#endif /* _CNSS_MAIN_H */
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index db55d3350eb5..99163d51a497 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -140,6 +140,12 @@ static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv)
cnss_pr_dbg("daemon_support is %d\n", req.daemon_support);
+ req.wake_msi = cnss_get_wake_msi(plat_priv);
+ if (req.wake_msi) {
+ cnss_pr_dbg("WAKE MSI base data is %d\n", req.wake_msi);
+ req.wake_msi_valid = 1;
+ }
+
req_desc.max_msg_len = WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN;
req_desc.msg_id = QMI_WLFW_HOST_CAP_REQ_V01;
req_desc.ei_array = wlfw_host_cap_req_msg_v01_ei;
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
index 84a4707e9cc3..7d6a771bc0d5 100644
--- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
@@ -1097,6 +1097,24 @@ struct elem_info wlfw_cal_report_req_msg_v01_ei[] = {
meta_data),
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ xo_cal_data_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ xo_cal_data),
+ },
+ {
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.is_array = QMI_COMMON_TLV_TYPE,
@@ -1828,6 +1846,24 @@ struct elem_info wlfw_host_cap_req_msg_v01_ei[] = {
daemon_support),
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ wake_msi_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ wake_msi),
+ },
+ {
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.is_array = QMI_COMMON_TLV_TYPE,
@@ -2166,3 +2202,20 @@ struct elem_info wlfw_m3_info_resp_msg_v01_ei[] = {
.is_array = QMI_COMMON_TLV_TYPE,
},
};
+
+struct elem_info wlfw_xo_cal_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_xo_cal_ind_msg_v01,
+ xo_cal_data),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
index cb8225a7c3c3..a3081433cc2b 100644
--- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
@@ -31,6 +31,7 @@
#define QMI_WLFW_M3_INFO_RESP_V01 0x003C
#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029
#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027
+#define QMI_WLFW_XO_CAL_IND_V01 0x003D
#define QMI_WLFW_INI_RESP_V01 0x002F
#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026
#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033
@@ -339,9 +340,11 @@ extern struct elem_info wlfw_bdf_download_resp_msg_v01_ei[];
struct wlfw_cal_report_req_msg_v01 {
u32 meta_data_len;
enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01];
+ u8 xo_cal_data_valid;
+ u8 xo_cal_data;
};
-#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 24
+#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 28
extern struct elem_info wlfw_cal_report_req_msg_v01_ei[];
struct wlfw_cal_report_resp_msg_v01 {
@@ -532,9 +535,11 @@ extern struct elem_info wlfw_mac_addr_resp_msg_v01_ei[];
struct wlfw_host_cap_req_msg_v01 {
u8 daemon_support_valid;
u8 daemon_support;
+ u8 wake_msi_valid;
+ u32 wake_msi;
};
-#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 4
+#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 11
extern struct elem_info wlfw_host_cap_req_msg_v01_ei[];
struct wlfw_host_cap_resp_msg_v01 {
@@ -642,4 +647,11 @@ struct wlfw_m3_info_resp_msg_v01 {
#define WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
extern struct elem_info wlfw_m3_info_resp_msg_v01_ei[];
+struct wlfw_xo_cal_ind_msg_v01 {
+ u8 xo_cal_data;
+};
+
+#define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4
+extern struct elem_info wlfw_xo_cal_ind_msg_v01_ei[];
+
#endif