Merge "cnss2: Refactor PCIe bus related code"

This commit is contained in:
Linux Build Service Account 2018-07-14 00:36:46 -07:00 committed by Gerrit - the friendly Code Review server
commit 741e5a2f47
6 changed files with 799 additions and 552 deletions

View file

@ -41,6 +41,38 @@ enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id)
}
}
void *cnss_bus_dev_to_bus_priv(struct device *dev)
{
if (!dev)
return NULL;
switch (cnss_get_dev_bus_type(dev)) {
case CNSS_BUS_PCI:
return cnss_get_pci_priv(to_pci_dev(dev));
default:
return NULL;
}
}
struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
{
void *bus_priv;
if (!dev)
return cnss_get_plat_priv(NULL);
bus_priv = cnss_bus_dev_to_bus_priv(dev);
if (!bus_priv)
return NULL;
switch (cnss_get_dev_bus_type(dev)) {
case CNSS_BUS_PCI:
return cnss_pci_priv_to_plat_priv(bus_priv);
default:
return NULL;
}
}
int cnss_bus_init(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
@ -150,11 +182,19 @@ void cnss_bus_fw_boot_timeout_hdlr(unsigned long data)
void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv)
{
int ret;
if (!plat_priv)
return;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
ret = cnss_pci_set_mhi_state(plat_priv->bus_priv,
CNSS_MHI_RDDM);
if (ret) {
cnss_pr_err("Failed to complete RDDM, err = %d\n", ret);
break;
}
return cnss_pci_collect_dump_info(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
@ -162,3 +202,155 @@ void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv)
return;
}
}
int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_call_driver_probe(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_call_driver_remove(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_dev_powerup(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_dev_shutdown(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_dev_crash_shutdown(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_dev_crash_shutdown(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_dev_ramdump(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_dev_ramdump(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_register_driver_hdlr(plat_priv->bus_priv, data);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_unregister_driver_hdlr(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
int modem_current_status)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_call_driver_modem_status(plat_priv->bus_priv,
modem_current_status);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_recovery_update_status(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_recovery_update_status(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}

View file

@ -27,6 +27,8 @@
enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev);
enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id);
void *cnss_bus_dev_to_bus_priv(struct device *dev);
struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev);
int cnss_bus_init(struct cnss_plat_data *plat_priv);
void cnss_bus_deinit(struct cnss_plat_data *plat_priv);
int cnss_bus_load_m3(struct cnss_plat_data *plat_priv);
@ -35,5 +37,15 @@ u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv);
int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv);
void cnss_bus_fw_boot_timeout_hdlr(unsigned long data);
void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv);
int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv);
int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv);
int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv);
int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv);
int cnss_bus_dev_crash_shutdown(struct cnss_plat_data *plat_priv);
int cnss_bus_dev_ramdump(struct cnss_plat_data *plat_priv);
int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data);
int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv);
int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
int modem_current_status);
int cnss_bus_recovery_update_status(struct cnss_plat_data *plat_priv);
#endif /* _CNSS_BUS_H */

View file

