123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #include <linux/err.h>
- #include <linux/seq_file.h>
- #include <linux/debugfs.h>
- #include <linux/uaccess.h>
- #include <linux/slab.h>
- #include "main.h"
- #include "debug.h"
- #include "qmi.h"
- #include "power.h"
- void *icnss_ipc_log_context;
- void *icnss_ipc_log_long_context;
- void *icnss_ipc_log_smp2p_context;
- void *icnss_ipc_soc_wake_context;
- static ssize_t icnss_regwrite_write(struct file *fp,
- const char __user *user_buf,
- size_t count, loff_t *off)
- {
- struct icnss_priv *priv =
- ((struct seq_file *)fp->private_data)->private;
- char buf[64];
- char *sptr, *token;
- unsigned int len = 0;
- uint32_t reg_offset, mem_type, reg_val;
- const char *delim = " ";
- int ret = 0;
- if (!test_bit(ICNSS_FW_READY, &priv->state) ||
- !test_bit(ICNSS_POWER_ON, &priv->state))
- return -EINVAL;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
- sptr = buf;
- token = strsep(&sptr, delim);
- if (!token)
- return -EINVAL;
- if (!sptr)
- return -EINVAL;
- if (kstrtou32(token, 0, &mem_type))
- return -EINVAL;
- token = strsep(&sptr, delim);
- if (!token)
- return -EINVAL;
- if (!sptr)
- return -EINVAL;
- if (kstrtou32(token, 0, ®_offset))
- return -EINVAL;
- token = strsep(&sptr, delim);
- if (!token)
- return -EINVAL;
- if (kstrtou32(token, 0, ®_val))
- return -EINVAL;
- ret = wlfw_athdiag_write_send_sync_msg(priv, reg_offset, mem_type,
- sizeof(uint32_t),
- (uint8_t *)®_val);
- if (ret)
- return ret;
- return count;
- }
- static int icnss_regwrite_show(struct seq_file *s, void *data)
- {
- struct icnss_priv *priv = s->private;
- seq_puts(s, "Usage: echo <mem_type> <offset> <reg_val> > <debugfs>/icnss/reg_write\n");
- if (!test_bit(ICNSS_FW_READY, &priv->state))
- seq_puts(s, "Firmware is not ready yet!, wait for FW READY\n");
- return 0;
- }
- static int icnss_regwrite_open(struct inode *inode, struct file *file)
- {
- return single_open(file, icnss_regwrite_show, inode->i_private);
- }
- static const struct file_operations icnss_regwrite_fops = {
- .read = seq_read,
- .write = icnss_regwrite_write,
- .open = icnss_regwrite_open,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- };
- static int icnss_regread_show(struct seq_file *s, void *data)
- {
- struct icnss_priv *priv = s->private;
- mutex_lock(&priv->dev_lock);
- if (!priv->diag_reg_read_buf) {
- seq_puts(s, "Usage: echo <mem_type> <offset> <data_len> > <debugfs>/icnss/reg_read\n");
- if (!test_bit(ICNSS_FW_READY, &priv->state))
- seq_puts(s, "Firmware is not ready yet!, wait for FW READY\n");
- mutex_unlock(&priv->dev_lock);
- return 0;
- }
- seq_printf(s, "REGREAD: Addr 0x%x Type 0x%x Length 0x%x\n",
- priv->diag_reg_read_addr, priv->diag_reg_read_mem_type,
- priv->diag_reg_read_len);
- seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4, priv->diag_reg_read_buf,
- priv->diag_reg_read_len, false);
- priv->diag_reg_read_len = 0;
- kfree(priv->diag_reg_read_buf);
- priv->diag_reg_read_buf = NULL;
- mutex_unlock(&priv->dev_lock);
- return 0;
- }
- static int icnss_regread_open(struct inode *inode, struct file *file)
- {
- return single_open(file, icnss_regread_show, inode->i_private);
- }
- static ssize_t icnss_reg_parse(const char __user *user_buf, size_t count,
- struct icnss_reg_info *reg_info_ptr)
- {
- char buf[64] = {0};
- char *sptr = NULL, *token = NULL;
- const char *delim = " ";
- unsigned int len = 0;
- if (user_buf == NULL)
- return -EFAULT;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
- sptr = buf;
- token = strsep(&sptr, delim);
- if (!token)
- return -EINVAL;
- if (!sptr)
- return -EINVAL;
- if (kstrtou32(token, 0, ®_info_ptr->mem_type))
- return -EINVAL;
- token = strsep(&sptr, delim);
- if (!token)
- return -EINVAL;
- if (!sptr)
- return -EINVAL;
- if (kstrtou32(token, 0, ®_info_ptr->reg_offset))
- return -EINVAL;
- token = strsep(&sptr, delim);
- if (!token)
- return -EINVAL;
- if (kstrtou32(token, 0, ®_info_ptr->data_len))
- return -EINVAL;
- if (reg_info_ptr->data_len == 0 ||
- reg_info_ptr->data_len > WLFW_MAX_DATA_SIZE)
- return -EINVAL;
- return 0;
- }
- static ssize_t icnss_regread_write(struct file *fp, const char __user *user_buf,
- size_t count, loff_t *off)
- {
- struct icnss_priv *priv =
- ((struct seq_file *)fp->private_data)->private;
- uint8_t *reg_buf = NULL;
- int ret = 0;
- struct icnss_reg_info reg_info;
- if (!test_bit(ICNSS_FW_READY, &priv->state) ||
- !test_bit(ICNSS_POWER_ON, &priv->state))
- return -EINVAL;
- ret = icnss_reg_parse(user_buf, count, ®_info);
- if (ret)
- return ret;
- mutex_lock(&priv->dev_lock);
- kfree(priv->diag_reg_read_buf);
- priv->diag_reg_read_buf = NULL;
- reg_buf = kzalloc(reg_info.data_len, GFP_KERNEL);
- if (!reg_buf) {
- mutex_unlock(&priv->dev_lock);
- return -ENOMEM;
- }
- ret = wlfw_athdiag_read_send_sync_msg(priv, reg_info.reg_offset,
- reg_info.mem_type,
- reg_info.data_len,
- reg_buf);
- if (ret) {
- kfree(reg_buf);
- mutex_unlock(&priv->dev_lock);
- return ret;
- }
- priv->diag_reg_read_addr = reg_info.reg_offset;
- priv->diag_reg_read_mem_type = reg_info.mem_type;
- priv->diag_reg_read_len = reg_info.data_len;
- priv->diag_reg_read_buf = reg_buf;
- mutex_unlock(&priv->dev_lock);
- return count;
- }
- static const struct file_operations icnss_regread_fops = {
- .read = seq_read,
- .write = icnss_regread_write,
- .open = icnss_regread_open,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- };
- static ssize_t icnss_stats_write(struct file *fp, const char __user *buf,
- size_t count, loff_t *off)
- {
- struct icnss_priv *priv =
- ((struct seq_file *)fp->private_data)->private;
- int ret;
- u32 val;
- ret = kstrtou32_from_user(buf, count, 0, &val);
- if (ret)
- return ret;
- if (ret == 0)
- memset(&priv->stats, 0, sizeof(priv->stats));
- return count;
- }
- static int icnss_stats_show_rejuvenate_info(struct seq_file *s,
- struct icnss_priv *priv)
- {
- if (priv->stats.rejuvenate_ind) {
- seq_puts(s, "\n<---------------- Rejuvenate Info ----------------->\n");
- seq_printf(s, "Number of Rejuvenations: %u\n",
- priv->stats.rejuvenate_ind);
- seq_printf(s, "Cause for Rejuvenation: 0x%x\n",
- priv->cause_for_rejuvenation);
- seq_printf(s, "Requesting Sub-System: 0x%x\n",
- priv->requesting_sub_system);
- seq_printf(s, "Line Number: %u\n",
- priv->line_number);
- seq_printf(s, "Function Name: %s\n",
- priv->function_name);
- }
- return 0;
- }
- static int icnss_stats_show_irqs(struct seq_file *s, struct icnss_priv *priv)
- {
- int i;
- seq_puts(s, "\n<------------------ IRQ stats ------------------->\n");
- seq_printf(s, "%4s %4s %8s %8s %8s %8s\n", "CE_ID", "IRQ", "Request",
- "Free", "Enable", "Disable");
- for (i = 0; i < ICNSS_MAX_IRQ_REGISTRATIONS; i++)
- seq_printf(s, "%4d: %4u %8u %8u %8u %8u\n", i,
- priv->ce_irqs[i], priv->stats.ce_irqs[i].request,
- priv->stats.ce_irqs[i].free,
- priv->stats.ce_irqs[i].enable,
- priv->stats.ce_irqs[i].disable);
- return 0;
- }
- static int icnss_stats_show_capability(struct seq_file *s,
- struct icnss_priv *priv)
- {
- if (test_bit(ICNSS_FW_READY, &priv->state)) {
- seq_puts(s, "\n<---------------- FW Capability ----------------->\n");
- seq_printf(s, "Chip ID: 0x%x\n", priv->chip_info.chip_id);
- seq_printf(s, "Chip family: 0x%x\n",
- priv->chip_info.chip_family);
- seq_printf(s, "Board ID: 0x%x\n", priv->board_id);
- seq_printf(s, "SOC Info: 0x%x\n", priv->soc_id);
- seq_printf(s, "Firmware Version: 0x%x\n",
- priv->fw_version_info.fw_version);
- seq_printf(s, "Firmware Build Timestamp: %s\n",
- priv->fw_version_info.fw_build_timestamp);
- seq_printf(s, "Firmware Build ID: %s\n",
- priv->fw_build_id);
- seq_printf(s, "RD card chain cap: %d\n",
- priv->rd_card_chain_cap);
- seq_printf(s, "PHY HE channel width cap: %d\n",
- priv->phy_he_channel_width_cap);
- seq_printf(s, "PHY QAM cap: %d\n",
- priv->phy_qam_cap);
- }
- return 0;
- }
- static int icnss_stats_show_events(struct seq_file *s, struct icnss_priv *priv)
- {
- int i;
- seq_puts(s, "\n<----------------- Events stats ------------------->\n");
- seq_printf(s, "%24s %16s %16s\n", "Events", "Posted", "Processed");
- for (i = 0; i < ICNSS_DRIVER_EVENT_MAX; i++)
- seq_printf(s, "%24s %16u %16u\n",
- icnss_driver_event_to_str(i),
- priv->stats.events[i].posted,
- priv->stats.events[i].processed);
- return 0;
- }
- static u64 icnss_get_serial_id(struct icnss_priv *priv)
- {
- u32 msb = priv->serial_id.serial_id_msb;
- u32 lsb = priv->serial_id.serial_id_lsb;
- msb &= 0xFFFF;
- return (((u64)msb << 32) | lsb);
- }
- static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
- {
- enum icnss_driver_state i;
- int skip = 0;
- unsigned long state;
- seq_printf(s, "\nSerial Number: 0x%llx", icnss_get_serial_id(priv));
- seq_printf(s, "\nState: 0x%lx(", priv->state);
- for (i = 0, state = priv->state; state != 0; state >>= 1, i++) {
- if (!(state & 0x1))
- continue;
- if (skip++)
- seq_puts(s, " | ");
- switch (i) {
- case ICNSS_WLFW_CONNECTED:
- seq_puts(s, "FW CONN");
- continue;
- case ICNSS_POWER_ON:
- seq_puts(s, "POWER ON");
- continue;
- case ICNSS_FW_READY:
- seq_puts(s, "FW READY");
- continue;
- case ICNSS_DRIVER_PROBED:
- seq_puts(s, "DRIVER PROBED");
- continue;
- case ICNSS_FW_TEST_MODE:
- seq_puts(s, "FW TEST MODE");
- continue;
- case ICNSS_PM_SUSPEND:
- seq_puts(s, "PM SUSPEND");
- continue;
- case ICNSS_PM_SUSPEND_NOIRQ:
- seq_puts(s, "PM SUSPEND NOIRQ");
- continue;
- case ICNSS_SSR_REGISTERED:
- seq_puts(s, "SSR REGISTERED");
- continue;
- case ICNSS_PDR_REGISTERED:
- seq_puts(s, "PDR REGISTERED");
- continue;
- case ICNSS_PD_RESTART:
- seq_puts(s, "PD RESTART");
- continue;
- case ICNSS_WLFW_EXISTS:
- seq_puts(s, "WLAN FW EXISTS");
- continue;
- case ICNSS_SHUTDOWN_DONE:
- seq_puts(s, "SHUTDOWN DONE");
- continue;
- case ICNSS_HOST_TRIGGERED_PDR:
- seq_puts(s, "HOST TRIGGERED PDR");
- continue;
- case ICNSS_FW_DOWN:
- seq_puts(s, "FW DOWN");
- continue;
- case ICNSS_DRIVER_UNLOADING:
- seq_puts(s, "DRIVER UNLOADING");
- continue;
- case ICNSS_REJUVENATE:
- seq_puts(s, "FW REJUVENATE");
- continue;
- case ICNSS_MODE_ON:
- seq_puts(s, "MODE ON DONE");
- continue;
- case ICNSS_BLOCK_SHUTDOWN:
- seq_puts(s, "BLOCK SHUTDOWN");
- continue;
- case ICNSS_PDR:
- seq_puts(s, "PDR TRIGGERED");
- continue;
- case ICNSS_IMS_CONNECTED:
- seq_puts(s, "IMS_CONNECTED");
- continue;
- case ICNSS_DEL_SERVER:
- seq_puts(s, "DEL SERVER");
- continue;
- case ICNSS_COLD_BOOT_CAL:
- seq_puts(s, "COLD BOOT CALIBRATION");
- continue;
- case ICNSS_QMI_DMS_CONNECTED:
- seq_puts(s, "DMS_CONNECTED");
- continue;
- case ICNSS_SLATE_SSR_REGISTERED:
- seq_puts(s, "SLATE SSR REGISTERED");
- continue;
- case ICNSS_SLATE_UP:
- seq_puts(s, "ICNSS SLATE UP");
- continue;
- case ICNSS_SLATE_READY:
- seq_puts(s, "ICNSS SLATE READY");
- continue;
- case ICNSS_LOW_POWER:
- seq_puts(s, "ICNSS LOW POWER");
- }
- seq_printf(s, "UNKNOWN-%d", i);
- }
- seq_puts(s, ")\n");
- return 0;
- }
- #define ICNSS_STATS_DUMP(_s, _priv, _x) \
- seq_printf(_s, "%24s: %u\n", #_x, _priv->stats._x)
- static int icnss_stats_show(struct seq_file *s, void *data)
- {
- struct icnss_priv *priv = s->private;
- ICNSS_STATS_DUMP(s, priv, ind_register_req);
- ICNSS_STATS_DUMP(s, priv, ind_register_resp);
- ICNSS_STATS_DUMP(s, priv, ind_register_err);
- ICNSS_STATS_DUMP(s, priv, cap_req);
- ICNSS_STATS_DUMP(s, priv, cap_resp);
- ICNSS_STATS_DUMP(s, priv, cap_err);
- ICNSS_STATS_DUMP(s, priv, pin_connect_result);
- ICNSS_STATS_DUMP(s, priv, cfg_req);
- ICNSS_STATS_DUMP(s, priv, cfg_resp);
- ICNSS_STATS_DUMP(s, priv, cfg_req_err);
- ICNSS_STATS_DUMP(s, priv, mode_req);
- ICNSS_STATS_DUMP(s, priv, mode_resp);
- ICNSS_STATS_DUMP(s, priv, mode_req_err);
- ICNSS_STATS_DUMP(s, priv, ini_req);
- ICNSS_STATS_DUMP(s, priv, ini_resp);
- ICNSS_STATS_DUMP(s, priv, ini_req_err);
- ICNSS_STATS_DUMP(s, priv, recovery.pdr_fw_crash);
- ICNSS_STATS_DUMP(s, priv, recovery.pdr_host_error);
- ICNSS_STATS_DUMP(s, priv, recovery.root_pd_crash);
- ICNSS_STATS_DUMP(s, priv, recovery.root_pd_shutdown);
- seq_puts(s, "\n<------------------ PM stats ------------------->\n");
- ICNSS_STATS_DUMP(s, priv, pm_suspend);
- ICNSS_STATS_DUMP(s, priv, pm_suspend_err);
- ICNSS_STATS_DUMP(s, priv, pm_resume);
- ICNSS_STATS_DUMP(s, priv, pm_resume_err);
- ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq);
- ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq_err);
- ICNSS_STATS_DUMP(s, priv, pm_resume_noirq);
- ICNSS_STATS_DUMP(s, priv, pm_resume_noirq_err);
- ICNSS_STATS_DUMP(s, priv, pm_stay_awake);
- ICNSS_STATS_DUMP(s, priv, pm_relax);
- if (priv->device_id == ADRASTEA_DEVICE_ID) {
- seq_puts(s, "\n<------------------ MSA stats ------------------->\n");
- ICNSS_STATS_DUMP(s, priv, msa_info_req);
- ICNSS_STATS_DUMP(s, priv, msa_info_resp);
- ICNSS_STATS_DUMP(s, priv, msa_info_err);
- ICNSS_STATS_DUMP(s, priv, msa_ready_req);
- ICNSS_STATS_DUMP(s, priv, msa_ready_resp);
- ICNSS_STATS_DUMP(s, priv, msa_ready_err);
- ICNSS_STATS_DUMP(s, priv, msa_ready_ind);
- seq_puts(s, "\n<------------------ Rejuvenate stats ------------------->\n");
- ICNSS_STATS_DUMP(s, priv, rejuvenate_ind);
- ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
- ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
- ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
- icnss_stats_show_rejuvenate_info(s, priv);
- }
- icnss_stats_show_irqs(s, priv);
- icnss_stats_show_capability(s, priv);
- icnss_stats_show_events(s, priv);
- icnss_stats_show_state(s, priv);
- return 0;
- }
- static int icnss_stats_open(struct inode *inode, struct file *file)
- {
- return single_open(file, icnss_stats_show, inode->i_private);
- }
- static const struct file_operations icnss_stats_fops = {
- .read = seq_read,
- .write = icnss_stats_write,
- .release = single_release,
- .open = icnss_stats_open,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- };
- static int icnss_fw_debug_show(struct seq_file *s, void *data)
- {
- struct icnss_priv *priv = s->private;
- seq_puts(s, "\nUsage: echo <CMD> <VAL> > <DEBUGFS>/icnss/fw_debug\n");
- seq_puts(s, "\nCMD: test_mode\n");
- seq_puts(s, " VAL: 0 (Test mode disable)\n");
- seq_puts(s, " VAL: 1 (WLAN FW test)\n");
- seq_puts(s, " VAL: 2 (CCPM test)\n");
- seq_puts(s, " VAL: 3 (Trigger Recovery)\n");
- seq_puts(s, " VAL: 4 (allow recursive recovery)\n");
- seq_puts(s, " VAL: 5 (Disallow recursive recovery)\n");
- seq_puts(s, " VAL: 6 (Trigger power supply callback)\n");
- seq_puts(s, "\nCMD: dynamic_feature_mask\n");
- seq_puts(s, " VAL: (64 bit feature mask)\n");
- if (!test_bit(ICNSS_FW_READY, &priv->state)) {
- seq_puts(s, "Firmware is not ready yet, can't run test_mode!\n");
- goto out;
- }
- if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
- seq_puts(s, "Machine mode is running, can't run test_mode!\n");
- goto out;
- }
- if (test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
- seq_puts(s, "test_mode is running, can't run test_mode!\n");
- goto out;
- }
- out:
- seq_puts(s, "\n");
- return 0;
- }
- static int icnss_test_mode_fw_test_off(struct icnss_priv *priv)
- {
- int ret;
- if (!test_bit(ICNSS_FW_READY, &priv->state)) {
- icnss_pr_err("Firmware is not ready yet!, wait for FW READY: state: 0x%lx\n",
- priv->state);
- ret = -ENODEV;
- goto out;
- }
- if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
- icnss_pr_err("Machine mode is running, can't run test mode: state: 0x%lx\n",
- priv->state);
- ret = -EINVAL;
- goto out;
- }
- if (!test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
- icnss_pr_err("Test mode not started, state: 0x%lx\n",
- priv->state);
- ret = -EINVAL;
- goto out;
- }
- icnss_wlan_disable(&priv->pdev->dev, ICNSS_OFF);
- ret = icnss_hw_power_off(priv);
- clear_bit(ICNSS_FW_TEST_MODE, &priv->state);
- out:
- return ret;
- }
- static int icnss_test_mode_fw_test(struct icnss_priv *priv,
- enum icnss_driver_mode mode)
- {
- int ret;
- if (!test_bit(ICNSS_FW_READY, &priv->state)) {
- icnss_pr_err("Firmware is not ready yet!, wait for FW READY, state: 0x%lx\n",
- priv->state);
- ret = -ENODEV;
- goto out;
- }
- if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
- icnss_pr_err("Machine mode is running, can't run test mode, state: 0x%lx\n",
- priv->state);
- ret = -EINVAL;
- goto out;
- }
- if (test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
- icnss_pr_err("Test mode already started, state: 0x%lx\n",
- priv->state);
- ret = -EBUSY;
- goto out;
- }
- ret = icnss_hw_power_on(priv);
- if (ret)
- goto out;
- set_bit(ICNSS_FW_TEST_MODE, &priv->state);
- ret = icnss_wlan_enable(&priv->pdev->dev, NULL, mode, NULL);
- if (ret)
- goto power_off;
- return 0;
- power_off:
- icnss_hw_power_off(priv);
- clear_bit(ICNSS_FW_TEST_MODE, &priv->state);
- out:
- return ret;
- }
- static ssize_t icnss_fw_debug_write(struct file *fp,
- const char __user *user_buf,
- size_t count, loff_t *off)
- {
- struct icnss_priv *priv =
- ((struct seq_file *)fp->private_data)->private;
- char buf[64];
- char *sptr, *token;
- unsigned int len = 0;
- char *cmd;
- uint64_t val;
- const char *delim = " ";
- int ret = 0;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
- buf[len] = '\0';
- sptr = buf;
- token = strsep(&sptr, delim);
- if (!token)
- return -EINVAL;
- if (!sptr)
- return -EINVAL;
- cmd = token;
- token = strsep(&sptr, delim);
- if (!token)
- return -EINVAL;
- if (kstrtou64(token, 0, &val))
- return -EINVAL;
- if (strcmp(cmd, "test_mode") == 0) {
- switch (val) {
- case 0:
- ret = icnss_test_mode_fw_test_off(priv);
- break;
- case 1:
- ret = icnss_test_mode_fw_test(priv, ICNSS_WALTEST);
- break;
- case 2:
- ret = icnss_test_mode_fw_test(priv, ICNSS_CCPM);
- break;
- case 3:
- ret = icnss_trigger_recovery(&priv->pdev->dev);
- break;
- case 4:
- icnss_allow_recursive_recovery(&priv->pdev->dev);
- break;
- case 5:
- icnss_disallow_recursive_recovery(&priv->pdev->dev);
- break;
- case 6:
- power_supply_changed(priv->batt_psy);
- break;
- default:
- return -EINVAL;
- }
- } else if (strcmp(cmd, "dynamic_feature_mask") == 0) {
- ret = wlfw_dynamic_feature_mask_send_sync_msg(priv, val);
- } else {
- return -EINVAL;
- }
- if (ret)
- return ret;
- return count;
- }
- static int icnss_fw_debug_open(struct inode *inode, struct file *file)
- {
- return single_open(file, icnss_fw_debug_show, inode->i_private);
- }
- static const struct file_operations icnss_fw_debug_fops = {
- .read = seq_read,
- .write = icnss_fw_debug_write,
- .release = single_release,
- .open = icnss_fw_debug_open,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- };
- static ssize_t icnss_control_params_debug_write(struct file *fp,
- const char __user *user_buf,
- size_t count, loff_t *off)
- {
- struct icnss_priv *priv =
- ((struct seq_file *)fp->private_data)->private;
- char buf[64];
- char *sptr, *token;
- char *cmd;
- u32 val;
- unsigned int len = 0;
- const char *delim = " ";
- if (!priv)
- return -ENODEV;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
- buf[len] = '\0';
- sptr = buf;
- token = strsep(&sptr, delim);
- if (!token)
- return -EINVAL;
- if (!sptr)
- return -EINVAL;
- cmd = token;
- token = strsep(&sptr, delim);
- if (!token)
- return -EINVAL;
- if (kstrtou32(token, 0, &val))
- return -EINVAL;
- if (strcmp(cmd, "qmi_timeout") == 0)
- priv->ctrl_params.qmi_timeout = msecs_to_jiffies(val);
- else
- return -EINVAL;
- return count;
- }
- static int icnss_control_params_debug_show(struct seq_file *s, void *data)
- {
- struct icnss_priv *priv = s->private;
- seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs>/icnss/control_params\n");
- seq_puts(s, "<params_name> can be from below:\n");
- seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
- seq_puts(s, "\nCurrent value:\n");
- seq_printf(s, "qmi_timeout: %u\n", jiffies_to_msecs(priv->ctrl_params.qmi_timeout));
- return 0;
- }
- static int icnss_control_params_debug_open(struct inode *inode,
- struct file *file)
- {
- return single_open(file, icnss_control_params_debug_show,
- inode->i_private);
- }
- static const struct file_operations icnss_control_params_debug_fops = {
- .read = seq_read,
- .write = icnss_control_params_debug_write,
- .release = single_release,
- .open = icnss_control_params_debug_open,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- };
- #ifdef CONFIG_ICNSS2_DEBUG
- int icnss_debugfs_create(struct icnss_priv *priv)
- {
- int ret = 0;
- struct dentry *root_dentry;
- root_dentry = debugfs_create_dir("icnss", NULL);
- if (IS_ERR(root_dentry)) {
- ret = PTR_ERR(root_dentry);
- icnss_pr_err("Unable to create debugfs %d\n", ret);
- goto out;
- }
- priv->root_dentry = root_dentry;
- debugfs_create_file("fw_debug", 0600, root_dentry, priv,
- &icnss_fw_debug_fops);
- debugfs_create_file("stats", 0600, root_dentry, priv,
- &icnss_stats_fops);
- debugfs_create_file("reg_read", 0600, root_dentry, priv,
- &icnss_regread_fops);
- debugfs_create_file("reg_write", 0600, root_dentry, priv,
- &icnss_regwrite_fops);
- debugfs_create_file("control_params", 0600, root_dentry, priv,
- &icnss_control_params_debug_fops);
- out:
- return ret;
- }
- #else
- int icnss_debugfs_create(struct icnss_priv *priv)
- {
- int ret = 0;
- struct dentry *root_dentry;
- root_dentry = debugfs_create_dir("icnss", NULL);
- if (IS_ERR(root_dentry)) {
- ret = PTR_ERR(root_dentry);
- icnss_pr_err("Unable to create debugfs %d\n", ret);
- return ret;
- }
- priv->root_dentry = root_dentry;
- debugfs_create_file("stats", 0600, root_dentry, priv,
- &icnss_stats_fops);
- return 0;
- }
- #endif
- void icnss_debugfs_destroy(struct icnss_priv *priv)
- {
- debugfs_remove_recursive(priv->root_dentry);
- }
- void icnss_debug_init(void)
- {
- icnss_ipc_log_context = ipc_log_context_create(NUM_LOG_PAGES,
- "icnss", 0);
- 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");
- icnss_ipc_log_smp2p_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
- "icnss_smp2p", 0);
- if (!icnss_ipc_log_smp2p_context)
- icnss_pr_err("Unable to create log smp2p context\n");
- icnss_ipc_soc_wake_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
- "icnss_soc_wake", 0);
- if (!icnss_ipc_soc_wake_context)
- icnss_pr_err("Unable to create log soc_wake context\n");
- }
- void icnss_debug_deinit(void)
- {
- if (icnss_ipc_log_context) {
- ipc_log_context_destroy(icnss_ipc_log_context);
- icnss_ipc_log_context = NULL;
- }
- if (icnss_ipc_log_long_context) {
- ipc_log_context_destroy(icnss_ipc_log_long_context);
- icnss_ipc_log_long_context = NULL;
- }
- if (icnss_ipc_log_smp2p_context) {
- ipc_log_context_destroy(icnss_ipc_log_smp2p_context);
- icnss_ipc_log_smp2p_context = NULL;
- }
- if (icnss_ipc_soc_wake_context) {
- ipc_log_context_destroy(icnss_ipc_soc_wake_context);
- icnss_ipc_soc_wake_context = NULL;
- }
- }
|