Merge "cnss2: Add support to remove WLAN recovery from SSR framework"

This commit is contained in:
qctecmdr 2020-08-13 04:49:33 -07:00 • committed by Gerrit - the friendly Code Review server
commit 8cc45cd760
6 changed files with 174 additions and 30 deletions

View file

@ -250,6 +250,21 @@ void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv, bool in_panic)
}
}
void cnss_bus_device_crashed(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_device_crashed(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return;
}
}
int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)

View file

@ -35,6 +35,7 @@ int cnss_bus_qmi_send_put(struct cnss_plat_data *plat_priv);
void cnss_bus_fw_boot_timeout_hdlr(struct timer_list *t);
void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv,
bool in_panic);
void cnss_bus_device_crashed(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);

View file

@ -12,8 +12,6 @@
#include <linux/suspend.h>
#include <linux/timer.h>
#include <soc/qcom/minidump.h>
#include <soc/qcom/ramdump.h>
#include <soc/qcom/subsystem_notif.h>
#include "main.h"
#include "bus.h"
@ -26,7 +24,7 @@
#define CNSS_DUMP_NAME "CNSS_WLAN"
#define CNSS_DUMP_DESC_SIZE 0x1000
#define CNSS_DUMP_SEG_VER 0x1
#define WLAN_RECOVERY_DELAY 1000
#define RECOVERY_DELAY_MS 100
#define FILE_SYSTEM_READY 1
#define FW_READY_TIMEOUT 20000
#define FW_ASSERT_TIMEOUT 5000
@ -785,7 +783,7 @@ static void cnss_put_resources(struct cnss_plat_data *plat_priv)
cnss_put_vreg_type(plat_priv, CNSS_VREG_PRIM);
}
#ifdef CONFIG_ESOC
#if IS_ENABLED(CONFIG_ESOC) && IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
static int cnss_modem_notifier_nb(struct notifier_block *nb,
unsigned long code,
void *ss_handle)
@ -893,6 +891,7 @@ static inline int cnss_register_esoc(struct cnss_plat_data *plat_priv)
static inline void cnss_unregister_esoc(struct cnss_plat_data *plat_priv) {}
#endif
#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
{
struct cnss_plat_data *plat_priv;
@ -985,6 +984,36 @@ static int cnss_subsys_ramdump(int enable,
return cnss_bus_dev_ramdump(plat_priv);
}
static void cnss_recovery_work_handler(struct work_struct *work)
{
}
#else
static void cnss_recovery_work_handler(struct work_struct *work)
{
struct cnss_plat_data *plat_priv =
container_of(work, struct cnss_plat_data, recovery_work);
if (!plat_priv->recovery_enabled)
panic("subsys-restart: Resetting the SoC wlan crashed\n");
cnss_bus_dev_shutdown(plat_priv);
msleep(RECOVERY_DELAY_MS);
cnss_bus_dev_powerup(plat_priv);
}
void cnss_device_crashed(struct device *dev)
{
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
if (!plat_priv)
return;
set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
schedule_work(&plat_priv->recovery_work);
}
EXPORT_SYMBOL(cnss_device_crashed);
#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
{
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
@ -1019,9 +1048,6 @@ 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_subsys_info *subsys_info =
&plat_priv->subsys_info;
plat_priv->recovery_count++;
if (plat_priv->device_id == QCA6174_DEVICE_ID)
@ -1054,11 +1080,7 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
break;
}
if (!subsys_info->subsys_device)
return 0;
subsys_set_crash_status(subsys_info->subsys_device, true);
subsystem_restart_dev(subsys_info->subsys_device);
cnss_bus_device_crashed(plat_priv);
return 0;
@ -1629,6 +1651,7 @@ int cnss_va_to_pa(struct device *dev, size_t size, void *va, dma_addr_t dma,
return 0;
}
#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
int cnss_register_subsys(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@ -1680,6 +1703,70 @@ void cnss_unregister_subsys(struct cnss_plat_data *plat_priv)
subsys_unregister(subsys_info->subsys_device);
}
static void *cnss_create_ramdump_device(struct cnss_plat_data *plat_priv)
{
struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info;
return create_ramdump_device(subsys_info->subsys_desc.name,
subsys_info->subsys_desc.dev);
}
static void cnss_destroy_ramdump_device(struct cnss_plat_data *plat_priv,
void *ramdump_dev)
{
destroy_ramdump_device(ramdump_dev);
}
#else
static int cnss_panic_handler(struct notifier_block *nb, unsigned long action,
void *data)
{
struct cnss_plat_data *plat_priv =
container_of(nb, struct cnss_plat_data, panic_nb);
cnss_bus_dev_crash_shutdown(plat_priv);
return NOTIFY_DONE;
}
int cnss_register_subsys(struct cnss_plat_data *plat_priv)
{
int ret;
if (!plat_priv)
return -ENODEV;
plat_priv->panic_nb.notifier_call = cnss_panic_handler;
ret = atomic_notifier_chain_register(&panic_notifier_list,
&plat_priv->panic_nb);
if (ret) {
cnss_pr_err("Failed to register panic handler\n");
return -EINVAL;
}
return 0;
}
void cnss_unregister_subsys(struct cnss_plat_data *plat_priv)
{
int ret;
ret = atomic_notifier_chain_unregister(&panic_notifier_list,
&plat_priv->panic_nb);
if (ret)
cnss_pr_err("Failed to unregister panic handler\n");
}
static void *cnss_create_ramdump_device(struct cnss_plat_data *plat_priv)
{
return &plat_priv->plat_dev->dev;
}
static void cnss_destroy_ramdump_device(struct cnss_plat_data *plat_priv,
void *ramdump_dev)
{
}
#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
static int cnss_init_dump_entry(struct cnss_plat_data *plat_priv)
{
struct cnss_ramdump_info *ramdump_info;
@ -1703,12 +1790,10 @@ static int cnss_register_ramdump_v1(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct device *dev;
struct cnss_subsys_info *subsys_info;
struct cnss_ramdump_info *ramdump_info;
u32 ramdump_size = 0;
dev = &plat_priv->plat_dev->dev;
subsys_info = &plat_priv->subsys_info;
ramdump_info = &plat_priv->ramdump_info;
if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
@ -1736,9 +1821,7 @@ static int cnss_register_ramdump_v1(struct cnss_plat_data *plat_priv)
goto free_ramdump;
}
ramdump_info->ramdump_dev =
create_ramdump_device(subsys_info->subsys_desc.name,
subsys_info->subsys_desc.dev);
ramdump_info->ramdump_dev = cnss_create_ramdump_device(plat_priv);
if (!ramdump_info->ramdump_dev) {
cnss_pr_err("Failed to create ramdump device!");
ret = -ENOMEM;
@ -1762,7 +1845,8 @@ static void cnss_unregister_ramdump_v1(struct cnss_plat_data *plat_priv)
ramdump_info = &plat_priv->ramdump_info;
if (ramdump_info->ramdump_dev)
destroy_ramdump_device(ramdump_info->ramdump_dev);
cnss_destroy_ramdump_device(plat_priv,
ramdump_info->ramdump_dev);
if (ramdump_info->ramdump_va)
dma_free_coherent(dev, ramdump_info->ramdump_size,
@ -1794,14 +1878,12 @@ static int cnss_ignore_dump_data_reg_fail(int ret)
static int cnss_register_ramdump_v2(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct cnss_subsys_info *subsys_info;
struct cnss_ramdump_info_v2 *info_v2;
struct cnss_dump_data *dump_data;
struct msm_dump_entry dump_entry;
struct device *dev = &plat_priv->plat_dev->dev;
u32 ramdump_size = 0;
subsys_info = &plat_priv->subsys_info;
info_v2 = &plat_priv->ramdump_info_v2;
dump_data = &info_v2->dump_data;
@ -1833,9 +1915,7 @@ static int cnss_register_ramdump_v2(struct cnss_plat_data *plat_priv)
goto free_ramdump;
}
info_v2->ramdump_dev =
create_ramdump_device(subsys_info->subsys_desc.name,
subsys_info->subsys_desc.dev);
info_v2->ramdump_dev = cnss_create_ramdump_device(plat_priv);
if (!info_v2->ramdump_dev) {
cnss_pr_err("Failed to create ramdump device!\n");
ret = -ENOMEM;
@ -1857,7 +1937,7 @@ static void cnss_unregister_ramdump_v2(struct cnss_plat_data *plat_priv)
info_v2 = &plat_priv->ramdump_info_v2;
if (info_v2->ramdump_dev)
destroy_ramdump_device(info_v2->ramdump_dev);
cnss_destroy_ramdump_device(plat_priv, info_v2->ramdump_dev);
kfree(info_v2->dump_data_vaddr);
info_v2->dump_data_vaddr = NULL;
@ -2051,6 +2131,32 @@ static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv)
kfree(bus_bw_info->cfg_table);
}
static ssize_t recovery_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
unsigned int recovery = 0;
if (!plat_priv)
return -ENODEV;
if (sscanf(buf, "%du", &recovery) != 1) {
cnss_pr_err("Invalid recovery sysfs command\n");
return -EINVAL;
}
if (recovery)
plat_priv->recovery_enabled = true;
else
plat_priv->recovery_enabled = false;
cnss_pr_dbg("%s WLAN recovery, count is %zu\n",
plat_priv->recovery_enabled ? "Enable" : "Disable", count);
return count;
}
static ssize_t shutdown_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@ -2114,10 +2220,12 @@ static ssize_t fs_ready_store(struct device *dev,
static DEVICE_ATTR_WO(fs_ready);
static DEVICE_ATTR_WO(shutdown);
static DEVICE_ATTR_WO(recovery);
static struct attribute *cnss_attrs[] = {
&dev_attr_fs_ready.attr,
&dev_attr_shutdown.attr,
&dev_attr_recovery.attr,
NULL,
};
@ -2243,6 +2351,7 @@ static int cnss_misc_init(struct cnss_plat_data *plat_priv)
cnss_pr_err("Failed to init platform device wakeup source, err = %d\n",
ret);
INIT_WORK(&plat_priv->recovery_work, cnss_recovery_work_handler);
init_completion(&plat_priv->power_up_complete);
init_completion(&plat_priv->cal_complete);
init_completion(&plat_priv->rddm_complete);

View file

@ -5,7 +5,7 @@
#define _CNSS_MAIN_H
#include <asm/arch_timer.h>
#ifdef CONFIG_ESOC
#if IS_ENABLED(CONFIG_ESOC)
#include <linux/esoc_client.h>
#endif
#include <linux/etherdevice.h>
@ -14,7 +14,11 @@
#include <linux/platform_device.h>
#include <net/cnss2.h>
#include <soc/qcom/memory_dump.h>
#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
#include <soc/qcom/ramdump.h>
#include <soc/qcom/subsystem_notif.h>
#include <soc/qcom/subsystem_restart.h>
#endif
#include "qmi.h"
@ -83,14 +87,16 @@ struct cnss_pinctrl_info {
struct pinctrl_state *wlan_en_sleep;
};
#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
struct cnss_subsys_info {
struct subsys_device *subsys_device;
struct subsys_desc subsys_desc;
void *subsys_handle;
};
#endif
struct cnss_ramdump_info {
struct ramdump_device *ramdump_dev;
void *ramdump_dev;
unsigned long ramdump_size;
void *ramdump_va;
phys_addr_t ramdump_pa;
@ -114,14 +120,14 @@ struct cnss_dump_data {
};
struct cnss_ramdump_info_v2 {
struct ramdump_device *ramdump_dev;
void *ramdump_dev;
unsigned long ramdump_size;
void *dump_data_vaddr;
u8 dump_data_valid;
struct cnss_dump_data dump_data;
};
#ifdef CONFIG_ESOC
#if IS_ENABLED(CONFIG_ESOC)
struct cnss_esoc_info {
struct esoc_desc *esoc_desc;
u8 notify_modem_status;
@ -342,26 +348,31 @@ struct cnss_plat_data {
struct list_head vreg_list;
struct list_head clk_list;
struct cnss_pinctrl_info pinctrl_info;
#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
struct cnss_subsys_info subsys_info;
#endif
struct cnss_ramdump_info ramdump_info;
struct cnss_ramdump_info_v2 ramdump_info_v2;
#ifdef CONFIG_ESOC
#if IS_ENABLED(CONFIG_ESOC)
struct cnss_esoc_info esoc_info;
#endif
struct cnss_bus_bw_info bus_bw_info;
struct notifier_block modem_nb;
struct notifier_block reboot_nb;
struct notifier_block panic_nb;
struct cnss_platform_cap cap;
struct pm_qos_request qos_request;
struct cnss_device_version device_version;
unsigned long device_id;
enum cnss_driver_status driver_status;
u32 recovery_count;
u8 recovery_enabled;
unsigned long driver_state;
struct list_head event_list;
spinlock_t event_lock; /* spinlock for driver work event handling */
struct work_struct event_work;
struct workqueue_struct *event_wq;
struct work_struct recovery_work;
struct qmi_handle qmi_wlfw;
struct wlfw_rf_chip_info chip_info;
struct wlfw_rf_board_info board_info;

View file

@ -12,7 +12,6 @@
#include <linux/pm_runtime.h>
#include <linux/memblock.h>
#include <linux/completion.h>
#include <soc/qcom/ramdump.h>
#include "main.h"
#include "bus.h"
@ -4203,6 +4202,14 @@ void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv)
plat_priv->ramdump_info_v2.dump_data_valid = false;
}
void cnss_pci_device_crashed(struct cnss_pci_data *pci_priv)
{
if (!pci_priv)
return;
cnss_device_crashed(&pci_priv->pci_dev->dev);
}
static int cnss_mhi_pm_runtime_get(struct mhi_controller *mhi_ctrl, void *priv)
{
struct cnss_pci_data *pci_priv = priv;

View file

@ -172,6 +172,7 @@ void cnss_pci_free_qdss_mem(struct cnss_pci_data *pci_priv);
int cnss_pci_load_m3(struct cnss_pci_data *pci_priv);
int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv);
void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic);
void cnss_pci_device_crashed(struct cnss_pci_data *pci_priv);
void cnss_pci_clear_dump_info(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);