@ -25,7 +25,6 @@
#include "main.h"
#include "bus.h"
#include "debug.h"
#include "pci.h"
#define CNSS_DUMP_FORMAT_VER 0x11
#define CNSS_DUMP_FORMAT_VER_V2 0x22
@ -55,13 +54,6 @@ module_param(enable_waltest, bool, 0600);
MODULE_PARM_DESC(enable_waltest, "Enable to handle firmware waltest");
#endif
enum cnss_debug_quirks {
LINK_DOWN_SELF_RECOVERY,
SKIP_DEVICE_BOOT,
USE_CORE_ONLY_FW,
SKIP_RECOVERY,
};
unsigned long quirks;
#ifdef CONFIG_CNSS2_DEBUG
module_param(quirks, ulong, 0600);
@ -93,44 +85,11 @@ static void cnss_set_plat_priv(struct platform_device *plat_dev,
plat_env = plat_priv;
}
static struct cnss_plat_data *cnss_get_plat_priv(struct platform_device
*plat_dev)
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev)
{
return plat_env;
}
void *cnss_bus_dev_to_bus_priv(struct device *dev)
{
if (!dev)
return NULL;
switch (cnss_get_dev_bus_type(dev)) {
case CNSS_BUS_PCI:
return cnss_get_pci_priv(to_pci_dev(dev));
default:
return NULL;
}
}
struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
{
void *bus_priv;
if (!dev)
return cnss_get_plat_priv(NULL);
bus_priv = cnss_bus_dev_to_bus_priv(dev);
if (!bus_priv)
return NULL;
switch (cnss_get_dev_bus_type(dev)) {
case CNSS_BUS_PCI:
return cnss_pci_priv_to_plat_priv(bus_priv);
default:
return NULL;
}
}
static int cnss_pm_notify(struct notifier_block *b,
unsigned long event, void *p)
{
@ -475,6 +434,16 @@ int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
}
EXPORT_SYMBOL(cnss_set_fw_log_mode);
unsigned long *cnss_get_debug_quirks(void)
{
return &quirks;
}
bool *cnss_get_qmi_bypass(void)
{
return &qmi_bypass;
}
static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@ -505,79 +474,6 @@ out:
return ret;
}
static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
cnss_pr_dbg("Skip driver probe\n");
goto out;
}
if (!plat_priv->driver_ops) {
cnss_pr_err("driver_ops is NULL\n");
ret = -EINVAL;
goto out;
}
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
ret = plat_priv->driver_ops->reinit(pci_priv->pci_dev,
pci_priv->pci_device_id);
if (ret) {
cnss_pr_err("Failed to reinit host driver, err = %d\n",
ret);
goto out;
}
clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
} 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) {
cnss_pr_err("Failed to probe host driver, err = %d\n",
ret);
goto out;
}
clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
}
return 0;
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 (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) ||
test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
cnss_pr_dbg("Skip driver remove\n");
return 0;
}
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) &&
test_bit(CNSS_DRIVER_PROBED, &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;
@ -601,7 +497,7 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
QMI_WLFW_CALIBRATION_V01);
} 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);
ret = cnss_bus_call_driver_probe(plat_priv);
} else {
complete(&plat_priv->power_up_complete);
}
@ -614,9 +510,7 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
return 0;
shutdown:
cnss_pci_stop_mhi(plat_priv->bus_priv);
cnss_suspend_pci_link(plat_priv->bus_priv);
cnss_power_off_device(plat_priv);
cnss_bus_dev_shutdown(plat_priv);
clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
@ -788,44 +682,6 @@ int cnss_power_down(struct device *dev)
}
EXPORT_SYMBOL(cnss_power_down);
int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
{
int ret = 0;
struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL!\n");
return -ENODEV;
}
if (plat_priv->driver_ops) {
cnss_pr_err("Driver has already registered!\n");
return -EEXIST;
}
ret = cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_REGISTER_DRIVER,
CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
driver_ops);
return ret;
}
EXPORT_SYMBOL(cnss_wlan_register_driver);
void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
{
struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL!\n");
return;
}
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
}
EXPORT_SYMBOL(cnss_wlan_unregister_driver);
static int cnss_get_resources(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@ -857,13 +713,11 @@ static int cnss_modem_notifier_nb(struct notifier_block *nb,
{
struct cnss_plat_data *plat_priv =
container_of(nb, struct cnss_plat_data, modem_nb);
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
struct cnss_esoc_info *esoc_info;
struct cnss_wlan_driver *driver_ops;
cnss_pr_dbg("Modem notifier: event %lu\n", code);
if (!pci_priv)
if (!plat_priv)
return NOTIFY_DONE;
esoc_info = &plat_priv->esoc_info;
@ -875,13 +729,10 @@ static int cnss_modem_notifier_nb(struct notifier_block *nb,
else
return NOTIFY_DONE;
driver_ops = plat_priv->driver_ops;
if (!driver_ops || !driver_ops->modem_status)
if (!cnss_bus_call_driver_modem_status(plat_priv,
esoc_info->modem_current_status))
return NOTIFY_DONE;
driver_ops->modem_status(pci_priv->pci_dev,
esoc_info->modem_current_status);
return NOTIFY_OK;
}
@ -955,246 +806,6 @@ static void cnss_unregister_esoc(struct cnss_plat_data *plat_priv)
devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
}
static int cnss_qca6174_powerup(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL!\n");
return -ENODEV;
}
ret = cnss_power_on_device(plat_priv);
if (ret) {
cnss_pr_err("Failed to power on device, err = %d\n", ret);
goto out;
}
ret = cnss_resume_pci_link(pci_priv);
if (ret) {
cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
goto power_off;
}
ret = cnss_driver_call_probe(plat_priv);
if (ret)
goto suspend_link;
return 0;
suspend_link:
cnss_suspend_pci_link(pci_priv);
power_off:
cnss_power_off_device(plat_priv);
out:
return ret;
}
static int cnss_qca6174_shutdown(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
if (!pci_priv)
return -ENODEV;
cnss_pm_request_resume(pci_priv);
cnss_driver_call_remove(plat_priv);
cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
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)
cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
cnss_power_off_device(plat_priv);
clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
return ret;
}
static void cnss_qca6174_crash_shutdown(struct cnss_plat_data *plat_priv)
{
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
if (!plat_priv->driver_ops)
return;
plat_priv->driver_ops->crash_shutdown(pci_priv->pci_dev);
}
static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
unsigned int timeout;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL!\n");
return -ENODEV;
}
if (plat_priv->ramdump_info_v2.dump_data_valid ||
test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
cnss_pci_clear_dump_info(pci_priv);
}
ret = cnss_power_on_device(plat_priv);
if (ret) {
cnss_pr_err("Failed to power on device, err = %d\n", ret);
goto out;
}
ret = cnss_resume_pci_link(pci_priv);
if (ret) {
cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
goto power_off;
}
timeout = cnss_get_qmi_timeout();
ret = cnss_pci_start_mhi(pci_priv);
if (ret) {
cnss_pr_err("Failed to start MHI, err = %d\n", ret);
if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
!pci_priv->pci_link_down_ind && timeout)
mod_timer(&plat_priv->fw_boot_timer,
jiffies + msecs_to_jiffies(timeout >> 1));
return 0;
}
if (test_bit(USE_CORE_ONLY_FW, &quirks)) {
clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
return 0;
}
cnss_set_pin_connect_status(plat_priv);
if (qmi_bypass) {
ret = cnss_driver_call_probe(plat_priv);
if (ret)
goto stop_mhi;
} else if (timeout) {
mod_timer(&plat_priv->fw_boot_timer,
jiffies + msecs_to_jiffies(timeout << 1));
}
return 0;
stop_mhi:
cnss_pci_stop_mhi(pci_priv);
cnss_suspend_pci_link(pci_priv);
power_off:
cnss_power_off_device(plat_priv);
out:
return ret;
}
static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
if (!pci_priv)
return -ENODEV;
cnss_pm_request_resume(pci_priv);
cnss_driver_call_remove(plat_priv);
cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
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);
if (ret)
cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
cnss_power_off_device(plat_priv);
clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
return ret;
}
static void cnss_qca6290_crash_shutdown(struct cnss_plat_data *plat_priv)
{
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
int ret = 0;
cnss_pr_dbg("Crash shutdown with driver_state 0x%lx\n",
plat_priv->driver_state);
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
cnss_pr_dbg("Ignore crash shutdown\n");
return;
}
ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM_KERNEL_PANIC);
if (ret) {
cnss_pr_err("Fail to complete RDDM, err = %d\n", ret);
return;
}
cnss_pci_collect_dump_info(pci_priv);
}
static int cnss_powerup(struct cnss_plat_data *plat_priv)
{
int ret;
switch (plat_priv->device_id) {
case QCA6174_DEVICE_ID:
ret = cnss_qca6174_powerup(plat_priv);
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
ret = cnss_qca6290_powerup(plat_priv);
break;
default:
cnss_pr_err("Unknown device_id found: 0x%lx\n",
plat_priv->device_id);
ret = -ENODEV;
}
return ret;
}
static int cnss_shutdown(struct cnss_plat_data *plat_priv)
{
int ret;
switch (plat_priv->device_id) {
case QCA6174_DEVICE_ID:
ret = cnss_qca6174_shutdown(plat_priv);
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
ret = cnss_qca6290_shutdown(plat_priv);
break;
default:
cnss_pr_err("Unknown device_id found: 0x%lx\n",
plat_priv->device_id);
ret = -ENODEV;
}
return ret;
}
static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
{
struct cnss_plat_data *plat_priv;
@ -1215,7 +826,7 @@ static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
return 0;
}
return cnss_powerup(plat_priv);
return cnss_bus_dev_powerup(plat_priv);
}
static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
@ -1239,68 +850,12 @@ static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
return 0;
}
return cnss_shutdown(plat_priv);
}
static int cnss_qca6290_ramdump(struct cnss_plat_data *plat_priv)
{
struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
struct cnss_dump_data *dump_data = &info_v2->dump_data;
struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
struct ramdump_segment *ramdump_segs, *s;
int i, ret = 0;
if (!info_v2->dump_data_valid ||
dump_data->nentries == 0)
return 0;
ramdump_segs = kcalloc(dump_data->nentries,
sizeof(*ramdump_segs),
GFP_KERNEL);
if (!ramdump_segs)
return -ENOMEM;
s = ramdump_segs;
for (i = 0; i < dump_data->nentries; i++) {
s->address = dump_seg->address;
s->v_address = dump_seg->v_address;
s->size = dump_seg->size;
s++;
dump_seg++;
}
ret = do_elf_ramdump(info_v2->ramdump_dev, ramdump_segs,
dump_data->nentries);
kfree(ramdump_segs);
cnss_pci_set_mhi_state(plat_priv->bus_priv, CNSS_MHI_DEINIT);
cnss_pci_clear_dump_info(plat_priv->bus_priv);
return ret;
}
static int cnss_qca6174_ramdump(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct cnss_ramdump_info *ramdump_info;
struct ramdump_segment segment;
ramdump_info = &plat_priv->ramdump_info;
if (!ramdump_info->ramdump_size)
return -EINVAL;
memset(&segment, 0, sizeof(segment));
segment.v_address = ramdump_info->ramdump_va;
segment.size = ramdump_info->ramdump_size;
ret = do_ramdump(ramdump_info->ramdump_dev, &segment, 1);
return ret;
return cnss_bus_dev_shutdown(plat_priv);
}
static int cnss_subsys_ramdump(int enable,
const struct subsys_desc *subsys_desc)
{
int ret = 0;
struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
if (!plat_priv) {
@ -1311,21 +866,7 @@ static int cnss_subsys_ramdump(int enable,
if (!enable)
return 0;
switch (plat_priv->device_id) {
case QCA6174_DEVICE_ID:
ret = cnss_qca6174_ramdump(plat_priv);
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
ret = cnss_qca6290_ramdump(plat_priv);
break;
default:
cnss_pr_err("Unknown device_id found: 0x%lx\n",
plat_priv->device_id);
ret = -ENODEV;
}
return ret;
return cnss_bus_dev_ramdump(plat_priv);
}
void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
@ -1368,19 +909,7 @@ static void cnss_subsys_crash_shutdown(const struct subsys_desc *subsys_desc)
cnss_pr_err("plat_priv is NULL!\n");
return;
}
switch (plat_priv->device_id) {
case QCA6174_DEVICE_ID:
cnss_qca6174_crash_shutdown(plat_priv);
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
cnss_qca6290_crash_shutdown(plat_priv);
break;
default:
cnss_pr_err("Unknown device_id found: 0x%lx\n",
plat_priv->device_id);
}
cnss_bus_dev_crash_shutdown(plat_priv);
}
static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
@ -1402,20 +931,15 @@ static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
enum cnss_recovery_reason reason)
{
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
struct cnss_subsys_info *subsys_info =
&plat_priv->subsys_info;
int ret = 0;
plat_priv->recovery_count++;
if (plat_priv->device_id == QCA6174_DEVICE_ID)
goto self_recovery;
if (plat_priv->driver_ops &&
test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state))
plat_priv->driver_ops->update_status(pci_priv->pci_dev,
CNSS_RECOVERY);
cnss_bus_recovery_update_status(plat_priv);
if (test_bit(SKIP_RECOVERY, &quirks)) {
cnss_pr_dbg("Skip device recovery\n");
@ -1429,11 +953,6 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
break;
case CNSS_REASON_RDDM:
clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM);
if (ret) {
cnss_pr_err("Failed to complete RDDM, err = %d\n", ret);
break;
}
cnss_bus_collect_dump_info(plat_priv);
break;
case CNSS_REASON_DEFAULT:
@ -1454,8 +973,8 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
return 0;
self_recovery:
cnss_shutdown(plat_priv);
cnss_powerup(plat_priv);
cnss_bus_dev_shutdown(plat_priv);
cnss_bus_dev_powerup(plat_priv);
return 0;
}
@ -1568,38 +1087,12 @@ int cnss_force_fw_assert(struct device *dev)
}
EXPORT_SYMBOL(cnss_force_fw_assert);
static int cnss_register_driver_hdlr(struct cnss_plat_data *plat_priv,
void *data)
{
int ret = 0;
set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
plat_priv->driver_ops = data;
ret = cnss_powerup(plat_priv);
if (ret) {
clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
plat_priv->driver_ops = NULL;
}
return ret;
}
static int cnss_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
{
set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
cnss_shutdown(plat_priv);
plat_priv->driver_ops = NULL;
return 0;
}
static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
set_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
ret = cnss_powerup(plat_priv);
ret = cnss_bus_dev_powerup(plat_priv);
if (ret)
clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
@ -1610,7 +1103,7 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
{
plat_priv->cal_done = true;
cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01);
cnss_shutdown(plat_priv);
cnss_bus_dev_shutdown(plat_priv);
clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
return 0;
@ -1618,12 +1111,12 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
{
return cnss_powerup(plat_priv);
return cnss_bus_dev_powerup(plat_priv);
}
static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
{
cnss_shutdown(plat_priv);
cnss_bus_dev_shutdown(plat_priv);
return 0;
}
@ -1682,11 +1175,11 @@ static void cnss_driver_event_work(struct work_struct *work)
ret = cnss_cold_boot_cal_done_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
ret = cnss_register_driver_hdlr(plat_priv,
event->data);
ret = cnss_bus_register_driver_hdlr(plat_priv,
event->data);
break;
case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
ret = cnss_unregister_driver_hdlr(plat_priv);
ret = cnss_bus_unregister_driver_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_RECOVERY:
ret = cnss_driver_recovery_hdlr(plat_priv,

View file

@ -164,6 +164,13 @@ struct cnss_pin_connect_result {
u32 host_pin_result;
};
enum cnss_debug_quirks {
LINK_DOWN_SELF_RECOVERY,
SKIP_DEVICE_BOOT,
USE_CORE_ONLY_FW,
SKIP_RECOVERY,
};
struct cnss_plat_data {
struct platform_device *plat_dev;
void *bus_priv;
@ -179,7 +186,6 @@ struct cnss_plat_data {
struct cnss_platform_cap cap;
struct pm_qos_request qos_request;
unsigned long device_id;
struct cnss_wlan_driver *driver_ops;
enum cnss_driver_status driver_status;
u32 recovery_count;
unsigned long driver_state;
@ -210,8 +216,8 @@ struct cnss_plat_data {
bool cal_done;
};
void *cnss_bus_dev_to_bus_priv(struct device *dev);
struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev);
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
unsigned long *cnss_get_debug_quirks(void);
int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
enum cnss_driver_event_type type,
u32 flags, void *data);
@ -238,5 +244,5 @@ 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);
bool *cnss_get_qmi_bypass(void);
#endif /* _CNSS_MAIN_H */

