cnss2: Sync code from kernel 4.14

Sync cnss2 codes to kernel 4.9 from kernel 4.14 for
qca6595 and qca6696. The code from 4.14 is based on
the commit:a9567eae9d979dcf83e73ef4e31d4ecbdb553e70 in
msm-4.14. Because the APIs of qmi are not updated with
4.14, so keep these qmi interfaces.

Add the description of cnss-qca-converged in cnss-wlan.txt.

CRs-Fixed: 2685017
Change-Id: I88a6d3a7dd4bd8209cd7aa83336b48fc1f0371e0
Signed-off-by: Kuichu Ni <kuichun@codeaurora.org>
This commit is contained in:
Kuichu Ni 2020-04-30 16:50:53 +08:00 • committed by Gerrit - the friendly Code Review server
commit 63adfad31b
19 changed files with 3491 additions and 564 deletions

View file

@ -14,6 +14,7 @@ Required properties:
- compatible: "qcom,cnss" for QCA6174 device
"qcom,cnss-qca6290" for QCA6290 device
"qcom,cnss-qca6390" for QCA6390 device
"qcom,cnss-qca-converged" for converged QCA devices
- wlan-en-gpio: WLAN_EN GPIO signal specified by the chip specifications
- vdd-wlan-supply: phandle to the regulator device tree node
- pinctrl-names: Names corresponding to the numbered pinctrl states
@ -35,6 +36,10 @@ Optional properties:
- vdd-wlan-xtal-aon-supply: phandle to the LDO-4 regulator. This is needed
on platforms where XTAL regulator depends on
always on regulator in VDDmin.
- vdd-wlan-ctrl1-supply: phandle to the DBU1 - 1.8V for QCA6595 or 3.3V for
QCA6174 on auto platform.
- vdd-wlan-ctrl2-supply: phandle to the DBU4 - 2.2V for QCA6595 or 3.85V for
QCA6696 on auto platform.
- vdd-wlan-core-supply: phandle to the 1.3V CORE regulator for QCA6174
- vdd-wlan-sp2t-supply: phandle to the 2.7V SP2T regulator for QCA6174
- qcom,smmu-s1-enable: Boolean property to decide whether to enable SMMU
@ -56,7 +61,32 @@ Optional properties:
WLAN_EN pin is a gpio or fixed regulator.
- qcom,mhi: phandle to indicate the device which needs MHI support.
- qcom,cap-tsf-gpio: WLAN_TSF_CAPTURED GPIO signal specified by the chip
specifications, should be drived depending on products
specifications, should be drived depending on products.
- cnss-daemon-support: Boolean property to decide whether cnss_daemon
userspace QMI client is supported.
- qcom,converged-dt: Boolean property to decide whether it supports multiple
chips.
- qcom,bus-type: U32 property to specify the bus type, is required when
'qcom,converged-dt' being present.
- wlan_vregs: String array to decide which vregs are required, is required
when 'qcom,converged-dt' being present.
- <supply-name>-supply: phandle to the regulator device tree node.
optional "supply-name" is "vdd-wlan-rfa".
- qcom,<supply-name>-info: Specifies configuration for supply. Should be
specified in <min_uV max_uV load_uA delay_us>.
- pcie-disable-l1: Boolean property to decide whether to disable PCIe L1 PM.
- pcie-disable-l1ss: Boolean property to decide whether to disable PCIe L1ss.
- qcom,set-wlaon-pwr-ctrl: Boolean property to indicate if set
WLAON_QFPROM_PWR_CTRL_REG register during power on
and off sequences.
List of chip specific sub nodes:
- chip_cfg@X: represent chip specific configurations
Each sub node has the following required properties:
- wlan_vregs: String array to decide which vregs are required, property
being present but no values means no additional vregs.
- supported-ids: U32 array to decide which device ids are supported by
sub node.
Example:
@ -76,3 +106,27 @@ Example:
qcom,mhi = <&mhi_wlan>;
qcom,cap-tsf-gpio = <&tlmm 126 1>;
};
qcom,cnss-qca-converged {
compatible = "qcom,cnss-qca-converged";
qcom,converged-dt;
qcom,bus-type=<0>;
vdd-wlan-ctrl1-supply = <&vreg_conn_pa>;
vdd-wlan-ctrl2-supply = <&vreg_conn_1p8>;
vdd-wlan-supply = <&vreg_wlan>;
wlan_vregs = "vdd-wlan-ctrl1", "vdd-wlan-ctrl2";
qcom,vdd-wlan-ctrl1-info = <0 0 0 0>;
qcom,vdd-wlan-ctrl2-info = <0 0 0 0>;
wlan-en-gpio = <&tlmm 169 0>;
pinctrl-names = "wlan_en_active", "wlan_en_sleep";
pinctrl-0 = <&cnss_wlan_en_active>;
pinctrl-1 = <&cnss_wlan_en_sleep>;
qcom,wlan-rc-num = <0>;
chip_cfg@1 {
supported-ids = <0x003e>;
wlan_vregs = "vdd-wlan";
qcom,vdd-wlan-info = <0 0 0 10>;
};
};

View file

