summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom/icnss.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/qcom/icnss.c')
-rw-r--r--drivers/soc/qcom/icnss.c123
1 files changed, 83 insertions, 40 deletions
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 16ab2400cd69..ab46eb70651c 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -48,6 +48,11 @@
#include <soc/qcom/socinfo.h>
#include <soc/qcom/ramdump.h>
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+#include <net/cnss_prealloc.h>
+#endif
+
+
#include "wlan_firmware_service_v01.h"
#ifdef CONFIG_ICNSS_DEBUG
@@ -62,7 +67,7 @@ module_param(qmi_timeout, ulong, 0600);
#define WLFW_CLIENT_ID 0x4b4e454c
#define MAX_PROP_SIZE 32
#define NUM_LOG_PAGES 10
-#define NUM_REG_LOG_PAGES 4
+#define NUM_LOG_LONG_PAGES 4
#define ICNSS_MAGIC 0x5abc5abc
#define ICNSS_SERVICE_LOCATION_CLIENT_NAME "ICNSS-WLAN"
@@ -77,6 +82,11 @@ module_param(qmi_timeout, ulong, 0600);
ipc_log_string(icnss_ipc_log_context, _x); \
} while (0)
+#define icnss_ipc_log_long_string(_x...) do { \
+ if (icnss_ipc_log_long_context) \
+ ipc_log_string(icnss_ipc_log_long_context, _x); \
+ } while (0)
+
#define icnss_pr_err(_fmt, ...) do { \
pr_err(_fmt, ##__VA_ARGS__); \
icnss_ipc_log_string("ERR: " pr_fmt(_fmt), \
@@ -101,6 +111,12 @@ module_param(qmi_timeout, ulong, 0600);
##__VA_ARGS__); \
} while (0)
+#define icnss_pr_vdbg(_fmt, ...) do { \
+ pr_debug(_fmt, ##__VA_ARGS__); \
+ icnss_ipc_log_long_string("DBG: " pr_fmt(_fmt), \
+ ##__VA_ARGS__); \
+ } while (0)
+
#ifdef CONFIG_ICNSS_DEBUG
#define ICNSS_ASSERT(_condition) do { \
if (!(_condition)) { \
@@ -138,6 +154,7 @@ uint64_t dynamic_feature_mask = QMI_WLFW_FW_REJUVENATE_V01;
module_param(dynamic_feature_mask, ullong, 0600);
void *icnss_ipc_log_context;
+void *icnss_ipc_log_long_context;
#define ICNSS_EVENT_PENDING 2989
@@ -367,7 +384,7 @@ static void icnss_pm_stay_awake(struct icnss_priv *priv)
if (atomic_inc_return(&priv->pm_count) != 1)
return;
- icnss_pr_dbg("PM stay awake, state: 0x%lx, count: %d\n", priv->state,
+ icnss_pr_vdbg("PM stay awake, state: 0x%lx, count: %d\n", priv->state,
atomic_read(&priv->pm_count));
pm_stay_awake(&priv->pdev->dev);
@@ -384,7 +401,7 @@ static void icnss_pm_relax(struct icnss_priv *priv)
if (r != 0)
return;
- icnss_pr_dbg("PM relax, state: 0x%lx, count: %d\n", priv->state,
+ icnss_pr_vdbg("PM relax, state: 0x%lx, count: %d\n", priv->state,
atomic_read(&priv->pm_count));
pm_relax(&priv->pdev->dev);
@@ -718,7 +735,7 @@ static int icnss_vreg_on(struct icnss_priv *priv)
if (!vreg_info->reg)
continue;
- icnss_pr_dbg("Regulator %s being enabled\n", vreg_info->name);
+ icnss_pr_vdbg("Regulator %s being enabled\n", vreg_info->name);
ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v,
vreg_info->max_v);
@@ -780,7 +797,7 @@ static int icnss_vreg_off(struct icnss_priv *priv)
if (!vreg_info->reg)
continue;
- icnss_pr_dbg("Regulator %s being disabled\n", vreg_info->name);
+ icnss_pr_vdbg("Regulator %s being disabled\n", vreg_info->name);
ret = regulator_disable(vreg_info->reg);
if (ret)
@@ -814,7 +831,7 @@ static int icnss_clk_init(struct icnss_priv *priv)
if (!clk_info->handle)
continue;
- icnss_pr_dbg("Clock %s being enabled\n", clk_info->name);
+ icnss_pr_vdbg("Clock %s being enabled\n", clk_info->name);
if (clk_info->freq) {
ret = clk_set_rate(clk_info->handle, clk_info->freq);
@@ -861,7 +878,7 @@ static int icnss_clk_deinit(struct icnss_priv *priv)
if (!clk_info->handle)
continue;
- icnss_pr_dbg("Clock %s being disabled\n", clk_info->name);
+ icnss_pr_vdbg("Clock %s being disabled\n", clk_info->name);
clk_disable_unprepare(clk_info->handle);
}
@@ -1734,7 +1751,7 @@ static void icnss_qmi_wlfw_clnt_notify_work(struct work_struct *work)
if (!penv || !penv->wlfw_clnt)
return;
- icnss_pr_dbg("Receiving Event in work queue context\n");
+ icnss_pr_vdbg("Receiving Event in work queue context\n");
do {
} while ((ret = qmi_recv_msg(penv->wlfw_clnt)) == 0);
@@ -1742,13 +1759,13 @@ static void icnss_qmi_wlfw_clnt_notify_work(struct work_struct *work)
if (ret != -ENOMSG)
icnss_pr_err("Error receiving message: %d\n", ret);
- icnss_pr_dbg("Receiving Event completed\n");
+ icnss_pr_vdbg("Receiving Event completed\n");
}
static void icnss_qmi_wlfw_clnt_notify(struct qmi_handle *handle,
enum qmi_event_type event, void *notify_priv)
{
- icnss_pr_dbg("QMI client notify: %d\n", event);
+ icnss_pr_vdbg("QMI client notify: %d\n", event);
if (!penv || !penv->wlfw_clnt)
return;
@@ -1763,11 +1780,29 @@ static void icnss_qmi_wlfw_clnt_notify(struct qmi_handle *handle,
}
}
+static int icnss_call_driver_uevent(struct icnss_priv *priv,
+ enum icnss_uevent uevent, void *data)
+{
+ struct icnss_uevent_data uevent_data;
+
+ if (!priv->ops || !priv->ops->uevent)
+ return 0;
+
+ icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n",
+ priv->state, uevent);
+
+ uevent_data.uevent = uevent;
+ uevent_data.data = data;
+
+ return priv->ops->uevent(&priv->pdev->dev, &uevent_data);
+}
+
static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
unsigned int msg_id, void *msg,
unsigned int msg_len, void *ind_cb_priv)
{
struct icnss_event_pd_service_down_data *event_data;
+ struct icnss_uevent_fw_down_data fw_down_data;
if (!penv)
return;
@@ -1799,6 +1834,9 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
return;
event_data->crashed = true;
event_data->fw_rejuvenate = true;
+ fw_down_data.crashed = true;
+ icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_DOWN,
+ &fw_down_data);
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
0, event_data);
break;
@@ -1912,23 +1950,6 @@ static int icnss_driver_event_server_exit(void *data)
return 0;
}
-static int icnss_call_driver_uevent(struct icnss_priv *priv,
- enum icnss_uevent uevent, void *data)
-{
- struct icnss_uevent_data uevent_data;
-
- if (!priv->ops || !priv->ops->uevent)
- return 0;
-
- icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n",
- priv->state, uevent);
-
- uevent_data.uevent = uevent;
- uevent_data.data = data;
-
- return priv->ops->uevent(&priv->pdev->dev, &uevent_data);
-}
-
static int icnss_call_driver_probe(struct icnss_priv *priv)
{
int ret;
@@ -1947,6 +1968,8 @@ static int icnss_call_driver_probe(struct icnss_priv *priv)
if (ret < 0) {
icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
ret, priv->state);
+ wcnss_prealloc_check_memory_leak();
+ wcnss_pre_alloc_reset();
goto out;
}
@@ -2076,6 +2099,8 @@ static int icnss_driver_event_register_driver(void *data)
if (ret) {
icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
ret, penv->state);
+ wcnss_prealloc_check_memory_leak();
+ wcnss_pre_alloc_reset();
goto power_off;
}
@@ -2085,7 +2110,6 @@ static int icnss_driver_event_register_driver(void *data)
power_off:
icnss_hw_power_off(penv);
- penv->ops = NULL;
out:
return ret;
}
@@ -2101,6 +2125,8 @@ static int icnss_driver_event_unregister_driver(void *data)
penv->ops->remove(&penv->pdev->dev);
clear_bit(ICNSS_DRIVER_PROBED, &penv->state);
+ wcnss_prealloc_check_memory_leak();
+ wcnss_pre_alloc_reset();
penv->ops = NULL;
@@ -2125,6 +2151,8 @@ static int icnss_call_driver_remove(struct icnss_priv *priv)
penv->ops->remove(&priv->pdev->dev);
clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
+ wcnss_prealloc_check_memory_leak();
+ wcnss_pre_alloc_reset();
icnss_hw_power_off(penv);
@@ -2142,7 +2170,8 @@ static int icnss_fw_crashed(struct icnss_priv *priv,
icnss_pm_stay_awake(priv);
- icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
+ if (test_bit(ICNSS_DRIVER_PROBED, &priv->state))
+ icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
if (event_data->wdog_bite) {
set_bit(ICNSS_WDOG_BITE, &priv->state);
@@ -2308,8 +2337,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
struct notif_data *notif = data;
struct icnss_priv *priv = container_of(nb, struct icnss_priv,
modem_ssr_nb);
+ struct icnss_uevent_fw_down_data fw_down_data;
- icnss_pr_dbg("Modem-Notify: event %lu\n", code);
+ icnss_pr_vdbg("Modem-Notify: event %lu\n", code);
if (code == SUBSYS_AFTER_SHUTDOWN &&
notif->crashed == CRASH_STATUS_ERR_FATAL) {
@@ -2340,6 +2370,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
if (notif->crashed == CRASH_STATUS_WDOG_BITE)
event_data->wdog_bite = true;
+ fw_down_data.crashed = !!notif->crashed;
+ icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
+
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
@@ -2403,6 +2436,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
service_notifier_nb);
enum pd_subsys_state *state = data;
struct icnss_event_pd_service_down_data *event_data;
+ struct icnss_uevent_fw_down_data fw_down_data;
icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n",
notification, priv->state);
@@ -2438,6 +2472,8 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
event_post:
icnss_ignore_qmi_timeout(true);
+ fw_down_data.crashed = event_data->crashed;
+ icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
done:
@@ -2609,7 +2645,7 @@ int icnss_register_driver(struct icnss_driver_ops *ops)
}
ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
- ICNSS_EVENT_SYNC, ops);
+ 0, ops);
if (ret == -EINTR)
ret = 0;
@@ -2656,7 +2692,7 @@ int icnss_ce_request_irq(unsigned int ce_id,
goto out;
}
- icnss_pr_dbg("CE request IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
+ icnss_pr_vdbg("CE request IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
icnss_pr_err("Invalid CE ID, ce_id: %d\n", ce_id);
@@ -2682,7 +2718,7 @@ int icnss_ce_request_irq(unsigned int ce_id,
irq_entry->irq = irq;
irq_entry->handler = handler;
- icnss_pr_dbg("IRQ requested: %d, ce_id: %d\n", irq, ce_id);
+ icnss_pr_vdbg("IRQ requested: %d, ce_id: %d\n", irq, ce_id);
penv->stats.ce_irqs[ce_id].request++;
out:
@@ -2701,7 +2737,7 @@ int icnss_ce_free_irq(unsigned int ce_id, void *ctx)
goto out;
}
- icnss_pr_dbg("CE free IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
+ icnss_pr_vdbg("CE free IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
icnss_pr_err("Invalid CE ID to free, ce_id: %d\n", ce_id);
@@ -2735,7 +2771,7 @@ void icnss_enable_irq(unsigned int ce_id)
return;
}
- icnss_pr_dbg("Enable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
+ icnss_pr_vdbg("Enable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
@@ -2759,7 +2795,7 @@ void icnss_disable_irq(unsigned int ce_id)
return;
}
- icnss_pr_dbg("Disable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
+ icnss_pr_vdbg("Disable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
@@ -4259,7 +4295,7 @@ static int icnss_pm_suspend(struct device *dev)
return -EINVAL;
}
- icnss_pr_dbg("PM Suspend, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM Suspend, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->pm_suspend ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -4288,7 +4324,7 @@ static int icnss_pm_resume(struct device *dev)
return -EINVAL;
}
- icnss_pr_dbg("PM resume, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM resume, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->pm_resume ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -4317,7 +4353,7 @@ static int icnss_pm_suspend_noirq(struct device *dev)
return -EINVAL;
}
- icnss_pr_dbg("PM suspend_noirq, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM suspend_noirq, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->suspend_noirq ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -4346,7 +4382,7 @@ static int icnss_pm_resume_noirq(struct device *dev)
return -EINVAL;
}
- icnss_pr_dbg("PM resume_noirq, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM resume_noirq, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->resume_noirq ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -4397,6 +4433,11 @@ static int __init icnss_initialize(void)
if (!icnss_ipc_log_context)
icnss_pr_err("Unable to create log context\n");
+ icnss_ipc_log_long_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
+ "icnss_long", 0);
+ if (!icnss_ipc_log_long_context)
+ icnss_pr_err("Unable to create log long context\n");
+
return platform_driver_register(&icnss_driver);
}
@@ -4405,6 +4446,8 @@ static void __exit icnss_exit(void)
platform_driver_unregister(&icnss_driver);
ipc_log_context_destroy(icnss_ipc_log_context);
icnss_ipc_log_context = NULL;
+ ipc_log_context_destroy(icnss_ipc_log_long_context);
+ icnss_ipc_log_long_context = NULL;
}