View file

@ -17,6 +17,7 @@
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/memblock.h>
#include <soc/qcom/ramdump.h>
#include "main.h"
#include "bus.h"
@ -234,6 +235,532 @@ static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up)
}
#endif /* CONFIG_PCI_MSM */
int cnss_pci_recovery_update_status(struct cnss_pci_data *pci_priv)
{
struct cnss_plat_data *plat_priv;
plat_priv = pci_priv->plat_priv;
if (pci_priv->driver_ops &&
test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state))
pci_priv->driver_ops->update_status(pci_priv->pci_dev,
CNSS_RECOVERY);
return 0;
}
int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv)
{
int ret = 0;
struct cnss_plat_data *plat_priv;
if (!pci_priv)
return -ENODEV;
plat_priv = pci_priv->plat_priv;
if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
cnss_pr_dbg("Skip driver probe\n");
goto out;
}
if (!pci_priv->driver_ops) {
cnss_pr_err("driver_ops is NULL\n");
ret = -EINVAL;
goto out;
}
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
ret = pci_priv->driver_ops->reinit(pci_priv->pci_dev,
pci_priv->pci_device_id);
if (ret) {
cnss_pr_err("Failed to reinit host driver, err = %d\n",
ret);
goto out;
}
clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
} else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
ret = pci_priv->driver_ops->probe(pci_priv->pci_dev,
pci_priv->pci_device_id);
if (ret) {
cnss_pr_err("Failed to probe host driver, err = %d\n",
ret);
goto out;
}
clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
}
return 0;
out:
return ret;
}
int cnss_pci_call_driver_remove(struct cnss_pci_data *pci_priv)
{
struct cnss_plat_data *plat_priv;
if (!pci_priv)
return -ENODEV;
plat_priv = pci_priv->plat_priv;
if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) ||
test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
cnss_pr_dbg("Skip driver remove\n");
return 0;
}
if (!pci_priv->driver_ops) {
cnss_pr_err("driver_ops is NULL\n");
return -EINVAL;
}
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
pci_priv->driver_ops->shutdown(pci_priv->pci_dev);
} else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
pci_priv->driver_ops->remove(pci_priv->pci_dev);
clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
}
return 0;
}
int cnss_pci_call_driver_modem_status(struct cnss_pci_data *pci_priv,
int modem_current_status)
{
struct cnss_wlan_driver *driver_ops;
if (!pci_priv)
return -ENODEV;
driver_ops = pci_priv->driver_ops;
if (!driver_ops || !driver_ops->modem_status)
return -EINVAL;
driver_ops->modem_status(pci_priv->pci_dev, modem_current_status);
return 0;
}
static int cnss_qca6174_powerup(struct cnss_pci_data *pci_priv)
{
int ret = 0;
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
ret = cnss_power_on_device(plat_priv);
if (ret) {
cnss_pr_err("Failed to power on device, err = %d\n", ret);
goto out;
}
ret = cnss_resume_pci_link(pci_priv);
if (ret) {
cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
goto power_off;
}
ret = cnss_pci_call_driver_probe(pci_priv);
if (ret)
goto suspend_link;
return 0;
suspend_link:
cnss_suspend_pci_link(pci_priv);
power_off:
cnss_power_off_device(plat_priv);
out:
return ret;
}
static int cnss_qca6174_shutdown(struct cnss_pci_data *pci_priv)
{
int ret = 0;
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
cnss_pm_request_resume(pci_priv);
cnss_pci_call_driver_remove(pci_priv);
cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
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)
cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
cnss_power_off_device(plat_priv);
clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
return ret;
}
static void cnss_qca6174_crash_shutdown(struct cnss_pci_data *pci_priv)
{
if (pci_priv->driver_ops && pci_priv->driver_ops->crash_shutdown)
pci_priv->driver_ops->crash_shutdown(pci_priv->pci_dev);
}
static int cnss_qca6174_ramdump(struct cnss_pci_data *pci_priv)
{
int ret = 0;
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
struct cnss_ramdump_info *ramdump_info;
struct ramdump_segment segment;
ramdump_info = &plat_priv->ramdump_info;
if (!ramdump_info->ramdump_size)
return -EINVAL;
memset(&segment, 0, sizeof(segment));
segment.v_address = ramdump_info->ramdump_va;
segment.size = ramdump_info->ramdump_size;
ret = do_ramdump(ramdump_info->ramdump_dev, &segment, 1);
return ret;
}
static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
{
int ret = 0;
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
unsigned int timeout;
if (plat_priv->ramdump_info_v2.dump_data_valid ||
test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
cnss_pci_clear_dump_info(pci_priv);
}
ret = cnss_power_on_device(plat_priv);
if (ret) {
cnss_pr_err("Failed to power on device, err = %d\n", ret);
goto out;
}
ret = cnss_resume_pci_link(pci_priv);
if (ret) {
cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
goto power_off;
}
timeout = cnss_get_qmi_timeout();
ret = cnss_pci_start_mhi(pci_priv);
if (ret) {
cnss_pr_err("Failed to start MHI, err = %d\n", ret);
if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
!pci_priv->pci_link_down_ind && timeout)
mod_timer(&plat_priv->fw_boot_timer,
jiffies + msecs_to_jiffies(timeout >> 1));
return 0;
}
if (test_bit(USE_CORE_ONLY_FW, cnss_get_debug_quirks())) {
clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
return 0;
}
cnss_set_pin_connect_status(plat_priv);
if (*cnss_get_qmi_bypass()) {
ret = cnss_pci_call_driver_probe(pci_priv);
if (ret)
goto stop_mhi;
} else if (timeout) {
mod_timer(&plat_priv->fw_boot_timer,
jiffies + msecs_to_jiffies(timeout << 1));
}
return 0;
stop_mhi:
cnss_pci_stop_mhi(pci_priv);
cnss_suspend_pci_link(pci_priv);
power_off:
cnss_power_off_device(plat_priv);
out:
return ret;
}
static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
{
int ret = 0;
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
cnss_pm_request_resume(pci_priv);
cnss_pci_call_driver_remove(pci_priv);
cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
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);
if (ret)
cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
cnss_power_off_device(plat_priv);
clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
return ret;
}
static void cnss_qca6290_crash_shutdown(struct cnss_pci_data *pci_priv)
{
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
int ret = 0;
cnss_pr_dbg("Crash shutdown with driver_state 0x%lx\n",
plat_priv->driver_state);
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
cnss_pr_dbg("Ignore crash shutdown\n");
return;
}
ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM_KERNEL_PANIC);
if (ret) {
cnss_pr_err("Fail to complete RDDM, err = %d\n", ret);
return;
}
cnss_pci_collect_dump_info(pci_priv);
}
static int cnss_qca6290_ramdump(struct cnss_pci_data *pci_priv)
{
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
struct cnss_dump_data *dump_data = &info_v2->dump_data;
struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
struct ramdump_segment *ramdump_segs, *s;
int i, ret = 0;
if (!info_v2->dump_data_valid ||
dump_data->nentries == 0)
return 0;
ramdump_segs = kcalloc(dump_data->nentries,
sizeof(*ramdump_segs),
GFP_KERNEL);
if (!ramdump_segs)
return -ENOMEM;
s = ramdump_segs;
for (i = 0; i < dump_data->nentries; i++) {
s->address = dump_seg->address;
s->v_address = dump_seg->v_address;
s->size = dump_seg->size;
s++;
dump_seg++;
}
ret = do_elf_ramdump(info_v2->ramdump_dev, ramdump_segs,
dump_data->nentries);
kfree(ramdump_segs);
cnss_pci_set_mhi_state(plat_priv->bus_priv, CNSS_MHI_DEINIT);
cnss_pci_clear_dump_info(plat_priv->bus_priv);
return ret;
}
int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv)
{
int ret = 0;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
return -ENODEV;
}
switch (pci_priv->device_id) {
case QCA6174_DEVICE_ID:
ret = cnss_qca6174_powerup(pci_priv);
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
ret = cnss_qca6290_powerup(pci_priv);
break;
default:
cnss_pr_err("Unknown device_id found: 0x%x\n",
pci_priv->device_id);
ret = -ENODEV;
}
return ret;
}
int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv)
{
int ret = 0;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
return -ENODEV;
}
switch (pci_priv->device_id) {
case QCA6174_DEVICE_ID:
ret = cnss_qca6174_shutdown(pci_priv);
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
ret = cnss_qca6290_shutdown(pci_priv);
break;
default:
cnss_pr_err("Unknown device_id found: 0x%x\n",
pci_priv->device_id);
ret = -ENODEV;
}
return ret;
}
int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv)
{
int ret = 0;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
return -ENODEV;
}
switch (pci_priv->device_id) {
case QCA6174_DEVICE_ID:
cnss_qca6174_crash_shutdown(pci_priv);
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
cnss_qca6290_crash_shutdown(pci_priv);
break;
default:
cnss_pr_err("Unknown device_id found: 0x%x\n",
pci_priv->device_id);
ret = -ENODEV;
}
return ret;
}
int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv)
{
int ret = 0;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
return -ENODEV;
}
switch (pci_priv->device_id) {
case QCA6174_DEVICE_ID:
ret = cnss_qca6174_ramdump(pci_priv);
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
ret = cnss_qca6290_ramdump(pci_priv);
break;
default:
cnss_pr_err("Unknown device_id found: 0x%x\n",
pci_priv->device_id);
ret = -ENODEV;
}
return ret;
}
int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
{
int ret = 0;
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
struct cnss_pci_data *pci_priv;
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL\n");
return -ENODEV;
}
pci_priv = plat_priv->bus_priv;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
return -ENODEV;
}
if (pci_priv->driver_ops) {
cnss_pr_err("Driver has already registered\n");
return -EEXIST;
}
ret = cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_REGISTER_DRIVER,
CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
driver_ops);
return ret;
}
EXPORT_SYMBOL(cnss_wlan_register_driver);
void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
{
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL\n");
return;
}
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
}
EXPORT_SYMBOL(cnss_wlan_unregister_driver);
int cnss_pci_register_driver_hdlr(struct cnss_pci_data *pci_priv,
void *data)
{
int ret = 0;
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
pci_priv->driver_ops = data;
ret = cnss_pci_dev_powerup(pci_priv);
if (ret) {
clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
pci_priv->driver_ops = NULL;
}
return ret;
}
int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv)
{
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
cnss_pci_dev_shutdown(pci_priv);
pci_priv->driver_ops = NULL;
return 0;
}
static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
{
int ret = 0;
@ -387,7 +914,7 @@ static int cnss_pci_suspend(struct device *dev)
if (!plat_priv)
goto out;
driver_ops = plat_priv->driver_ops;
driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->suspend) {
ret = driver_ops->suspend(pci_dev, state);
if (ret) {
@ -459,7 +986,7 @@ static int cnss_pci_resume(struct device *dev)
cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
}
driver_ops = plat_priv->driver_ops;
driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->resume) {
ret = driver_ops->resume(pci_dev);
if (ret)
@ -488,7 +1015,7 @@ static int cnss_pci_suspend_noirq(struct device *dev)
if (!plat_priv)
goto out;
driver_ops = plat_priv->driver_ops;
driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->suspend_noirq)
ret = driver_ops->suspend_noirq(pci_dev);
@ -511,7 +1038,7 @@ static int cnss_pci_resume_noirq(struct device *dev)
if (!plat_priv)
goto out;
driver_ops = plat_priv->driver_ops;
driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->resume_noirq &&
!pci_priv->pci_link_down_ind)
ret = driver_ops->resume_noirq(pci_dev);
@ -542,7 +1069,7 @@ static int cnss_pci_runtime_suspend(struct device *dev)
cnss_pr_dbg("Runtime suspend start\n");
driver_ops = plat_priv->driver_ops;
driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->runtime_ops &&
driver_ops->runtime_ops->runtime_suspend)
ret = driver_ops->runtime_ops->runtime_suspend(pci_dev);
@ -574,7 +1101,7 @@ static int cnss_pci_runtime_resume(struct device *dev)
cnss_pr_dbg("Runtime resume start\n");
driver_ops = plat_priv->driver_ops;
driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->runtime_ops &&
driver_ops->runtime_ops->runtime_resume)
ret = driver_ops->runtime_ops->runtime_resume(pci_dev);
@ -1054,13 +1581,19 @@ void cnss_get_msi_address(struct device *dev, u32 *msi_addr_low,
}
EXPORT_SYMBOL(cnss_get_msi_address);
static char *get_wake_msi_name(void)
{
return (char *)WAKE_MSI_NAME;
}
u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv)
{
int ret, num_vectors;
u32 user_base_data, base_vector;
char *wake_msi_name = get_wake_msi_name();
ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
WAKE_MSI_NAME, &num_vectors,
wake_msi_name, &num_vectors,
&user_base_data, &base_vector);
if (ret) {
@ -1286,8 +1819,8 @@ static void cnss_mhi_notify_status(enum MHI_CB_REASON reason, void *priv)
cnss_pr_dbg("MHI status cb is called with reason %d\n", reason);
if (plat_priv->driver_ops && plat_priv->driver_ops->update_status)
plat_priv->driver_ops->update_status(pci_priv->pci_dev,
if (pci_priv->driver_ops && pci_priv->driver_ops->update_status)
pci_priv->driver_ops->update_status(pci_priv->pci_dev,
CNSS_FW_DOWN);
set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);

View file

@ -62,6 +62,7 @@ struct cnss_pci_data {
const struct pci_device_id *pci_device_id;
u32 device_id;
u16 revision_id;
struct cnss_wlan_driver *driver_ops;
bool pci_link_state;
bool pci_link_down_ind;
struct pci_saved_state *saved_state;
@ -155,5 +156,15 @@ int cnss_pm_request_resume(struct cnss_pci_data *pci_priv);
u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv);
int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv);
void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv);
int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv);
int cnss_pci_call_driver_remove(struct cnss_pci_data *pci_priv);
int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv);
int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv);
int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv);
int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv);
int cnss_pci_register_driver_hdlr(struct cnss_pci_data *pci_priv, void *data);
int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv);
int cnss_pci_call_driver_modem_status(struct cnss_pci_data *pci_priv,
int modem_current_status);
int cnss_pci_recovery_update_status(struct cnss_pci_data *pci_priv);
#endif /* _CNSS_PCI_H */