@ -6,4 +6,5 @@ cnss2-y += debug.o
cnss2-y += pci.o
cnss2-y += usb.o
cnss2-y += power.o
cnss2-$(CONFIG_CNSS2_DEBUG) += genl.o
cnss2-$(CONFIG_CNSS2_QMI) += qmi.o wlan_firmware_service_v01.o

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -29,40 +29,52 @@ enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
return CNSS_BUS_NONE;
}
enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id)
enum cnss_dev_bus_type cnss_get_bus_type(struct cnss_plat_data *plat_priv)
{
switch (device_id) {
int ret;
struct device *dev;
u32 bus_type = CNSS_BUS_NONE;
if (plat_priv->is_converged_dt) {
dev = &plat_priv->plat_dev->dev;
ret = of_property_read_u32(dev->of_node, "qcom,bus-type",
&bus_type);
if (!ret)
cnss_pr_dbg("Got bus type[%u] from dt\n", bus_type);
else
cnss_pr_err("No bus type for converged dt\n");
return bus_type;
}
/* Get bus type according to device id if it's not converged DT */
switch (plat_priv->device_id) {
case QCA6174_DEVICE_ID:
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
return CNSS_BUS_PCI;
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
bus_type = CNSS_BUS_PCI;
break;
case QCN7605_COMPOSITE_DEVICE_ID:
case QCN7605_STANDALONE_DEVICE_ID:
return CNSS_BUS_USB;
bus_type = CNSS_BUS_USB;
break;
default:
cnss_pr_err("Unknown device_id: 0x%lx\n", device_id);
return CNSS_BUS_NONE;
cnss_pr_err("Unknown device: 0x%lx\n", plat_priv->device_id);
break;
}
return bus_type;
}
bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv)
{
if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_USB)
if (cnss_get_bus_type(plat_priv) == CNSS_BUS_USB)
return false;
else
return true;
}
bool cnss_bus_dev_cal_rep_valid(struct cnss_plat_data *plat_priv)
{
bool ret = false;
if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_USB)
ret = true;
return ret;
}
void *cnss_bus_dev_to_bus_priv(struct device *dev)
{
if (!dev)
@ -161,6 +173,37 @@ int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv)
}
}
int cnss_bus_alloc_qdss_mem(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_alloc_qdss_mem(plat_priv->bus_priv);
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
void cnss_bus_free_qdss_mem(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
cnss_pci_free_qdss_mem(plat_priv->bus_priv);
return;
default:
cnss_pr_err("Unsupported bus type: %d\n",
plat_priv->bus_type);
return;
}
}
u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
@ -388,3 +431,18 @@ int cnss_bus_update_status(struct cnss_plat_data *plat_priv,
return -EINVAL;
}
}
int cnss_get_msi_assignment(struct cnss_plat_data *plat_priv,
char *msi_name,
int *num_vectors, u32 *user_base_data,
u32 *base_vector)
{
struct cnss_pci_data *pci_priv;
pci_priv = plat_priv->bus_priv;
return cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
msi_name,
num_vectors,
user_base_data,
base_vector);
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -22,27 +22,28 @@
#define QCA6174_REV3_2_VERSION 0x5030000
#define QCA6290_VENDOR_ID 0x17CB
#define QCA6290_DEVICE_ID 0x1100
#define QCA6290_EMULATION_VENDOR_ID 0x168C
#define QCA6290_EMULATION_DEVICE_ID 0xABCD
#define QCA6390_VENDOR_ID 0x17CB
#define QCA6390_EMULATION_DEVICE_ID 0x0108
#define QCA6390_DEVICE_ID 0x1101
#define QCN7605_VENDOR_ID 0x17CB
#define QCN7605_DEVICE_ID 0x1102
#define QCN7605_USB_VENDOR_ID 0x05C6
#define QCN7605_COMPOSITE_DEVICE_ID QCN7605_COMPOSITE_PRODUCT_ID
#define QCN7605_STANDALONE_DEVICE_ID QCN7605_STANDALONE_PRODUCT_ID
#define QCN7605_STANDALONE_PRODUCT_ID 0x9900
#define QCN7605_COMPOSITE_PRODUCT_ID 0x9901
#define QCN7605_COMPOSITE_DEVICE_ID QCN7605_COMPOSITE_PRODUCT_ID
#define QCN7605_STANDALONE_DEVICE_ID QCN7605_STANDALONE_PRODUCT_ID
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);
enum cnss_dev_bus_type cnss_get_bus_type(struct cnss_plat_data *plat_priv);
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);
int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv);
int cnss_bus_alloc_qdss_mem(struct cnss_plat_data *plat_priv);
void cnss_bus_free_qdss_mem(struct cnss_plat_data *plat_priv);
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);
@ -60,8 +61,10 @@ int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
int modem_current_status);
int cnss_bus_update_status(struct cnss_plat_data *plat_priv,
enum cnss_driver_status status);
int cnss_bus_recovery_update_status(struct cnss_plat_data *plat_priv);
bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv);
bool cnss_bus_dev_cal_rep_valid(struct cnss_plat_data *plat_priv);
int cnss_get_msi_assignment(struct cnss_plat_data *plat_priv,
char *msi_name,
int *num_vectors,
u32 *user_base_data,
u32 *base_vector);
#endif /* _CNSS_BUS_H */

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -85,6 +85,12 @@ static int cnss_stats_show_state(struct seq_file *s,
case CNSS_DRIVER_UNLOADING:
seq_puts(s, "DRIVER_UNLOADING");
continue;
case CNSS_DRIVER_IDLE_RESTART:
seq_puts(s, "IDLE_RESTART");
continue;
case CNSS_DRIVER_IDLE_SHUTDOWN:
seq_puts(s, "IDLE_SHUTDOWN");
continue;
case CNSS_DRIVER_PROBED:
seq_puts(s, "DRIVER_PROBED");
continue;
@ -100,6 +106,9 @@ static int cnss_stats_show_state(struct seq_file *s,
case CNSS_DRIVER_DEBUG:
seq_puts(s, "DRIVER_DEBUG");
continue;
case CNSS_IN_SUSPEND_RESUME:
seq_puts(s, "IN_SUSPEND_RESUME");
continue;
}
seq_printf(s, "UNKNOWN-%d", i);
@ -504,6 +513,145 @@ static const struct file_operations cnss_runtime_pm_debug_fops = {
.llseek = seq_lseek,
};
static ssize_t cnss_control_params_debug_write(struct file *fp,
const char __user *user_buf,
size_t count, loff_t *off)
{
struct cnss_plat_data *plat_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 (!plat_priv)
return -ENODEV;
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;
cmd = token;
token = strsep(&sptr, delim);
if (!token)
return -EINVAL;
if (kstrtou32(token, 0, &val))
return -EINVAL;
if (strcmp(cmd, "quirks") == 0)
plat_priv->ctrl_params.quirks = val;
else if (strcmp(cmd, "mhi_timeout") == 0)
plat_priv->ctrl_params.mhi_timeout = val;
else if (strcmp(cmd, "qmi_timeout") == 0)
plat_priv->ctrl_params.qmi_timeout = val;
else if (strcmp(cmd, "bdf_type") == 0)
plat_priv->ctrl_params.bdf_type = val;
else
return -EINVAL;
return count;
}
static int cnss_show_quirks_state(struct seq_file *s,
struct cnss_plat_data *plat_priv)
{
enum cnss_debug_quirks i;
int skip = 0;
unsigned long state;
seq_printf(s, "quirks: 0x%lx (", plat_priv->ctrl_params.quirks);
for (i = 0, state = plat_priv->ctrl_params.quirks;
state != 0; state >>= 1, i++) {
if (!(state & 0x1))
continue;
if (skip++)
seq_puts(s, " | ");
switch (i) {
case LINK_DOWN_SELF_RECOVERY:
seq_puts(s, "LINK_DOWN_SELF_RECOVERY");
continue;
case SKIP_DEVICE_BOOT:
seq_puts(s, "SKIP_DEVICE_BOOT");
continue;
case USE_CORE_ONLY_FW:
seq_puts(s, "USE_CORE_ONLY_FW");
continue;
case SKIP_RECOVERY:
seq_puts(s, "SKIP_RECOVERY");
continue;
case QMI_BYPASS:
seq_puts(s, "QMI_BYPASS");
continue;
case ENABLE_WALTEST:
seq_puts(s, "WALTEST");
continue;
case ENABLE_PCI_LINK_DOWN_PANIC:
seq_puts(s, "PCI_LINK_DOWN_PANIC");
continue;
case FBC_BYPASS:
seq_puts(s, "FBC_BYPASS");
continue;
case ENABLE_DAEMON_SUPPORT:
seq_puts(s, "DAEMON_SUPPORT");
continue;
case IGNORE_PCI_LINK_FAILURE:
seq_puts(s, "IGNORE_PCI_LINK_FAILURE");
continue;
}
seq_printf(s, "UNKNOWN-%d", i);
}
seq_puts(s, ")\n");
return 0;
}
static int cnss_control_params_debug_show(struct seq_file *s, void *data)
{
struct cnss_plat_data *cnss_priv = s->private;
seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs_path>/cnss/control_params\n");
seq_puts(s, "<params_name> can be one of below:\n");
seq_puts(s, "quirks: Debug quirks for driver\n");
seq_puts(s, "mhi_timeout: Timeout for MHI operation in milliseconds\n");
seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
seq_puts(s, "bdf_type: Type of board data file to be downloaded\n");
seq_puts(s, "\nCurrent value:\n");
cnss_show_quirks_state(s, cnss_priv);
seq_printf(s, "mhi_timeout: %u\n", cnss_priv->ctrl_params.mhi_timeout);
seq_printf(s, "qmi_timeout: %u\n", cnss_priv->ctrl_params.qmi_timeout);
seq_printf(s, "bdf_type: %u\n", cnss_priv->ctrl_params.bdf_type);
return 0;
}
static int cnss_control_params_debug_open(struct inode *inode,
struct file *file)
{
return single_open(file, cnss_control_params_debug_show,
inode->i_private);
}
static const struct file_operations cnss_control_params_debug_fops = {
.read = seq_read,
.write = cnss_control_params_debug_write,
.open = cnss_control_params_debug_open,
.owner = THIS_MODULE,
.llseek = seq_lseek,
};
#ifdef CONFIG_CNSS2_DEBUG
static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
{
@ -517,6 +665,8 @@ static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
&cnss_reg_write_debug_fops);
debugfs_create_file("runtime_pm", 0600, root_dentry, plat_priv,
&cnss_runtime_pm_debug_fops);
debugfs_create_file("control_params", 0600, root_dentry, plat_priv,
&cnss_control_params_debug_fops);
return 0;
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -63,6 +63,9 @@ extern void *cnss_ipc_log_context;
} while (0)
#endif
#define cnss_fatal_err(_fmt, ...) \
cnss_pr_err("fatal: " _fmt, ##__VA_ARGS__)
int cnss_debug_init(void);
void cnss_debug_deinit(void);
int cnss_debugfs_create(struct cnss_plat_data *plat_priv);

View file

@ -0,0 +1,213 @@
/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) "cnss_genl: " fmt
#include <linux/err.h>
#include <linux/module.h>
#include <net/netlink.h>
#include <net/genetlink.h>
#include "main.h"
#include "debug.h"
#include "genl.h"
#define CNSS_GENL_FAMILY_NAME "cnss-genl"
#define CNSS_GENL_MCAST_GROUP_NAME "cnss-genl-grp"
#define CNSS_GENL_VERSION 1
#define CNSS_GENL_DATA_LEN_MAX (15 * 1024)
#define CNSS_GENL_STR_LEN_MAX 16
enum {
CNSS_GENL_ATTR_MSG_UNSPEC,
CNSS_GENL_ATTR_MSG_TYPE,
CNSS_GENL_ATTR_MSG_FILE_NAME,
CNSS_GENL_ATTR_MSG_TOTAL_SIZE,
CNSS_GENL_ATTR_MSG_SEG_ID,
CNSS_GENL_ATTR_MSG_END,
CNSS_GENL_ATTR_MSG_DATA_LEN,
CNSS_GENL_ATTR_MSG_DATA,
__CNSS_GENL_ATTR_MAX,
};
#define CNSS_GENL_ATTR_MAX (__CNSS_GENL_ATTR_MAX - 1)
enum {
CNSS_GENL_CMD_UNSPEC,
CNSS_GENL_CMD_MSG,
__CNSS_GENL_CMD_MAX,
};
#define CNSS_GENL_CMD_MAX (__CNSS_GENL_CMD_MAX - 1)
static struct nla_policy cnss_genl_msg_policy[CNSS_GENL_ATTR_MAX + 1] = {
[CNSS_GENL_ATTR_MSG_TYPE] = { .type = NLA_U8 },
[CNSS_GENL_ATTR_MSG_FILE_NAME] = { .type = NLA_NUL_STRING,
.len = CNSS_GENL_STR_LEN_MAX },
[CNSS_GENL_ATTR_MSG_TOTAL_SIZE] = { .type = NLA_U32 },
[CNSS_GENL_ATTR_MSG_SEG_ID] = { .type = NLA_U32 },
[CNSS_GENL_ATTR_MSG_END] = { .type = NLA_U8 },
[CNSS_GENL_ATTR_MSG_DATA_LEN] = { .type = NLA_U32 },
[CNSS_GENL_ATTR_MSG_DATA] = { .type = NLA_BINARY,
.len = CNSS_GENL_DATA_LEN_MAX },
};
static int cnss_genl_process_msg(struct sk_buff *skb, struct genl_info *info)
{
return 0;
}
static struct genl_ops cnss_genl_ops[] = {
{
.cmd = CNSS_GENL_CMD_MSG,
.policy = cnss_genl_msg_policy,
.doit = cnss_genl_process_msg,
},
};
static struct genl_multicast_group cnss_genl_mcast_grp[] = {
{
.name = CNSS_GENL_MCAST_GROUP_NAME,
},
};
static struct genl_family cnss_genl_family = {
.id = 0,
.hdrsize = 0,
.name = CNSS_GENL_FAMILY_NAME,
.version = CNSS_GENL_VERSION,
.maxattr = CNSS_GENL_ATTR_MAX,
.module = THIS_MODULE,
.ops = cnss_genl_ops,
.n_ops = ARRAY_SIZE(cnss_genl_ops),
.mcgrps = cnss_genl_mcast_grp,
.n_mcgrps = ARRAY_SIZE(cnss_genl_mcast_grp),
};
static int cnss_genl_send_data(u8 type, char *file_name, u32 total_size,
u32 seg_id, u8 end, u32 data_len, u8 *msg_buff)
{
struct sk_buff *skb = NULL;
void *msg_header = NULL;
int ret = 0;
char filename[CNSS_GENL_STR_LEN_MAX + 1];
cnss_pr_dbg("type: %u, file_name %s, total_size: %x, seg_id %u, end %u, data_len %u\n",
type, file_name, total_size, seg_id, end, data_len);
if (!file_name)
strlcpy(filename, "default", sizeof(filename));
else
strlcpy(filename, file_name, sizeof(filename));
skb = genlmsg_new(NLMSG_HDRLEN +
nla_total_size(sizeof(type)) +
nla_total_size(strlen(filename) + 1) +
nla_total_size(sizeof(total_size)) +
nla_total_size(sizeof(seg_id)) +
nla_total_size(sizeof(end)) +
nla_total_size(sizeof(data_len)) +
nla_total_size(data_len), GFP_KERNEL);
if (!skb)
return -ENOMEM;
msg_header = genlmsg_put(skb, 0, 0,
&cnss_genl_family, 0,
CNSS_GENL_CMD_MSG);
if (!msg_header) {
ret = -ENOMEM;
goto fail;
}
ret = nla_put_u8(skb, CNSS_GENL_ATTR_MSG_TYPE, type);
if (ret < 0)
goto fail;
ret = nla_put_string(skb, CNSS_GENL_ATTR_MSG_FILE_NAME, filename);
if (ret < 0)
goto fail;
ret = nla_put_u32(skb, CNSS_GENL_ATTR_MSG_TOTAL_SIZE, total_size);
if (ret < 0)
goto fail;
ret = nla_put_u32(skb, CNSS_GENL_ATTR_MSG_SEG_ID, seg_id);
if (ret < 0)
goto fail;
ret = nla_put_u8(skb, CNSS_GENL_ATTR_MSG_END, end);
if (ret < 0)
goto fail;
ret = nla_put_u32(skb, CNSS_GENL_ATTR_MSG_DATA_LEN, data_len);
if (ret < 0)
goto fail;
ret = nla_put(skb, CNSS_GENL_ATTR_MSG_DATA, data_len, msg_buff);
if (ret < 0)
goto fail;
genlmsg_end(skb, msg_header);
ret = genlmsg_multicast(&cnss_genl_family, skb, 0, 0, GFP_KERNEL);
if (ret < 0)
cnss_pr_err("Fail to send genl msg: %d\n", ret);
return ret;
fail:
cnss_pr_err("Fail to generate genl msg: %d\n", ret);
if (skb)
nlmsg_free(skb);
return ret;
}
int cnss_genl_send_msg(void *buff, u8 type, char *file_name, u32 total_size)
{
int ret = 0;
u8 *msg_buff = buff;
u32 remaining = total_size;
u32 seg_id = 0;
u32 data_len = 0;
u8 end = 0;
cnss_pr_dbg("type: %u, total_size: %x\n", type, total_size);
while (remaining) {
if (remaining > CNSS_GENL_DATA_LEN_MAX) {
data_len = CNSS_GENL_DATA_LEN_MAX;
} else {
data_len = remaining;
end = 1;
}
ret = cnss_genl_send_data(type, file_name, total_size,
seg_id, end, data_len, msg_buff);
if (ret < 0) {
cnss_pr_err("fail to send genl data, ret %d\n", ret);
return ret;
}
remaining -= data_len;
msg_buff += data_len;
seg_id++;
}
return ret;
}
int cnss_genl_init(void)
{
int ret = 0;
ret = genl_register_family(&cnss_genl_family);
if (ret != 0)
cnss_pr_err("genl_register_family fail: %d\n", ret);
return ret;
}
void cnss_genl_exit(void)
{
genl_unregister_family(&cnss_genl_family);
}

View file

@ -0,0 +1,43 @@
/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __CNSS_GENL_H__
#define __CNSS_GENL_H__
enum cnss_genl_msg_type {
CNSS_GENL_MSG_TYPE_UNSPEC,
CNSS_GENL_MSG_TYPE_QDSS,
};
#ifdef CONFIG_CNSS2_DEBUG
int cnss_genl_init(void);
void cnss_genl_exit(void);
int cnss_genl_send_msg(void *buff, u8 type,
char *file_name, u32 total_size);
#else
static inline int cnss_genl_init(void)
{
return 0;
}
static inline void cnss_genl_exit(void)
{
}
static inline int cnss_genl_send_msg(void *buff, u8 type,
char *file_name, u32 total_size)
{
return 0;
}
#endif
#endif

View file

@ -25,6 +25,7 @@
#include "main.h"
#include "bus.h"
#include "debug.h"
#include "genl.h"
#define CNSS_DUMP_FORMAT_VER 0x11
#define CNSS_DUMP_FORMAT_VER_V2 0x22
@ -38,28 +39,18 @@
#define FW_ASSERT_TIMEOUT 5000
#define CNSS_EVENT_PENDING 2989
#ifdef CONFIG_CNSS_EMULATION
#define CNSS_MHI_TIMEOUT_DEFAULT 90000
#else
#define CNSS_MHI_TIMEOUT_DEFAULT 0
#endif
#define CNSS_QMI_TIMEOUT_DEFAULT 10000
#define CNSS_BDF_TYPE_DEFAULT CNSS_BDF_ELF
static struct cnss_plat_data *plat_env;
static DECLARE_RWSEM(cnss_pm_sem);
static bool qmi_bypass;
#ifdef CONFIG_CNSS2_DEBUG
module_param(qmi_bypass, bool, 0600);
MODULE_PARM_DESC(qmi_bypass, "Bypass QMI from platform driver");
#endif
static bool enable_waltest;
#ifdef CONFIG_CNSS2_DEBUG
module_param(enable_waltest, bool, 0600);
MODULE_PARM_DESC(enable_waltest, "Enable to handle firmware waltest");
#endif
unsigned long quirks;
#ifdef CONFIG_CNSS2_DEBUG
module_param(quirks, ulong, 0600);
MODULE_PARM_DESC(quirks, "Debug quirks for the driver");
#endif
static struct cnss_fw_files FW_FILES_QCA6174_FW_3_0 = {
"qwlan30.bin", "bdwlan30.bin", "otp30.bin", "utf30.bin",
"utfbd30.bin", "epping30.bin", "evicted30.bin"
@ -185,9 +176,11 @@ int cnss_request_bus_bandwidth(struct device *dev, int bandwidth)
switch (bandwidth) {
case CNSS_BUS_WIDTH_NONE:
case CNSS_BUS_WIDTH_IDLE:
case CNSS_BUS_WIDTH_LOW:
case CNSS_BUS_WIDTH_MEDIUM:
case CNSS_BUS_WIDTH_HIGH:
case CNSS_BUS_WIDTH_VERY_HIGH:
ret = msm_bus_scale_client_update_request(
bus_bw_info->bus_client, bandwidth);
if (!ret)
@ -252,10 +245,13 @@ int cnss_wlan_enable(struct device *dev,
if (!plat_priv)
return -ENODEV;
if (!plat_priv)
return -ENODEV;
if (plat_priv->device_id == QCA6174_DEVICE_ID)
return 0;
if (qmi_bypass)
if (test_bit(QMI_BYPASS, &plat_priv->ctrl_params.quirks))
return 0;
if (!config || !host_version) {
@ -269,6 +265,9 @@ int cnss_wlan_enable(struct device *dev,
if (mode == CNSS_WALTEST || mode == CNSS_CCPM)
goto skip_cfg;
if (plat_priv->device_id == QCN7605_DEVICE_ID)
config->send_msi_ce = true;
ret = cnss_wlfw_wlan_cfg_send_sync(plat_priv, config, host_version);
if (ret)
goto out;
@ -286,17 +285,19 @@ int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode)
if (!plat_priv)
return -ENODEV;
if (!plat_priv)
return -ENODEV;
if (plat_priv->device_id == QCA6174_DEVICE_ID)
return 0;
if (qmi_bypass)
if (test_bit(QMI_BYPASS, &plat_priv->ctrl_params.quirks))
return 0;
return cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF);
}
EXPORT_SYMBOL(cnss_wlan_disable);
#ifdef CONFIG_CNSS2_DEBUG
int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
u32 data_len, u8 *output)
{
@ -354,21 +355,6 @@ out:
return ret;
}
EXPORT_SYMBOL(cnss_athdiag_write);
#else
int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
u32 data_len, u8 *output)
{
return -EPERM;
}
EXPORT_SYMBOL(cnss_athdiag_read);
int cnss_athdiag_write(struct device *dev, u32 offset, u32 mem_type,
u32 data_len, u8 *input)
{
return -EPERM;
}
EXPORT_SYMBOL(cnss_athdiag_write);
#endif
int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
{
@ -376,6 +362,9 @@ int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
if (!plat_priv)
return -ENODEV;
if (!plat_priv)
return -ENODEV;
if (plat_priv->device_id == QCA6174_DEVICE_ID)
return 0;
@ -383,16 +372,6 @@ int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
}
EXPORT_SYMBOL(cnss_set_fw_log_mode);
bool *cnss_get_qmi_bypass(void)
{
return &qmi_bypass;
}
unsigned long *cnss_get_debug_quirks(void)
{
return &quirks;
}
static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@ -406,10 +385,19 @@ static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
if (ret)
goto out;
ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv);
cnss_wlfw_bdf_dnld_send_sync(plat_priv, CNSS_BDF_REGDB);
if (plat_priv->device_id == QCN7605_DEVICE_ID)
plat_priv->ctrl_params.bdf_type = CNSS_BDF_BIN;
ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv,
plat_priv->ctrl_params.bdf_type);
if (ret)
goto out;
if (plat_priv->device_id == QCN7605_DEVICE_ID)
return 0;
ret = cnss_bus_load_m3(plat_priv);
if (ret)
goto out;
@ -439,17 +427,14 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
}
if (enable_waltest) {
if (test_bit(ENABLE_WALTEST, &plat_priv->ctrl_params.quirks)) {
ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
CNSS_WALTEST);
} else if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) {
ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
CNSS_CALIBRATION);
} else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
ret = cnss_bus_call_driver_probe(plat_priv);
} else {
complete(&plat_priv->power_up_complete);
ret = cnss_bus_call_driver_probe(plat_priv);
}
if (ret && test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
@ -511,6 +496,16 @@ static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
return "POWER_UP";
case CNSS_DRIVER_EVENT_POWER_DOWN:
return "POWER_DOWN";
case CNSS_DRIVER_EVENT_IDLE_RESTART:
return "IDLE_RESTART";
case CNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
return "IDLE_SHUTDOWN";
case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM:
return "QDSS_TRACE_REQ_MEM";
case CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE:
return "QDSS_TRACE_SAVE";
case CNSS_DRIVER_EVENT_QDSS_TRACE_FREE:
return "QDSS_TRACE_FREE";
case CNSS_DRIVER_EVENT_MAX:
return "EVENT_MAX";
}
@ -590,7 +585,14 @@ out:
unsigned int cnss_get_boot_timeout(struct device *dev)
{
return cnss_get_qmi_timeout();
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL\n");
return 0;
}
return cnss_get_qmi_timeout(plat_priv);
}
EXPORT_SYMBOL(cnss_get_boot_timeout);
@ -653,13 +655,79 @@ EXPORT_SYMBOL(cnss_power_down);
int cnss_idle_restart(struct device *dev)
{
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
unsigned int timeout;
int ret = 0;
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL\n");
return -ENODEV;
}
cnss_pr_dbg("Doing idle restart\n");
ret = cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_IDLE_RESTART,
CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
if (ret)
goto out;
if (plat_priv->device_id == QCA6174_DEVICE_ID) {
ret = cnss_bus_call_driver_probe(plat_priv);
goto out;
}
timeout = cnss_get_boot_timeout(dev);
reinit_completion(&plat_priv->power_up_complete);
ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
msecs_to_jiffies(timeout) << 2);
if (!ret) {
cnss_pr_err("Timeout waiting for idle restart to complete\n");
ret = -EAGAIN;
goto out;
}
return 0;
out:
return ret;
}
EXPORT_SYMBOL(cnss_idle_restart);
int cnss_idle_shutdown(struct device *dev)
{
return 0;
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
int ret;
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL\n");
return -ENODEV;
}
if (test_bit(CNSS_IN_SUSPEND_RESUME, &plat_priv->driver_state)) {
cnss_pr_dbg("System suspend or resume in progress, ignore idle shutdown\n");
return -EAGAIN;
}
cnss_pr_dbg("Doing idle shutdown\n");
if (!test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
goto skip_wait;
reinit_completion(&plat_priv->recovery_complete);
ret = wait_for_completion_timeout(&plat_priv->recovery_complete,
RECOVERY_TIMEOUT);
if (!ret) {
cnss_pr_err("Timeout waiting for recovery to complete\n");
CNSS_ASSERT(0);
}
skip_wait:
return cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
}
EXPORT_SYMBOL(cnss_idle_shutdown);
@ -686,6 +754,8 @@ out:
static void cnss_put_resources(struct cnss_plat_data *plat_priv)
{
cnss_put_pinctrl(plat_priv);
cnss_put_vreg(plat_priv);
}
static int cnss_modem_notifier_nb(struct notifier_block *nb,
@ -780,9 +850,9 @@ static void cnss_unregister_esoc(struct cnss_plat_data *plat_priv)
esoc_info = &plat_priv->esoc_info;
if (esoc_info->notify_modem_status)
subsys_notif_unregister_notifier(esoc_info->
modem_notify_handler,
&plat_priv->modem_nb);
subsys_notif_unregister_notifier(
esoc_info->modem_notify_handler,
&plat_priv->modem_nb);
if (esoc_info->esoc_desc)
devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
}
@ -803,7 +873,7 @@ static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
}
if (!plat_priv->driver_state) {
cnss_pr_dbg("Powerup is ignored\n");
cnss_pr_dbg("subsys powerup is ignored\n");
return 0;
}
@ -827,7 +897,7 @@ static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
}
if (!plat_priv->driver_state) {
cnss_pr_dbg("shutdown is ignored\n");
cnss_pr_dbg("subsys shutdown is ignored\n");
return 0;
}
@ -921,14 +991,15 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
if (plat_priv->device_id == QCA6174_DEVICE_ID)
goto self_recovery;
if (test_bit(SKIP_RECOVERY, &quirks)) {
if (test_bit(SKIP_RECOVERY, &plat_priv->ctrl_params.quirks)) {
cnss_pr_dbg("Skip device recovery\n");
return 0;
}
switch (reason) {
case CNSS_REASON_LINK_DOWN:
if (test_bit(LINK_DOWN_SELF_RECOVERY, &quirks))
if (test_bit(LINK_DOWN_SELF_RECOVERY,
&plat_priv->ctrl_params.quirks))
goto self_recovery;
break;
case CNSS_REASON_RDDM:
@ -980,16 +1051,19 @@ static int cnss_driver_recovery_hdlr(struct cnss_plat_data *plat_priv,
goto out;
}
if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
cnss_pr_err("Driver unload is in progress, ignore recovery\n");
if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) {
cnss_pr_err("Driver unload or idle shutdown is in progress, ignore recovery\n");
ret = -EINVAL;
goto out;
}
switch (plat_priv->device_id) {
case QCA6174_DEVICE_ID:
if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
cnss_pr_err("Driver load is in progress, ignore recovery\n");
if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_IDLE_RESTART,
&plat_priv->driver_state)) {
cnss_pr_err("Driver load or idle restart is in progress, ignore recovery\n");
ret = -EINVAL;
goto out;
}
@ -1027,6 +1101,12 @@ void cnss_schedule_recovery(struct device *dev,
cnss_bus_update_status(plat_priv, CNSS_FW_DOWN);
if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) {
cnss_pr_dbg("Driver unload or idle shutdown is in progress, ignore schedule recovery\n");
return;
}
if (in_interrupt() || irqs_disabled())
gfp = GFP_ATOMIC;
@ -1055,18 +1135,45 @@ int cnss_force_fw_assert(struct device *dev)
return -EOPNOTSUPP;
}
if (cnss_pci_is_device_down(dev)) {
cnss_pr_info("Device is already in bad state, ignore force assert\n");
return 0;
}
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
cnss_pr_info("Recovery is already in progress, ignore forced FW assert\n");
return 0;
}
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
0, NULL);
if (in_interrupt() || irqs_disabled())
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
0, NULL);
else
cnss_bus_force_fw_assert_hdlr(plat_priv);
return 0;
}
EXPORT_SYMBOL(cnss_force_fw_assert);
static int cnss_wlfw_server_arrive_hdlr(struct cnss_plat_data *plat_priv)
{
int ret;
unsigned int bdf_type;
ret = cnss_wlfw_server_arrive(plat_priv);
if (ret)
goto out;
if (!cnss_bus_req_mem_ind_valid(plat_priv)) {
ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
if (ret)
goto out;
bdf_type = plat_priv->ctrl_params.bdf_type;
ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv, bdf_type);
}
out:
return ret;
}
int cnss_force_collect_rddm(struct device *dev)
{
@ -1083,14 +1190,27 @@ int cnss_force_collect_rddm(struct device *dev)
return -EOPNOTSUPP;
}
if (cnss_pci_is_device_down(dev)) {
cnss_pr_info("Device is already in bad state, ignore force collect rddm\n");
return 0;
}
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
cnss_pr_info("Recovery is already in progress, ignore forced collect rddm\n");
return 0;
}
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
0, NULL);
if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state) ||
test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) {
cnss_pr_info("Loading/Unloading/idle restart/shutdown is in progress, ignore forced collect rddm\n");
return 0;
}
ret = cnss_bus_force_fw_assert_hdlr(plat_priv);
if (ret)
return ret;
reinit_completion(&plat_priv->rddm_complete);
ret = wait_for_completion_timeout
@ -1123,30 +1243,6 @@ int cnss_qmi_send(struct device *dev, int type, void *cmd,
}
EXPORT_SYMBOL(cnss_qmi_send);
static int cnss_wlfw_server_arrive_hdlr(struct cnss_plat_data *plat_priv)
{
int ret;
ret = cnss_wlfw_server_arrive(plat_priv);
if (ret)
goto out;
if (!cnss_bus_req_mem_ind_valid(plat_priv)) {
ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
if (ret)
goto out;
ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv);
if (ret)
goto out;
/*cnss driver sends meta data report and waits for FW_READY*/
if (cnss_bus_dev_cal_rep_valid(plat_priv))
ret = cnss_wlfw_cal_report_send_sync(plat_priv);
}
out:
return ret;
}
static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
@ -1177,7 +1273,13 @@ 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, CNSS_OFF);
if (plat_priv->device_id == QCN7605_DEVICE_ID ||
plat_priv->device_id == QCN7605_STANDALONE_DEVICE_ID ||
plat_priv->device_id == QCN7605_COMPOSITE_DEVICE_ID)
goto skip_shutdown;
cnss_bus_dev_shutdown(plat_priv);
skip_shutdown:
complete(&plat_priv->cal_complete);
clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
@ -1186,7 +1288,13 @@ 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_bus_dev_powerup(plat_priv);
int ret;
ret = cnss_bus_dev_powerup(plat_priv);
if (ret)
clear_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state);
return ret;
}
static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
@ -1196,6 +1304,109 @@ static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
return 0;
}
static int cnss_qdss_trace_req_mem_hdlr(struct cnss_plat_data *plat_priv)
{
int ret = 0;
ret = cnss_bus_alloc_qdss_mem(plat_priv);
if (ret < 0)
return ret;
return cnss_wlfw_qdss_trace_mem_info_send_sync(plat_priv);
}
static void *cnss_qdss_trace_pa_to_va(struct cnss_plat_data *plat_priv,
u64 pa, u32 size, int *seg_id)
{
int i = 0;
struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem;
u64 offset = 0;
void *va = NULL;
u64 local_pa;
u32 local_size;
for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) {
local_pa = (u64)qdss_mem[i].pa;
local_size = (u32)qdss_mem[i].size;
if (pa == local_pa && size <= local_size) {
va = qdss_mem[i].va;
break;
}
if (pa > local_pa &&
pa < local_pa + local_size &&
pa + size <= local_pa + local_size) {
offset = pa - local_pa;
va = qdss_mem[i].va + offset;
break;
}
}
*seg_id = i;
return va;
}
static int cnss_qdss_trace_save_hdlr(struct cnss_plat_data *plat_priv,
void *data)
{
struct cnss_qmi_event_qdss_trace_save_data *event_data = data;
struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem;
int ret = 0;
int i;
void *va = NULL;
u64 pa;
u32 size;
int seg_id = 0;
if (!plat_priv->qdss_mem_seg_len) {
cnss_pr_err("Memory for QDSS trace is not available\n");
return -ENOMEM;
}
if (event_data->mem_seg_len == 0) {
for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) {
ret = cnss_genl_send_msg(qdss_mem[i].va,
CNSS_GENL_MSG_TYPE_QDSS,
event_data->file_name,
qdss_mem[i].size);
if (ret < 0) {
cnss_pr_err("Fail to save QDSS data: %d\n",
ret);
break;
}
}
} else {
for (i = 0; i < event_data->mem_seg_len; i++) {
pa = event_data->mem_seg[i].addr;
size = event_data->mem_seg[i].size;
va = cnss_qdss_trace_pa_to_va(plat_priv, pa,
size, &seg_id);
if (!va) {
cnss_pr_err("Fail to find matching va for pa 0x%llx\n",
pa);
ret = -EINVAL;
break;
}
ret = cnss_genl_send_msg(va, CNSS_GENL_MSG_TYPE_QDSS,
event_data->file_name, size);
if (ret < 0) {
cnss_pr_err("Fail to save QDSS data: %d\n",
ret);
break;
}
}
}
kfree(data);
return ret;
}
static int cnss_qdss_trace_free_hdlr(struct cnss_plat_data *plat_priv)
{
cnss_bus_free_qdss_mem(plat_priv);
return 0;
}
static void cnss_driver_event_work(struct work_struct *work)
{
struct cnss_plat_data *plat_priv =
@ -1266,12 +1477,30 @@ static void cnss_driver_event_work(struct work_struct *work)
case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
ret = cnss_bus_force_fw_assert_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_IDLE_RESTART:
set_bit(CNSS_DRIVER_IDLE_RESTART,
&plat_priv->driver_state);
/* fall through */
case CNSS_DRIVER_EVENT_POWER_UP:
ret = cnss_power_up_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
set_bit(CNSS_DRIVER_IDLE_SHUTDOWN,
&plat_priv->driver_state);
/* fall through */
case CNSS_DRIVER_EVENT_POWER_DOWN:
ret = cnss_power_down_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM:
ret = cnss_qdss_trace_req_mem_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE:
ret = cnss_qdss_trace_save_hdlr(plat_priv,
event->data);
break;
case CNSS_DRIVER_EVENT_QDSS_TRACE_FREE:
ret = cnss_qdss_trace_free_hdlr(plat_priv);
break;
default:
cnss_pr_err("Invalid driver event type: %d",
event->type);
@ -1378,10 +1607,13 @@ static int cnss_register_ramdump_v1(struct cnss_plat_data *plat_priv)
subsys_info = &plat_priv->subsys_info;
ramdump_info = &plat_priv->ramdump_info;
if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
if (of_property_read_u32(plat_priv->dev_node,
"qcom,wlan-ramdump-dynamic",
&ramdump_size) == 0) {
ramdump_info->ramdump_va = dma_alloc_coherent(dev, ramdump_size,
&ramdump_info->ramdump_pa, GFP_KERNEL);
ramdump_info->ramdump_va =
dma_alloc_coherent(dev, ramdump_size,
&ramdump_info->ramdump_pa,
GFP_KERNEL);
if (ramdump_info->ramdump_va)
ramdump_info->ramdump_size = ramdump_size;
@ -1441,14 +1673,14 @@ static int cnss_register_ramdump_v2(struct cnss_plat_data *plat_priv)
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;
if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
if (of_property_read_u32(plat_priv->dev_node,
"qcom,wlan-ramdump-dynamic",
&ramdump_size) == 0)
info_v2->ramdump_size = ramdump_size;
@ -1512,16 +1744,14 @@ int cnss_register_ramdump(struct cnss_plat_data *plat_priv)
case QCA6174_DEVICE_ID:
ret = cnss_register_ramdump_v1(plat_priv);
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
case QCA6390_EMULATION_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
ret = cnss_register_ramdump_v2(plat_priv);
break;
case QCN7605_COMPOSITE_DEVICE_ID:
case QCN7605_STANDALONE_DEVICE_ID:
break;
default:
cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
ret = -ENODEV;
@ -1536,10 +1766,9 @@ void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
case QCA6174_DEVICE_ID:
cnss_unregister_ramdump_v1(plat_priv);
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
case QCA6390_EMULATION_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
cnss_unregister_ramdump_v2(plat_priv);
break;
case QCN7605_COMPOSITE_DEVICE_ID:
@ -1600,7 +1829,7 @@ static ssize_t cnss_fs_ready_store(struct device *dev,
cnss_pr_dbg("File system is ready, fs_ready is %d, count is %zu\n",
fs_ready, count);
if (qmi_bypass) {
if (test_bit(QMI_BYPASS, &plat_priv->ctrl_params.quirks)) {
cnss_pr_dbg("QMI is bypassed.\n");
return count;
}
@ -1611,10 +1840,9 @@ static ssize_t cnss_fs_ready_store(struct device *dev,
}
switch (plat_priv->device_id) {
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
case QCA6390_EMULATION_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
break;
default:
cnss_pr_err("Not supported for device ID 0x%lx\n",
@ -1691,6 +1919,7 @@ static int cnss_misc_init(struct cnss_plat_data *plat_priv)
init_completion(&plat_priv->power_up_complete);
init_completion(&plat_priv->cal_complete);
init_completion(&plat_priv->rddm_complete);
init_completion(&plat_priv->recovery_complete);
mutex_init(&plat_priv->dev_lock);
return 0;
@ -1698,6 +1927,7 @@ static int cnss_misc_init(struct cnss_plat_data *plat_priv)
static void cnss_misc_deinit(struct cnss_plat_data *plat_priv)
{
complete_all(&plat_priv->recovery_complete);
complete_all(&plat_priv->rddm_complete);
complete_all(&plat_priv->cal_complete);
complete_all(&plat_priv->power_up_complete);
@ -1706,10 +1936,33 @@ static void cnss_misc_deinit(struct cnss_plat_data *plat_priv)
del_timer(&plat_priv->fw_boot_timer);
}
static void cnss_init_control_params(struct cnss_plat_data *plat_priv)
{
if (of_property_read_bool(plat_priv->plat_dev->dev.of_node,
"cnss-daemon-support"))
plat_priv->ctrl_params.quirks |= BIT(ENABLE_DAEMON_SUPPORT);
plat_priv->ctrl_params.mhi_timeout = CNSS_MHI_TIMEOUT_DEFAULT;
plat_priv->ctrl_params.qmi_timeout = CNSS_QMI_TIMEOUT_DEFAULT;
plat_priv->ctrl_params.bdf_type = CNSS_BDF_TYPE_DEFAULT;
}
static void cnss_get_wlaon_pwr_ctrl_info(struct cnss_plat_data *plat_priv)
{
struct device *dev = &plat_priv->plat_dev->dev;
plat_priv->set_wlaon_pwr_ctrl =
of_property_read_bool(dev->of_node, "qcom,set-wlaon-pwr-ctrl");
cnss_pr_dbg("set_wlaon_pwr_ctrl is %d\n",
plat_priv->set_wlaon_pwr_ctrl);
}
static const struct platform_device_id cnss_platform_id_table[] = {
{ .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, },
{ .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, },
{ .name = "qca6390", .driver_data = QCA6390_DEVICE_ID, },
{ .name = "qcaconv", .driver_data = 0},
};
static const struct of_device_id cnss_of_match_table[] = {
@ -1722,10 +1975,56 @@ static const struct of_device_id cnss_of_match_table[] = {
{
.compatible = "qcom,cnss-qca6390",
.data = (void *)&cnss_platform_id_table[2]},
{
.compatible = "qcom,cnss-qca-converged",
.data = (void *)&cnss_platform_id_table[3]},
{ },
};
MODULE_DEVICE_TABLE(of, cnss_of_match_table);
struct cnss_fw_path {
unsigned long device_id;
const char path[CNSS_FW_PATH_MAX_LEN];
};
static const struct cnss_fw_path cnss_fw_path_table[] = {
{ QCA6174_DEVICE_ID, "qca6174/" },
{ QCA6290_DEVICE_ID, "qca6290/" },
{ QCA6390_DEVICE_ID, "qca6390/" },
{ QCN7605_DEVICE_ID, "qcn7605/" },
{ 0, "" }
};
const char *cnss_get_fw_path(struct cnss_plat_data *plat_priv)
{
const struct cnss_fw_path *fw_path;
const char *path;
int size = ARRAY_SIZE(cnss_fw_path_table);
if (!plat_priv->is_converged_dt) {
path = cnss_fw_path_table[size - 1].path;
} else {
fw_path = cnss_fw_path_table;
while (fw_path->device_id &&
fw_path->device_id != plat_priv->device_id) {
fw_path++;
}
path = fw_path->path;
}
cnss_pr_dbg("get firmware path[%s] for device[0x%lx]\n",
path, plat_priv->device_id);
return path;
}
static inline bool
cnss_is_converged_dt(struct cnss_plat_data *plat_priv)
{
return of_property_read_bool(plat_priv->plat_dev->dev.of_node,
"qcom,converged-dt");
}
static int cnss_probe(struct platform_device *plat_dev)
{
int ret = 0;
@ -1756,16 +2055,25 @@ static int cnss_probe(struct platform_device *plat_dev)
}
plat_priv->plat_dev = plat_dev;
plat_priv->dev_node = NULL;
plat_priv->device_id = device_id->driver_data;
plat_priv->bus_type = cnss_get_bus_type(plat_priv->device_id);
plat_priv->is_converged_dt = cnss_is_converged_dt(plat_priv);
cnss_pr_dbg("Probing platform driver from %s DT\n",
plat_priv->is_converged_dt ? "converged" : "single");
plat_priv->bus_type = cnss_get_bus_type(plat_priv);
cnss_set_plat_priv(plat_dev, plat_priv);
platform_set_drvdata(plat_dev, plat_priv);
INIT_LIST_HEAD(&plat_priv->vreg_list);
cnss_get_wlaon_pwr_ctrl_info(plat_priv);
cnss_init_control_params(plat_priv);
ret = cnss_get_resources(plat_priv);
if (ret)
goto reset_ctx;
if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) {
if (!test_bit(SKIP_DEVICE_BOOT, &plat_priv->ctrl_params.quirks)) {
ret = cnss_power_on_device(plat_priv);
if (ret)
goto free_res;
@ -1803,6 +2111,10 @@ static int cnss_probe(struct platform_device *plat_dev)
if (ret)
goto destroy_debugfs;
ret = cnss_genl_init();
if (ret < 0)
cnss_pr_err("CNSS genl init failed %d\n", ret);
cnss_pr_info("Platform driver probed successfully.\n");
return 0;
@ -1820,10 +2132,10 @@ unreg_bus_scale:
unreg_esoc:
cnss_unregister_esoc(plat_priv);
deinit_bus:
if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
if (!test_bit(SKIP_DEVICE_BOOT, &plat_priv->ctrl_params.quirks))
cnss_bus_deinit(plat_priv);
power_off:
if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
if (!test_bit(SKIP_DEVICE_BOOT, &plat_priv->ctrl_params.quirks))
cnss_power_off_device(plat_priv);
free_res:
cnss_put_resources(plat_priv);
@ -1838,6 +2150,7 @@ static int cnss_remove(struct platform_device *plat_dev)
{
struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev);
cnss_genl_exit();
cnss_misc_deinit(plat_priv);
cnss_debugfs_destroy(plat_priv);
cnss_qmi_deinit(plat_priv);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -27,20 +27,22 @@
#define QMI_WLFW_MAX_TIMESTAMP_LEN 32
#define QMI_WLFW_MAX_NUM_MEM_SEG 32
#define CNSS_RDDM_TIMEOUT_MS 20000
#define RECOVERY_TIMEOUT 60000
#define CNSS_EVENT_SYNC BIT(0)
#define CNSS_EVENT_UNINTERRUPTIBLE BIT(1)
#define CNSS_EVENT_SYNC_UNINTERRUPTIBLE (CNSS_EVENT_SYNC | \
CNSS_EVENT_UNINTERRUPTIBLE)
#define CNSS_FW_PATH_MAX_LEN 32
enum cnss_dev_bus_type {
CNSS_BUS_NONE = -1,
CNSS_BUS_PCI,
CNSS_BUS_USB,
};
struct cnss_vreg_info {
struct regulator *reg;
struct cnss_vreg_cfg {
const char *name;
u32 min_uv;
u32 max_uv;
@ -48,11 +50,19 @@ struct cnss_vreg_info {
u32 delay_us;
};
struct cnss_vreg_info {
struct list_head list;
struct regulator *reg;
struct cnss_vreg_cfg cfg;
u32 enabled;
};
struct cnss_pinctrl_info {
struct pinctrl *pinctrl;
struct pinctrl_state *bootstrap_active;
struct pinctrl_state *wlan_en_active;
struct pinctrl_state *wlan_en_sleep;
u32 activated;
};
struct cnss_subsys_info {
@ -161,6 +171,11 @@ enum cnss_driver_event_type {
CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
CNSS_DRIVER_EVENT_POWER_UP,
CNSS_DRIVER_EVENT_POWER_DOWN,
CNSS_DRIVER_EVENT_IDLE_RESTART,
CNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM,
CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE,
CNSS_DRIVER_EVENT_QDSS_TRACE_FREE,
CNSS_DRIVER_EVENT_CAL_UPDATE,
CNSS_DRIVER_EVENT_CAL_DOWNLOAD,
CNSS_DRIVER_EVENT_MAX,
@ -173,11 +188,14 @@ enum cnss_driver_state {
CNSS_COLD_BOOT_CAL,
CNSS_DRIVER_LOADING,
CNSS_DRIVER_UNLOADING,
CNSS_DRIVER_IDLE_RESTART,
CNSS_DRIVER_IDLE_SHUTDOWN,
CNSS_DRIVER_PROBED,
CNSS_DRIVER_RECOVERY,
CNSS_FW_BOOT_RECOVERY,
CNSS_DEV_ERR_NOTIFY,
CNSS_DRIVER_DEBUG,
CNSS_IN_SUSPEND_RESUME,
};
struct cnss_recovery_data {
@ -208,13 +226,49 @@ enum cnss_debug_quirks {
SKIP_DEVICE_BOOT,
USE_CORE_ONLY_FW,
SKIP_RECOVERY,
QMI_BYPASS,
ENABLE_WALTEST,
ENABLE_PCI_LINK_DOWN_PANIC,
FBC_BYPASS,
ENABLE_DAEMON_SUPPORT,
IGNORE_PCI_LINK_FAILURE,
};
enum cnss_bdf_type {
CNSS_BDF_BIN,
CNSS_BDF_ELF,
CNSS_BDF_REGDB = 4,
CNSS_BDF_DUMMY = 255,
};
struct cnss_control_params {
unsigned long quirks;
unsigned int mhi_timeout;
unsigned int qmi_timeout;
unsigned int bdf_type;
};
enum cnss_ce_index {
CNSS_CE_00,
CNSS_CE_01,
CNSS_CE_02,
CNSS_CE_03,
CNSS_CE_04,
CNSS_CE_05,
CNSS_CE_06,
CNSS_CE_07,
CNSS_CE_08,
CNSS_CE_09,
CNSS_CE_10,
CNSS_CE_11,
CNSS_CE_COMMON,
};
struct cnss_plat_data {
struct platform_device *plat_dev;
void *bus_priv;
enum cnss_dev_bus_type bus_type;
struct cnss_vreg_info *vreg_info;
struct list_head vreg_list;
struct cnss_pinctrl_info pinctrl_info;
struct cnss_subsys_info subsys_info;
struct cnss_ramdump_info ramdump_info;
@ -224,6 +278,7 @@ struct cnss_plat_data {
struct notifier_block modem_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;
@ -242,6 +297,9 @@ struct cnss_plat_data {
u32 fw_mem_seg_len;
struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG];
struct cnss_fw_mem m3_mem;
u32 qdss_mem_seg_len;
struct cnss_fw_mem qdss_mem[QMI_WLFW_MAX_NUM_MEM_SEG];
u32 *qdss_reg;
struct cnss_pin_connect_result pin_result;
struct dentry *root_dentry;
atomic_t pm_count;
@ -254,18 +312,23 @@ struct cnss_plat_data {
u32 diag_reg_read_len;
u8 *diag_reg_read_buf;
bool cal_done;
char firmware_name[13];
char firmware_name[CNSS_FW_PATH_MAX_LEN];
struct completion rddm_complete;
struct completion recovery_complete;
struct cnss_control_params ctrl_params;
u32 is_converged_dt;
struct device_node *dev_node;
u8 set_wlaon_pwr_ctrl;
};
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
bool *cnss_get_qmi_bypass(void);
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);
int cnss_get_vreg(struct cnss_plat_data *plat_priv);
int cnss_get_pinctrl(struct cnss_plat_data *plat_priv);
void cnss_put_vreg(struct cnss_plat_data *plat_priv);
void cnss_put_pinctrl(struct cnss_plat_data *plat_priv);
int cnss_power_on_device(struct cnss_plat_data *plat_priv);
void cnss_power_off_device(struct cnss_plat_data *plat_priv);
int cnss_register_subsys(struct cnss_plat_data *plat_priv);
@ -273,7 +336,7 @@ void cnss_unregister_subsys(struct cnss_plat_data *plat_priv);
int cnss_register_ramdump(struct cnss_plat_data *plat_priv);
void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv);
void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv);
u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv);
bool *cnss_get_qmi_bypass(void);
bool is_qcn7605_device(u16 device_id);
const char *cnss_get_fw_path(struct cnss_plat_data *plat_priv);
int cnss_dev_specific_power_on(struct cnss_plat_data *plat_priv);
#endif /* _CNSS_MAIN_H */

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -46,6 +46,16 @@ struct cnss_msi_config {
struct cnss_msi_user *users;
};
struct cnss_pci_reg {
char *name;
u32 offset;
};
struct cnss_pci_debug_reg {
u32 offset;
u32 val;
};
struct cnss_pci_data {
struct pci_dev *pci_dev;
struct cnss_plat_data *plat_priv;
@ -70,10 +80,12 @@ struct cnss_pci_data {
void __iomem *bar;
struct cnss_msi_config *msi_config;
u32 msi_ep_base_data;
#ifdef CONFIG_MHI_BUS
struct mhi_controller *mhi_ctrl;
#endif
unsigned long mhi_state;
u32 remap_window;
struct timer_list dev_rddm_timer;
bool disable_pc;
struct cnss_pci_debug_reg *debug_reg;
};
static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data)
@ -126,6 +138,8 @@ int cnss_resume_pci_link(struct cnss_pci_data *pci_priv);
int cnss_pci_init(struct cnss_plat_data *plat_priv);
void cnss_pci_deinit(struct cnss_plat_data *plat_priv);
int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv);
int cnss_pci_alloc_qdss_mem(struct cnss_pci_data *pci_priv);
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_set_mhi_state(struct cnss_pci_data *pci_priv,
enum cnss_mhi_state state);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -18,19 +18,25 @@
#include "main.h"
#include "debug.h"
static struct cnss_vreg_info cnss_vreg_info[] = {
{NULL, "vdd-wlan-core", 1300000, 1300000, 0, 0},
{NULL, "vdd-wlan-io", 1800000, 1800000, 0, 0},
{NULL, "vdd-wlan-xtal-aon", 0, 0, 0, 0},
{NULL, "vdd-wlan-xtal", 1800000, 1800000, 0, 2},
{NULL, "vdd-wlan", 0, 0, 0, 0},
{NULL, "vdd-wlan-sp2t", 2700000, 2700000, 0, 0},
{NULL, "wlan-ant-switch", 2700000, 2700000, 20000, 0},
{NULL, "wlan-soc-swreg", 1200000, 1200000, 0, 0},
{NULL, "vdd-wlan-en", 0, 0, 0, 10},
static struct cnss_vreg_cfg cnss_vreg_list[] = {
{"vdd-wlan-core", 1300000, 1300000, 0, 0},
{"vdd-wlan-io", 1800000, 1800000, 0, 0},
{"vdd-wlan-xtal-aon", 0, 0, 0, 0},
{"vdd-wlan-xtal", 1800000, 1800000, 0, 2},
{"vdd-wlan", 0, 0, 0, 0},
{"vdd-wlan-aon", 1055000, 1055000, 0, 0},
{"vdd-wlan-rfa1", 1350000, 1350000, 0, 0},
{"vdd-wlan-rfa2", 2040000, 2040000, 0, 0},
{"vdd-wlan-rfa3", 1900000, 1900000, 0, 0},
{"vdd-wlan-ctrl1", 0, 0, 0, 0},
{"vdd-wlan-ctrl2", 0, 0, 0, 0},
{"vdd-wlan-sp2t", 2700000, 2700000, 0, 0},
{"wlan-ant-switch", 2700000, 2700000, 20000, 0},
{"wlan-soc-swreg", 1200000, 1200000, 0, 0},
{"vdd-wlan-en", 0, 0, 0, 10},
};
#define CNSS_VREG_INFO_SIZE ARRAY_SIZE(cnss_vreg_info)
#define CNSS_VREG_INFO_SIZE ARRAY_SIZE(cnss_vreg_list)
#define MAX_PROP_SIZE 32
#define BOOTSTRAP_GPIO "qcom,enable-bootstrap-gpio"
@ -38,71 +44,114 @@ static struct cnss_vreg_info cnss_vreg_info[] = {
#define WLAN_EN_GPIO "wlan-en-gpio"
#define WLAN_EN_ACTIVE "wlan_en_active"
#define WLAN_EN_SLEEP "wlan_en_sleep"
#define WLAN_VREGS_PROP "wlan_vregs"
#define BOOTSTRAP_DELAY 1000
#define WLAN_ENABLE_DELAY 1000
/* For converged dt node, get the required vregs from property 'wlan_vregs',
* which is string array; if the property is present but no value is set,
* means no additional wlan verg is required.
* For non-converged dt, go through all vregs in static array 'cnss_vreg_list'.
*/
int cnss_get_vreg(struct cnss_plat_data *plat_priv)
{
int ret = 0;
int i;
struct cnss_vreg_info *vreg_info;
struct cnss_vreg_info *vreg;
struct device *dev;
struct regulator *reg;
const __be32 *prop;
char prop_name[MAX_PROP_SIZE];
int len;
char prop_name[MAX_PROP_SIZE] = {0};
int len, id_n;
struct device_node *dt_node;
dev = &plat_priv->plat_dev->dev;
plat_priv->vreg_info = devm_kzalloc(dev, sizeof(cnss_vreg_info),
GFP_KERNEL);
if (!plat_priv->vreg_info) {
ret = -ENOMEM;
goto out;
if (!list_empty(&plat_priv->vreg_list) &&
!plat_priv->is_converged_dt) {
cnss_pr_dbg("Vregs have already been updated\n");
return 0;
}
memcpy(plat_priv->vreg_info, cnss_vreg_info, sizeof(cnss_vreg_info));
dev = &plat_priv->plat_dev->dev;
dt_node = (plat_priv->dev_node ? plat_priv->dev_node : dev->of_node);
for (i = 0; i < CNSS_VREG_INFO_SIZE; i++) {
vreg_info = &plat_priv->vreg_info[i];
reg = devm_regulator_get_optional(dev, vreg_info->name);
if (IS_ERR(reg)) {
ret = PTR_ERR(reg);
if (ret == -ENODEV)
continue;
else if (ret == -EPROBE_DEFER)
cnss_pr_info("EPROBE_DEFER for regulator: %s\n",
vreg_info->name);
else
cnss_pr_err("Failed to get regulator %s, err = %d\n",
vreg_info->name, ret);
if (plat_priv->is_converged_dt) {
id_n = of_property_count_strings(dt_node, WLAN_VREGS_PROP);
if (id_n <= 0) {
if (id_n == -ENODATA) {
cnss_pr_dbg("No additional vregs for: %s:%lx\n",
dt_node->name,
plat_priv->device_id);
return 0;
}
cnss_pr_err("property %s is invalid or missed: %s:%lx\n",
WLAN_VREGS_PROP, dt_node->name,
plat_priv->device_id);
return -EINVAL;
}
} else {
id_n = CNSS_VREG_INFO_SIZE;
}
for (i = 0; i < id_n; i++) {
vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
if (!vreg) {
ret = -ENOMEM;
goto out;
}
vreg_info->reg = reg;
if (plat_priv->is_converged_dt) {
ret = of_property_read_string_index(dt_node,
WLAN_VREGS_PROP, i,
&vreg->cfg.name);
if (ret) {
devm_kfree(dev, vreg);
cnss_pr_err("Failed to read vreg ids\n");
goto out;
}
} else {
memcpy(&vreg->cfg, &cnss_vreg_list[i],
sizeof(vreg->cfg));
}
reg = devm_regulator_get_optional(dev, vreg->cfg.name);
if (IS_ERR(reg)) {
ret = PTR_ERR(reg);
if (ret == -ENODEV) {
devm_kfree(dev, vreg);
continue;
}
else if (ret == -EPROBE_DEFER)
cnss_pr_info("EPROBE_DEFER for regulator: %s\n",
vreg->cfg.name);
else
cnss_pr_err("Failed to get regulator %s, err = %d\n",
vreg->cfg.name, ret);
devm_kfree(dev, vreg);
goto out;
}
vreg->reg = reg;
snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-info",
vreg_info->name);
prop = of_get_property(dev->of_node, prop_name, &len);
cnss_pr_dbg("Got regulator info, name: %s, len: %d\n",
prop_name, len);
vreg->cfg.name);
prop = of_get_property(dt_node, prop_name, &len);
if (!prop || len != (4 * sizeof(__be32))) {
cnss_pr_dbg("Property %s %s, use default\n", prop_name,
prop ? "invalid format" : "doesn't exist");
} else {
vreg_info->min_uv = be32_to_cpup(&prop[0]);
vreg_info->max_uv = be32_to_cpup(&prop[1]);
vreg_info->load_ua = be32_to_cpup(&prop[2]);
vreg_info->delay_us = be32_to_cpup(&prop[3]);
vreg->cfg.min_uv = be32_to_cpup(&prop[0]);
vreg->cfg.max_uv = be32_to_cpup(&prop[1]);
vreg->cfg.load_ua = be32_to_cpup(&prop[2]);
vreg->cfg.delay_us = be32_to_cpup(&prop[3]);
}
list_add_tail(&vreg->list, &plat_priv->vreg_list);
cnss_pr_dbg("Got regulator: %s, min_uv: %u, max_uv: %u, load_ua: %u, delay_us: %u\n",
vreg_info->name, vreg_info->min_uv,
vreg_info->max_uv, vreg_info->load_ua,
vreg_info->delay_us);
vreg->cfg.name, vreg->cfg.min_uv,
vreg->cfg.max_uv, vreg->cfg.load_ua,
vreg->cfg.delay_us);
}
return 0;
@ -110,121 +159,148 @@ out:
return ret;
}
void cnss_put_vreg(struct cnss_plat_data *plat_priv)
{
struct device *dev;
struct cnss_vreg_info *vreg;
dev = &plat_priv->plat_dev->dev;
while (!list_empty(&plat_priv->vreg_list)) {
vreg = list_first_entry(&plat_priv->vreg_list,
struct cnss_vreg_info, list);
list_del(&vreg->list);
if (IS_ERR_OR_NULL(vreg->reg))
continue;
cnss_pr_dbg("Put regulator: %s\n", vreg->cfg.name);
devm_regulator_put(vreg->reg);
devm_kfree(dev, vreg);
}
}
static int cnss_vreg_on(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct cnss_vreg_info *vreg_info;
int i;
struct cnss_vreg_info *vreg;
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL!\n");
return -ENODEV;
}
for (i = 0; i < CNSS_VREG_INFO_SIZE; i++) {
vreg_info = &plat_priv->vreg_info[i];
if (!vreg_info->reg)
list_for_each_entry(vreg, &plat_priv->vreg_list, list) {
if (IS_ERR_OR_NULL(vreg->reg))
continue;
cnss_pr_dbg("Regulator %s is being enabled\n", vreg_info->name);
if (vreg->enabled) {
cnss_pr_dbg("Regulator %s is already enabled\n",
vreg->cfg.name);
continue;
}
if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0) {
ret = regulator_set_voltage(vreg_info->reg,
vreg_info->min_uv,
vreg_info->max_uv);
cnss_pr_dbg("Regulator %s is being enabled\n",
vreg->cfg.name);
if (vreg->cfg.min_uv != 0 && vreg->cfg.max_uv != 0) {
ret = regulator_set_voltage(vreg->reg,
vreg->cfg.min_uv,
vreg->cfg.max_uv);
if (ret) {
cnss_pr_err("Failed to set voltage for regulator %s, min_uv: %u, max_uv: %u, err = %d\n",
vreg_info->name, vreg_info->min_uv,
vreg_info->max_uv, ret);
vreg->cfg.name,
vreg->cfg.min_uv,
vreg->cfg.max_uv, ret);
break;
}
}
if (vreg_info->load_ua) {
ret = regulator_set_load(vreg_info->reg,
vreg_info->load_ua);
if (vreg->cfg.load_ua) {
ret = regulator_set_load(vreg->reg, vreg->cfg.load_ua);
if (ret < 0) {
cnss_pr_err("Failed to set load for regulator %s, load: %u, err = %d\n",
vreg_info->name, vreg_info->load_ua,
vreg->cfg.name, vreg->cfg.load_ua,
ret);
break;
}
}
if (vreg_info->delay_us)
udelay(vreg_info->delay_us);
if (vreg->cfg.delay_us)
udelay(vreg->cfg.delay_us);
ret = regulator_enable(vreg_info->reg);
ret = regulator_enable(vreg->reg);
if (ret) {
cnss_pr_err("Failed to enable regulator %s, err = %d\n",
vreg_info->name, ret);
vreg->cfg.name, ret);
break;
}
vreg->enabled = true;
}
if (ret) {
for (; i >= 0; i--) {
vreg_info = &plat_priv->vreg_info[i];
if (!ret)
return 0;
if (!vreg_info->reg)
continue;
list_for_each_entry_continue_reverse(vreg, &plat_priv->vreg_list,
list) {
if (IS_ERR_OR_NULL(vreg->reg) || !vreg->enabled)
continue;
regulator_disable(vreg_info->reg);
if (vreg_info->load_ua)
regulator_set_load(vreg_info->reg, 0);
if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0)
regulator_set_voltage(vreg_info->reg, 0,
vreg_info->max_uv);
}
return ret;
regulator_disable(vreg->reg);
if (vreg->cfg.load_ua)
regulator_set_load(vreg->reg, 0);
if (vreg->cfg.min_uv != 0 && vreg->cfg.max_uv != 0)
regulator_set_voltage(vreg->reg, 0, vreg->cfg.max_uv);
vreg->enabled = false;
}
return 0;
return ret;
}
static int cnss_vreg_off(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct cnss_vreg_info *vreg_info;
int i;
struct cnss_vreg_info *vreg;
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL!\n");
return -ENODEV;
}
for (i = CNSS_VREG_INFO_SIZE - 1; i >= 0; i--) {
vreg_info = &plat_priv->vreg_info[i];
if (!vreg_info->reg)
list_for_each_entry_reverse(vreg, &plat_priv->vreg_list, list) {
if (IS_ERR_OR_NULL(vreg->reg))
continue;
cnss_pr_dbg("Regulator %s is being disabled\n",
vreg_info->name);
if (!vreg->enabled) {
cnss_pr_dbg("Regulator %s is already disabled\n",
vreg->cfg.name);
continue;
}
ret = regulator_disable(vreg_info->reg);
cnss_pr_dbg("Regulator %s is being disabled\n",
vreg->cfg.name);
ret = regulator_disable(vreg->reg);
if (ret)
cnss_pr_err("Failed to disable regulator %s, err = %d\n",
vreg_info->name, ret);
vreg->cfg.name, ret);
if (vreg_info->load_ua) {
ret = regulator_set_load(vreg_info->reg, 0);
if (vreg->cfg.load_ua) {
ret = regulator_set_load(vreg->reg, 0);
if (ret < 0)
cnss_pr_err("Failed to set load for regulator %s, err = %d\n",
vreg_info->name, ret);
vreg->cfg.name, ret);
}
if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0) {
ret = regulator_set_voltage(vreg_info->reg, 0,
vreg_info->max_uv);
if (vreg->cfg.min_uv != 0 && vreg->cfg.max_uv != 0) {
ret = regulator_set_voltage(vreg->reg, 0,
vreg->cfg.max_uv);
if (ret)
cnss_pr_err("Failed to set voltage for regulator %s, err = %d\n",
vreg_info->name, ret);
vreg->cfg.name, ret);
}
vreg->enabled = false;
}
return ret;
@ -285,6 +361,18 @@ out:
return ret;
}
void cnss_put_pinctrl(struct cnss_plat_data *plat_priv)
{
struct pinctrl *pinctrl;
pinctrl = plat_priv->pinctrl_info.pinctrl;
if (IS_ERR_OR_NULL(pinctrl))
return;
devm_pinctrl_put(pinctrl);
memset(&plat_priv->pinctrl_info, 0, sizeof(plat_priv->pinctrl_info));
}
static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
bool state)
{
@ -300,10 +388,15 @@ static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
pinctrl_info = &plat_priv->pinctrl_info;
if (state) {
if (pinctrl_info->activated) {
cnss_pr_dbg("Pinctrl is already activated\n");
goto out;
}
if (!IS_ERR_OR_NULL(pinctrl_info->bootstrap_active)) {
ret = pinctrl_select_state(pinctrl_info->pinctrl,
pinctrl_info->
bootstrap_active);
ret = pinctrl_select_state(
pinctrl_info->pinctrl,
pinctrl_info->bootstrap_active);
if (ret) {
cnss_pr_err("Failed to select bootstrap active state, err = %d\n",
ret);
@ -313,9 +406,9 @@ static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
}
if (!IS_ERR_OR_NULL(pinctrl_info->wlan_en_active)) {
ret = pinctrl_select_state(pinctrl_info->pinctrl,
pinctrl_info->
wlan_en_active);
ret = pinctrl_select_state(
pinctrl_info->pinctrl,
pinctrl_info->wlan_en_active);
if (ret) {
cnss_pr_err("Failed to select wlan_en active state, err = %d\n",
ret);
@ -323,7 +416,13 @@ static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
}
udelay(WLAN_ENABLE_DELAY);
}
pinctrl_info->activated = true;
} else {
if (!pinctrl_info->activated) {
cnss_pr_dbg("Pinctrl is already de-activated\n");
goto out;
}
if (!IS_ERR_OR_NULL(pinctrl_info->wlan_en_sleep)) {
ret = pinctrl_select_state(pinctrl_info->pinctrl,
pinctrl_info->wlan_en_sleep);
@ -333,6 +432,7 @@ static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
goto out;
}
}
pinctrl_info->activated = false;
}
return 0;
@ -384,3 +484,18 @@ void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv)
plat_priv->pin_result.host_pin_result = pin_status;
}
/* If it's converged dt, get device specific regulators and enable them. */
int cnss_dev_specific_power_on(struct cnss_plat_data *plat_priv)
{
int ret;
if (!plat_priv->is_converged_dt)
return 0;
ret = cnss_get_vreg(plat_priv);
if (ret)
return ret;
return cnss_power_on_device(plat_priv);
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -22,18 +22,14 @@
#define WLFW_SERVICE_INS_ID_V01 1
#define WLFW_CLIENT_ID 0x4b4e454c
#define MAX_BDF_FILE_NAME 11
#define BDF_FILE_NAME_PREFIX "bdwlan"
#define ELF_BDF_FILE_NAME "bdwlan.elf"
#define ELF_BDF_FILE_NAME_PREFIX "bdwlan.e"
#define BIN_BDF_FILE_NAME "bdwlan.bin"
#define BIN_BDF_FILE_NAME_PREFIX "bdwlan.b"
#define REGDB_FILE_NAME "regdb.bin"
#define DUMMY_BDF_FILE_NAME "bdwlan.dmy"
enum cnss_bdf_type {
CNSS_BDF_BIN,
CNSS_BDF_ELF,
CNSS_BDF_DUMMY = 255,
};
#define CE_MSI_NAME "CE"
#ifdef CONFIG_CNSS2_DEBUG
static unsigned int qmi_timeout = 10000;
@ -249,6 +245,13 @@ static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv)
req.initiate_cal_update_enable_valid = 1;
req.initiate_cal_update_enable = 1;
req.qdss_trace_req_mem_enable_valid = 1;
req.qdss_trace_req_mem_enable = 1;
req.qdss_trace_save_enable_valid = 1;
req.qdss_trace_save_enable = 1;
req.qdss_trace_free_enable_valid = 1;
req.qdss_trace_free_enable = 1;
req_desc.max_msg_len = WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN;
req_desc.msg_id = QMI_WLFW_IND_REGISTER_REQ_V01;
req_desc.ei_array = wlfw_ind_register_req_msg_v01_ei;
@ -512,56 +515,80 @@ out:
return ret;
}
int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv)
int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
u32 bdf_type)
{
struct wlfw_bdf_download_req_msg_v01 *req;
struct wlfw_bdf_download_resp_msg_v01 resp;
struct msg_desc req_desc, resp_desc;
char filename[MAX_BDF_FILE_NAME];
char filename[CNSS_FW_PATH_MAX_LEN];
const struct firmware *fw_entry;
const u8 *temp;
unsigned int remaining;
int ret = 0;
const char *fw_path;
cnss_pr_dbg("Sending BDF download message, state: 0x%lx\n",
plat_priv->driver_state);
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req) {
ret = -ENOMEM;
goto out;
}
if (!req)
return -ENOMEM;
fw_path = cnss_get_fw_path(plat_priv);
switch (bdf_type) {
case CNSS_BDF_ELF:
if (plat_priv->board_info.board_id == 0xFF)
snprintf(filename, sizeof(filename), ELF_BDF_FILE_NAME);
snprintf(filename, sizeof(filename),
"%s" ELF_BDF_FILE_NAME, fw_path);
else if (plat_priv->board_info.board_id < 0xFF)
snprintf(filename, sizeof(filename),
"%s" ELF_BDF_FILE_NAME_PREFIX "%02x",
fw_path, plat_priv->board_info.board_id);
else
snprintf(filename, sizeof(filename),
ELF_BDF_FILE_NAME_PREFIX "%02x",
plat_priv->board_info.board_id);
"%s" BDF_FILE_NAME_PREFIX "%02x.e%02x",
fw_path,
plat_priv->board_info.board_id >> 8 & 0xFF,
plat_priv->board_info.board_id & 0xFF);
break;
case CNSS_BDF_BIN:
if (plat_priv->board_info.board_id == 0xFF)
snprintf(filename, sizeof(filename), BIN_BDF_FILE_NAME);
snprintf(filename, sizeof(filename),
"%s" BIN_BDF_FILE_NAME, fw_path);
else if (plat_priv->board_info.board_id < 0xFF)
snprintf(filename, sizeof(filename),
"%s" BIN_BDF_FILE_NAME_PREFIX "%02x",
fw_path, plat_priv->board_info.board_id);
else
snprintf(filename, sizeof(filename),
BIN_BDF_FILE_NAME_PREFIX "%02x",
plat_priv->board_info.board_id);
"%s" BDF_FILE_NAME_PREFIX "%02x.b%02x",
fw_path,
plat_priv->board_info.board_id >> 8 & 0xFF,
plat_priv->board_info.board_id & 0xFF);
break;
case CNSS_BDF_REGDB:
snprintf(filename, sizeof(filename), REGDB_FILE_NAME);
break;
case CNSS_BDF_DUMMY:
cnss_pr_dbg("CNSS_BDF_DUMMY is set, sending dummy BDF\n");
snprintf(filename, sizeof(filename), DUMMY_BDF_FILE_NAME);
snprintf(filename, sizeof(filename),
"%s" DUMMY_BDF_FILE_NAME, fw_path);
temp = DUMMY_BDF_FILE_NAME;
remaining = MAX_BDF_FILE_NAME;
remaining = CNSS_FW_PATH_MAX_LEN;
goto bypass_bdf;
default:
cnss_pr_err("Invalid BDF type: %d\n", bdf_type);
cnss_pr_err("Invalid BDF type: %d\n",
plat_priv->ctrl_params.bdf_type);
ret = -EINVAL;
goto err_req_fw;
}
ret = request_firmware(&fw_entry, filename, &plat_priv->plat_dev->dev);
if (bdf_type == CNSS_BDF_REGDB)
ret = request_firmware_direct(&fw_entry, filename,
&plat_priv->plat_dev->dev);
else
ret = request_firmware(&fw_entry, filename,
&plat_priv->plat_dev->dev);
if (ret) {
cnss_pr_err("Failed to load BDF: %s\n", filename);
goto err_req_fw;
@ -593,7 +620,7 @@ bypass_bdf:
req->data_valid = 1;
req->end_valid = 1;
req->bdf_type_valid = 1;
req->bdf_type = bdf_type;
req->bdf_type = plat_priv->ctrl_params.bdf_type;
if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
@ -608,7 +635,7 @@ bypass_bdf:
req, sizeof(*req), &resp_desc, &resp,
sizeof(resp), QMI_WLFW_TIMEOUT_MS);
if (ret < 0) {
cnss_pr_err("Failed to send BDF download request, err = %d\n",
cnss_pr_err("Failed to wait for response of BDF download request, err: %d\n",
ret);
goto err_send;
}
@ -625,14 +652,19 @@ bypass_bdf:
req->seg_id++;
}
err_send:
if (bdf_type != CNSS_BDF_DUMMY)
release_firmware(fw_entry);
err_req_fw:
kfree(req);
out:
if (ret)
return 0;
err_send:
if (plat_priv->ctrl_params.bdf_type != CNSS_BDF_DUMMY)
release_firmware(fw_entry);
err_req_fw:
if (bdf_type != CNSS_BDF_REGDB)
CNSS_ASSERT(0);
kfree(req);
return ret;
}
@ -763,7 +795,7 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
struct wlfw_wlan_cfg_req_msg_v01 req;
struct wlfw_wlan_cfg_resp_msg_v01 resp;
struct msg_desc req_desc, resp_desc;
u32 i;
u32 i, ce_id, num_vectors, user_base_data, base_vector;
int ret = 0;
cnss_pr_dbg("Sending WLAN config message, state: 0x%lx\n",
@ -803,6 +835,18 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num;
}
if (config->num_shadow_reg_cfg) {
req.shadow_reg_valid = 1;
if (config->num_shadow_reg_cfg >
QMI_WLFW_MAX_NUM_SHADOW_REG_V01)
req.shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01;
else
req.shadow_reg_len = config->num_shadow_reg_cfg;
memcpy(req.shadow_reg, config->shadow_reg_cfg,
sizeof(struct wlfw_shadow_reg_cfg_s_v01)
* req.shadow_reg_len);
}
req.shadow_reg_v2_valid = 1;
if (config->num_shadow_reg_v2_cfg >
QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01)
@ -814,6 +858,31 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01)
* req.shadow_reg_v2_len);
if (config->rri_over_ddr_cfg_valid) {
req.rri_over_ddr_cfg_valid = 1;
req.rri_over_ddr_cfg.base_addr_low =
config->rri_over_ddr_cfg.base_addr_low;
req.rri_over_ddr_cfg.base_addr_high =
config->rri_over_ddr_cfg.base_addr_high;
}
if (config->send_msi_ce) {
ret = cnss_get_msi_assignment(plat_priv,
CE_MSI_NAME,
&num_vectors,
&user_base_data,
&base_vector);
if (!ret) {
req.msi_cfg_valid = 1;
req.msi_cfg_len = QMI_WLFW_MAX_NUM_CE_V01;
for (ce_id = 0; ce_id < QMI_WLFW_MAX_NUM_CE_V01;
ce_id++) {
req.msi_cfg[ce_id].ce_id = ce_id;
req.msi_cfg[ce_id].msi_vector =
(ce_id % num_vectors) + base_vector;
}
}
}
req_desc.max_msg_len = WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN;
req_desc.msg_id = QMI_WLFW_WLAN_CFG_REQ_V01;
req_desc.ei_array = wlfw_wlan_cfg_req_msg_v01_ei;
@ -896,7 +965,7 @@ int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv,
}
if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
cnss_pr_err("athdiag read request failed, result: %d, err: %d\n",
cnss_pr_err("Athdiag read request failed, result: %d, err: %d\n",
resp->resp.result, resp->resp.error);
ret = resp->resp.result;
goto out;
@ -1031,8 +1100,9 @@ out:
return ret;
}
int cnss_wlfw_cal_report_send_sync(struct cnss_plat_data *plat_priv)
int cnss_wlfw_qdss_trace_mem_info_send_sync(struct cnss_plat_data *plat_priv)
{
/* not ready in kernel 4.9 */
return 0;
}
@ -1087,7 +1157,7 @@ static void cnss_wlfw_clnt_ind(struct qmi_handle *handle,
}
}
unsigned int cnss_get_qmi_timeout(void)
unsigned int cnss_get_qmi_timeout(struct cnss_plat_data *plat_priv)
{
cnss_pr_dbg("QMI timeout is %u ms\n", QMI_WLFW_TIMEOUT_MS);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -15,17 +15,33 @@
struct cnss_plat_data;
#define QDSS_TRACE_SEG_LEN_MAX 32
#define QDSS_TRACE_FILE_NAME_MAX 16
struct cnss_mem_seg {
u64 addr;
u32 size;
};
struct cnss_qmi_event_qdss_trace_save_data {
u32 total_size;
u32 mem_seg_len;
struct cnss_mem_seg mem_seg[QDSS_TRACE_SEG_LEN_MAX];
char file_name[QDSS_TRACE_FILE_NAME_MAX + 1];
};
#ifdef CONFIG_CNSS2_QMI
#include "wlan_firmware_service_v01.h"
int cnss_qmi_init(struct cnss_plat_data *plat_priv);
void cnss_qmi_deinit(struct cnss_plat_data *plat_priv);
unsigned int cnss_get_qmi_timeout(void);
unsigned int cnss_get_qmi_timeout(struct cnss_plat_data *plat_priv);
int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv);
int cnss_wlfw_server_exit(struct cnss_plat_data *plat_priv);
int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv);
int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv);
int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv);
int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
u32 bdf_type);
int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv);
int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
enum cnss_driver_mode mode);
@ -40,8 +56,7 @@ int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
u32 data_len, u8 *data);
int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
u8 fw_log_mode);
int cnss_wlfw_cal_report_send_sync(struct cnss_plat_data *plat_priv);
int cnss_wlfw_qdss_trace_mem_info_send_sync(struct cnss_plat_data *plat_priv);
#else
#define QMI_WLFW_TIMEOUT_MS 10000
@ -54,12 +69,14 @@ static inline void cnss_qmi_deinit(struct cnss_plat_data *plat_priv)
{
}
static inline unsigned int cnss_get_qmi_timeout(void)
static inline
unsigned int cnss_get_qmi_timeout(struct cnss_plat_data *plat_priv)
{
return QMI_WLFW_TIMEOUT_MS;
}
static inline int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv)
static inline int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv,
void *data)
{
return 0;
}
@ -80,7 +97,8 @@ static inline int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv)
return 0;
}
static inline int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv)
static inline int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
u32 bdf_type)
{
return 0;
}
@ -129,10 +147,10 @@ int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
}
static inline
int cnss_wlfw_cal_report_send_sync(struct cnss_plat_data *plat_priv)
int cnss_wlfw_qdss_trace_mem_info_send_sync(struct cnss_plat_data *plat_priv)
{
return 0;
}
#endif /* CONFIG_CNSS2_QMI */
#endif /* _CNSS_QMI_H */

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2017, 2020 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -31,7 +31,7 @@ static struct cnss_dfs_nol_info {
int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
{
mutex_lock(&unsafe_channel_list_lock);
if ((!unsafe_ch_list) || (ch_count > CNSS_MAX_CH_NUM)) {
if (!unsafe_ch_list || ch_count > CNSS_MAX_CH_NUM) {
mutex_unlock(&unsafe_channel_list_lock);
return -EINVAL;
}

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -144,6 +144,57 @@ static struct elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = {
},
};
static struct elem_info wlfw_rri_over_ddr_cfg_s_v01_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0,
.offset = offsetof(struct wlfw_rri_over_ddr_cfg_s_v01,
base_addr_low),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0,
.offset = offsetof(struct wlfw_rri_over_ddr_cfg_s_v01,
base_addr_high),
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
static struct elem_info wlfw_msi_cfg_s_v01_ei[] = {
{
.data_type = QMI_UNSIGNED_2_BYTE,
.elem_len = 1,
.elem_size = sizeof(u16),
.is_array = NO_ARRAY,
.tlv_type = 0,
.offset = offsetof(struct wlfw_msi_cfg_s_v01,
ce_id),
},
{
.data_type = QMI_UNSIGNED_2_BYTE,
.elem_len = 1,
.elem_size = sizeof(u16),
.is_array = NO_ARRAY,
.tlv_type = 0,
.offset = offsetof(struct wlfw_msi_cfg_s_v01,
msi_vector),
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
static struct elem_info wlfw_memory_region_info_s_v01_ei[] = {
{
.data_type = QMI_UNSIGNED_8_BYTE,
@ -607,6 +658,60 @@ struct elem_info wlfw_ind_register_req_msg_v01_ei[] = {
.offset = offsetof(struct wlfw_ind_register_req_msg_v01,
cal_done_enable),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x1C,
.offset = offsetof(struct wlfw_ind_register_req_msg_v01,
qdss_trace_req_mem_enable_valid),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x1C,
.offset = offsetof(struct wlfw_ind_register_req_msg_v01,
qdss_trace_req_mem_enable),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x1D,
.offset = offsetof(struct wlfw_ind_register_req_msg_v01,
qdss_trace_save_enable_valid),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x1D,
.offset = offsetof(struct wlfw_ind_register_req_msg_v01,
qdss_trace_save_enable),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x1E,
.offset = offsetof(struct wlfw_ind_register_req_msg_v01,
qdss_trace_free_enable_valid),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x1E,
.offset = offsetof(struct wlfw_ind_register_req_msg_v01,
qdss_trace_free_enable),
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
@ -921,6 +1026,53 @@ struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = {
shadow_reg_v2),
.ei_array = wlfw_shadow_reg_v2_cfg_s_v01_ei,
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x15,
.offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
rri_over_ddr_cfg_valid),
},
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct wlfw_rri_over_ddr_cfg_s_v01),
.is_array = NO_ARRAY,
.tlv_type = 0x15,
.offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
rri_over_ddr_cfg),
.ei_array = wlfw_rri_over_ddr_cfg_s_v01_ei,
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x16,
.offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
msi_cfg_valid),
},
{
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x16,
.offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
msi_cfg_len),
},
{
.data_type = QMI_STRUCT,
.elem_len = QMI_WLFW_MAX_NUM_CE_V01,
.elem_size = sizeof(struct wlfw_msi_cfg_s_v01),
.is_array = VAR_LEN_ARRAY,
.tlv_type = 0x16,
.offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
msi_cfg),
.ei_array = wlfw_msi_cfg_s_v01_ei,
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
@ -1077,6 +1229,42 @@ struct elem_info wlfw_cap_resp_msg_v01_ei[] = {
.offset = offsetof(struct wlfw_cap_resp_msg_v01,
num_macs),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x16,
.offset = offsetof(struct wlfw_cap_resp_msg_v01,
voltage_mv_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x16,
.offset = offsetof(struct wlfw_cap_resp_msg_v01,
voltage_mv),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x17,
.offset = offsetof(struct wlfw_cap_resp_msg_v01,
time_freq_hz_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x17,
.offset = offsetof(struct wlfw_cap_resp_msg_v01,
time_freq_hz),
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
@ -1316,9 +1504,9 @@ struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = {
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(
struct wlfw_initiate_cal_download_ind_msg_v01,
total_size_valid),
.offset = offsetof(struct
wlfw_initiate_cal_download_ind_msg_v01,
total_size_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
@ -1326,9 +1514,9 @@ struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = {
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(
struct wlfw_initiate_cal_download_ind_msg_v01,
total_size),
.offset = offsetof(struct
wlfw_initiate_cal_download_ind_msg_v01,
total_size),
},
{
.data_type = QMI_OPT_FLAG,
@ -1336,9 +1524,9 @@ struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = {
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(
struct wlfw_initiate_cal_download_ind_msg_v01,
cal_data_location_valid),
.offset = offsetof(struct
wlfw_initiate_cal_download_ind_msg_v01,
cal_data_location_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
@ -1346,9 +1534,9 @@ struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = {
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(
struct wlfw_initiate_cal_download_ind_msg_v01,
cal_data_location),
.offset = offsetof(struct
wlfw_initiate_cal_download_ind_msg_v01,
cal_data_location),
},
{
.data_type = QMI_EOTI,
@ -1538,8 +1726,8 @@ struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = {
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_initiate_cal_update_ind_msg_v01,
cal_data_location_valid),
wlfw_initiate_cal_update_ind_msg_v01,
cal_data_location_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
@ -1548,8 +1736,8 @@ struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = {
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_initiate_cal_update_ind_msg_v01,
cal_data_location),
wlfw_initiate_cal_update_ind_msg_v01,
cal_data_location),
},
{
.data_type = QMI_EOTI,
@ -2719,3 +2907,554 @@ struct elem_info wlfw_cal_done_ind_msg_v01_ei[] = {
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_req_mem_ind_msg_v01_ei[] = {
{
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
wlfw_qdss_trace_req_mem_ind_msg_v01,
mem_seg_len),
},
{
.data_type = QMI_STRUCT,
.elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
.elem_size = sizeof(struct wlfw_mem_seg_s_v01),
.is_array = VAR_LEN_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
wlfw_qdss_trace_req_mem_ind_msg_v01,
mem_seg),
.ei_array = wlfw_mem_seg_s_v01_ei,
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_mem_info_req_msg_v01_ei[] = {
{
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
wlfw_qdss_trace_mem_info_req_msg_v01,
mem_seg_len),
},
{
.data_type = QMI_STRUCT,
.elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
.elem_size = sizeof(struct wlfw_mem_seg_resp_s_v01),
.is_array = VAR_LEN_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
wlfw_qdss_trace_mem_info_req_msg_v01,
mem_seg),
.ei_array = wlfw_mem_seg_resp_s_v01_ei,
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_mem_info_resp_msg_v01_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
.is_array = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
wlfw_qdss_trace_mem_info_resp_msg_v01,
resp),
.ei_array = qmi_response_type_v01_ei,
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_save_ind_msg_v01_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
wlfw_qdss_trace_save_ind_msg_v01,
source),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
wlfw_qdss_trace_save_ind_msg_v01,
total_size),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_save_ind_msg_v01,
mem_seg_valid),
},
{
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_save_ind_msg_v01,
mem_seg_len),
},
{
.data_type = QMI_STRUCT,
.elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
.elem_size = sizeof(struct wlfw_mem_seg_resp_s_v01),
.is_array = VAR_LEN_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_save_ind_msg_v01,
mem_seg),
.ei_array = wlfw_mem_seg_resp_s_v01_ei,
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(struct
wlfw_qdss_trace_save_ind_msg_v01,
file_name_valid),
},
{
.data_type = QMI_STRING,
.elem_len = QMI_WLFW_MAX_STR_LEN_V01 + 1,
.elem_size = sizeof(char),
.is_array = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(struct
wlfw_qdss_trace_save_ind_msg_v01,
file_name),
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_data_req_msg_v01_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct
wlfw_qdss_trace_data_req_msg_v01,
seg_id),
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_data_resp_msg_v01_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
.is_array = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
wlfw_qdss_trace_data_resp_msg_v01,
resp),
.ei_array = qmi_response_type_v01_ei,
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_data_resp_msg_v01,
total_size_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_data_resp_msg_v01,
total_size),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(struct
wlfw_qdss_trace_data_resp_msg_v01,
seg_id_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(struct
wlfw_qdss_trace_data_resp_msg_v01,
seg_id),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x12,
.offset = offsetof(struct
wlfw_qdss_trace_data_resp_msg_v01,
data_valid),
},
{
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(u16),
.is_array = NO_ARRAY,
.tlv_type = 0x12,
.offset = offsetof(struct
wlfw_qdss_trace_data_resp_msg_v01,
data_len),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
.elem_size = sizeof(u8),
.is_array = VAR_LEN_ARRAY,
.tlv_type = 0x12,
.offset = offsetof(struct
wlfw_qdss_trace_data_resp_msg_v01,
data),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x13,
.offset = offsetof(struct
wlfw_qdss_trace_data_resp_msg_v01,
end_valid),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x13,
.offset = offsetof(struct
wlfw_qdss_trace_data_resp_msg_v01,
end),
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_config_download_req_msg_v01_ei[] = {
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_config_download_req_msg_v01,
total_size_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_config_download_req_msg_v01,
total_size),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(struct
wlfw_qdss_trace_config_download_req_msg_v01,
seg_id_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(struct
wlfw_qdss_trace_config_download_req_msg_v01,
seg_id),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x12,
.offset = offsetof(struct
wlfw_qdss_trace_config_download_req_msg_v01,
data_valid),
},
{
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(u16),
.is_array = NO_ARRAY,
.tlv_type = 0x12,
.offset = offsetof(struct
wlfw_qdss_trace_config_download_req_msg_v01,
data_len),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
.elem_size = sizeof(u8),
.is_array = VAR_LEN_ARRAY,
.tlv_type = 0x12,
.offset = offsetof(struct
wlfw_qdss_trace_config_download_req_msg_v01,
data),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x13,
.offset = offsetof(struct
wlfw_qdss_trace_config_download_req_msg_v01,
end_valid),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x13,
.offset = offsetof(struct
wlfw_qdss_trace_config_download_req_msg_v01,
end),
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_config_download_resp_msg_v01_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
.is_array = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
wlfw_qdss_trace_config_download_resp_msg_v01,
resp),
.ei_array = qmi_response_type_v01_ei,
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_mode_req_msg_v01_ei[] = {
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_mode_req_msg_v01,
mode_valid),
},
{
.data_type = QMI_SIGNED_4_BYTE_ENUM,
.elem_len = 1,
.elem_size = sizeof(enum wlfw_qdss_trace_mode_enum_v01),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_mode_req_msg_v01,
mode),
},
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(struct
wlfw_qdss_trace_mode_req_msg_v01,
option_valid),
},
{
.data_type = QMI_UNSIGNED_8_BYTE,
.elem_len = 1,
.elem_size = sizeof(u64),
.is_array = NO_ARRAY,
.tlv_type = 0x11,
.offset = offsetof(struct
wlfw_qdss_trace_mode_req_msg_v01,
option),
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_mode_resp_msg_v01_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
.is_array = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct
wlfw_qdss_trace_mode_resp_msg_v01,
resp),
.ei_array = qmi_response_type_v01_ei,
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_qdss_trace_free_ind_msg_v01_ei[] = {
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_free_ind_msg_v01,
mem_seg_valid),
},
{
.data_type = QMI_DATA_LEN,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_free_ind_msg_v01,
mem_seg_len),
},
{
.data_type = QMI_STRUCT,
.elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
.elem_size = sizeof(struct wlfw_mem_seg_resp_s_v01),
.is_array = VAR_LEN_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct
wlfw_qdss_trace_free_ind_msg_v01,
mem_seg),
.ei_array = wlfw_mem_seg_resp_s_v01_ei,
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_shutdown_req_msg_v01_ei[] = {
{
.data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct wlfw_shutdown_req_msg_v01,
shutdown_valid),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct wlfw_shutdown_req_msg_v01,
shutdown),
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_shutdown_resp_msg_v01_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct qmi_response_type_v01),
.is_array = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct wlfw_shutdown_resp_msg_v01,
resp),
.ei_array = qmi_response_type_v01_ei,
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
},
};

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -22,6 +22,7 @@
#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
#define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037
#define QMI_WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_V01 0x0044
#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A
#define QMI_WLFW_CAL_DONE_IND_V01 0x003E
#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034
@ -36,6 +37,9 @@
#define QMI_WLFW_XO_CAL_IND_V01 0x003D
#define QMI_WLFW_INI_RESP_V01 0x002F
#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026
#define QMI_WLFW_QDSS_TRACE_MEM_INFO_REQ_V01 0x0040
#define QMI_WLFW_QDSS_TRACE_REQ_MEM_IND_V01 0x003F
#define QMI_WLFW_SHUTDOWN_RESP_V01 0x0043
#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033
#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028
#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034
@ -44,29 +48,38 @@
#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022
#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020
#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023
#define QMI_WLFW_QDSS_TRACE_MODE_REQ_V01 0x0045
#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
#define QMI_WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_RESP_V01 0x0044
#define QMI_WLFW_REJUVENATE_IND_V01 0x0039
#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B
#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031
#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022
#define QMI_WLFW_RESPOND_MEM_REQ_V01 0x0036
#define QMI_WLFW_QDSS_TRACE_MODE_RESP_V01 0x0045
#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C
#define QMI_WLFW_FW_READY_IND_V01 0x0021
#define QMI_WLFW_QDSS_TRACE_SAVE_IND_V01 0x0041
#define QMI_WLFW_QDSS_TRACE_MEM_INFO_RESP_V01 0x0040
#define QMI_WLFW_MSA_READY_RESP_V01 0x002E
#define QMI_WLFW_QDSS_TRACE_DATA_REQ_V01 0x0042
#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029
#define QMI_WLFW_INI_REQ_V01 0x002F
#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025
#define QMI_WLFW_REJUVENATE_ACK_RESP_V01 0x003A
#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D
#define QMI_WLFW_MSA_READY_REQ_V01 0x002E
#define QMI_WLFW_QDSS_TRACE_DATA_RESP_V01 0x0042
#define QMI_WLFW_CAP_RESP_V01 0x0024
#define QMI_WLFW_REJUVENATE_ACK_REQ_V01 0x003A
#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030
#define QMI_WLFW_SHUTDOWN_REQ_V01 0x0043
#define QMI_WLFW_VBATT_REQ_V01 0x0032
#define QMI_WLFW_MAC_ADDR_REQ_V01 0x0033
#define QMI_WLFW_RESPOND_MEM_RESP_V01 0x0036
#define QMI_WLFW_VBATT_RESP_V01 0x0032
#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D
#define QMI_WLFW_QDSS_TRACE_FREE_IND_V01 0x0046
#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027
#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030
#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023
@ -129,9 +142,17 @@ enum wlfw_mem_type_enum_v01 {
QMI_WLFW_MEM_M3_V01 = 3,
QMI_WLFW_MEM_CAL_V01 = 4,
QMI_WLFW_MEM_DPD_V01 = 5,
QMI_WLFW_MEM_QDSS_V01 = 6,
WLFW_MEM_TYPE_ENUM_MAX_VAL_V01 = INT_MAX,
};
enum wlfw_qdss_trace_mode_enum_v01 {
WLFW_QDSS_TRACE_MODE_ENUM_MIN_VAL_V01 = INT_MIN,
QMI_WLFW_QDSS_TRACE_OFF_V01 = 0,
QMI_WLFW_QDSS_TRACE_ON_V01 = 1,
WLFW_QDSS_TRACE_MODE_ENUM_MAX_VAL_V01 = INT_MAX,
};
#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00)
#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01)
#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02)
@ -170,6 +191,16 @@ struct wlfw_shadow_reg_v2_cfg_s_v01 {
u32 addr;
};
struct wlfw_rri_over_ddr_cfg_s_v01 {
u32 base_addr_low;
u32 base_addr_high;
};
struct wlfw_msi_cfg_s_v01 {
u16 ce_id;
u16 msi_vector;
};
struct wlfw_memory_region_info_s_v01 {
u64 region_addr;
u32 size;
@ -239,9 +270,15 @@ struct wlfw_ind_register_req_msg_v01 {
u8 xo_cal_enable;
u8 cal_done_enable_valid;
u8 cal_done_enable;
u8 qdss_trace_req_mem_enable_valid;
u8 qdss_trace_req_mem_enable;
u8 qdss_trace_save_enable_valid;
u8 qdss_trace_save_enable;
u8 qdss_trace_free_enable_valid;
u8 qdss_trace_free_enable;
};
#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 54
#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 66
extern struct elem_info wlfw_ind_register_req_msg_v01_ei[];
struct wlfw_ind_register_resp_msg_v01 {
@ -312,9 +349,14 @@ struct wlfw_wlan_cfg_req_msg_v01 {
u32 shadow_reg_v2_len;
struct wlfw_shadow_reg_v2_cfg_s_v01
shadow_reg_v2[QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01];
u8 rri_over_ddr_cfg_valid;
struct wlfw_rri_over_ddr_cfg_s_v01 rri_over_ddr_cfg;
u8 msi_cfg_valid;
u32 msi_cfg_len;
struct wlfw_msi_cfg_s_v01 msi_cfg[QMI_WLFW_MAX_NUM_CE_V01];
};
#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803
#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 866
extern struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[];
struct wlfw_wlan_cfg_resp_msg_v01 {
@ -345,9 +387,13 @@ struct wlfw_cap_resp_msg_v01 {
char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1];
u8 num_macs_valid;
u8 num_macs;
u8 voltage_mv_valid;
u32 voltage_mv;
u8 time_freq_hz_valid;
u32 time_freq_hz;
};
#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 207
#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 221
extern struct elem_info wlfw_cap_resp_msg_v01_ei[];
struct wlfw_bdf_download_req_msg_v01 {
@ -737,4 +783,126 @@ struct wlfw_cal_done_ind_msg_v01 {
#define WLFW_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0
extern struct elem_info wlfw_cal_done_ind_msg_v01_ei[];
struct wlfw_qdss_trace_req_mem_ind_msg_v01 {
u32 mem_seg_len;
struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
};
#define WLFW_QDSS_TRACE_REQ_MEM_IND_MSG_V01_MAX_MSG_LEN 1124
extern struct elem_info wlfw_qdss_trace_req_mem_ind_msg_v01_ei[];
struct wlfw_qdss_trace_mem_info_req_msg_v01 {
u32 mem_seg_len;
struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
};
#define WLFW_QDSS_TRACE_MEM_INFO_REQ_MSG_V01_MAX_MSG_LEN 548
extern struct elem_info wlfw_qdss_trace_mem_info_req_msg_v01_ei[];
struct wlfw_qdss_trace_mem_info_resp_msg_v01 {
struct qmi_response_type_v01 resp;
};
#define WLFW_QDSS_TRACE_MEM_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
extern struct elem_info wlfw_qdss_trace_mem_info_resp_msg_v01_ei[];
struct wlfw_qdss_trace_save_ind_msg_v01 {
u32 source;
u32 total_size;
u8 mem_seg_valid;
u32 mem_seg_len;
struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
u8 file_name_valid;
char file_name[QMI_WLFW_MAX_STR_LEN_V01 + 1];
};
#define WLFW_QDSS_TRACE_SAVE_IND_MSG_V01_MAX_MSG_LEN 581
extern struct elem_info wlfw_qdss_trace_save_ind_msg_v01_ei[];
struct wlfw_qdss_trace_data_req_msg_v01 {
u32 seg_id;
};
#define WLFW_QDSS_TRACE_DATA_REQ_MSG_V01_MAX_MSG_LEN 7
extern struct elem_info wlfw_qdss_trace_data_req_msg_v01_ei[];
struct wlfw_qdss_trace_data_resp_msg_v01 {
struct qmi_response_type_v01 resp;
u8 total_size_valid;
u32 total_size;
u8 seg_id_valid;
u32 seg_id;
u8 data_valid;
u32 data_len;
u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
u8 end_valid;
u8 end;
};
#define WLFW_QDSS_TRACE_DATA_RESP_MSG_V01_MAX_MSG_LEN 6174
extern struct elem_info wlfw_qdss_trace_data_resp_msg_v01_ei[];
struct wlfw_qdss_trace_config_download_req_msg_v01 {
u8 total_size_valid;
u32 total_size;
u8 seg_id_valid;
u32 seg_id;
u8 data_valid;
u32 data_len;
u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
u8 end_valid;
u8 end;
};
#define WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6167
extern struct elem_info wlfw_qdss_trace_config_download_req_msg_v01_ei[];
struct wlfw_qdss_trace_config_download_resp_msg_v01 {
struct qmi_response_type_v01 resp;
};
#define WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
extern struct elem_info wlfw_qdss_trace_config_download_resp_msg_v01_ei[];
struct wlfw_qdss_trace_mode_req_msg_v01 {
u8 mode_valid;
enum wlfw_qdss_trace_mode_enum_v01 mode;
u8 option_valid;
u64 option;
};
#define WLFW_QDSS_TRACE_MODE_REQ_MSG_V01_MAX_MSG_LEN 18
extern struct elem_info wlfw_qdss_trace_mode_req_msg_v01_ei[];
struct wlfw_qdss_trace_mode_resp_msg_v01 {
struct qmi_response_type_v01 resp;
};
#define WLFW_QDSS_TRACE_MODE_RESP_MSG_V01_MAX_MSG_LEN 7
extern struct elem_info wlfw_qdss_trace_mode_resp_msg_v01_ei[];
struct wlfw_qdss_trace_free_ind_msg_v01 {
u8 mem_seg_valid;
u32 mem_seg_len;
struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
};
#define WLFW_QDSS_TRACE_FREE_IND_MSG_V01_MAX_MSG_LEN 548
extern struct elem_info wlfw_qdss_trace_free_ind_msg_v01_ei[];
struct wlfw_shutdown_req_msg_v01 {
u8 shutdown_valid;
u8 shutdown;
};
#define WLFW_SHUTDOWN_REQ_MSG_V01_MAX_MSG_LEN 4
extern struct elem_info wlfw_shutdown_req_msg_v01_ei[];
struct wlfw_shutdown_resp_msg_v01 {
struct qmi_response_type_v01 resp;
};
#define WLFW_SHUTDOWN_RESP_MSG_V01_MAX_MSG_LEN 7
extern struct elem_info wlfw_shutdown_resp_msg_v01_ei[];
#endif

View file

@ -27,9 +27,11 @@
enum cnss_bus_width_type {
CNSS_BUS_WIDTH_NONE,
CNSS_BUS_WIDTH_IDLE,
CNSS_BUS_WIDTH_LOW,
CNSS_BUS_WIDTH_MEDIUM,
CNSS_BUS_WIDTH_HIGH
CNSS_BUS_WIDTH_HIGH,
CNSS_BUS_WIDTH_VERY_HIGH,
};
enum cnss_platform_cap_flag {
@ -158,6 +160,7 @@ struct cnss_wlan_enable_cfg {
struct cnss_shadow_reg_v2_cfg *shadow_reg_v2_cfg;
bool rri_over_ddr_cfg_valid;
struct cnss_rri_over_ddr_cfg rri_over_ddr_cfg;
bool send_msi_ce;
};
enum cnss_driver_mode {