Merge 4f03c58310 on remote branch

Change-Id: I92a9213e9c300f9811e744169af6ad4d2d0fb1a0
Bu işleme şunda yer alıyor:
Linux Build Service Account
2023-03-20 15:42:56 -07:00
işleme 7cc38a20ce
20 değiştirilmiş dosya ile 1514 ekleme ve 183 silme

8
Kbuild
Dosyayı Görüntüle

@@ -36,6 +36,14 @@ ifeq ($(CONFIG_CNSS2_CONDITIONAL_POWEROFF),y)
KBUILD_CPPFLAGS += -DCONFIG_CNSS2_CONDITIONAL_POWEROFF
endif
ifeq ($(CONFIG_CNSS_REQ_FW_DIRECT),y)
KBUILD_CPPFLAGS += -DCONFIG_CNSS_REQ_FW_DIRECT
endif
ifeq ($(CONFIG_CNSS_SUPPORT_DUAL_DEV),y)
KBUILD_CPPFLAGS += -DCONFIG_CNSS_SUPPORT_DUAL_DEV
endif
ifeq ($(CONFIG_AUTO_PROJECT),y)
KBUILD_CPPFLAGS += -DCONFIG_PULLDOWN_WLANEN
endif

Dosyayı Görüntüle

@@ -11,14 +11,11 @@ WLAN_PLATFORM_ROOT = $(shell pwd)
KBUILD_OPTIONS := WLAN_PLATFORM_ROOT=$(WLAN_PLATFORM_ROOT)
ifeq ($(USE_EXTERNAL_CONFIGS),)
KBUILD_OPTIONS += CONFIG_CNSS_OUT_OF_TREE=y
ifneq (,$(filter $(CONFIG_PCI_MSM),y m))
KBUILD_OPTIONS += CONFIG_CNSS2=m
KBUILD_OPTIONS += CONFIG_CNSS2_QMI=y
KBUILD_OPTIONS += CONFIG_CNSS2_DEBUG=y
endif
KBUILD_OPTIONS += CONFIG_ICNSS2=m
KBUILD_OPTIONS += CONFIG_CNSS2_QMI=y
KBUILD_OPTIONS += CONFIG_ICNSS2_QMI=y
KBUILD_OPTIONS += CONFIG_CNSS2_DEBUG=y
KBUILD_OPTIONS += CONFIG_ICNSS2_DEBUG=y
KBUILD_OPTIONS += CONFIG_CNSS_QMI_SVC=m
KBUILD_OPTIONS += CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
@@ -29,8 +26,10 @@ KBUILD_OPTIONS += CONFIG_CNSS2_SSR_DRIVER_DUMP=y
endif
endif
all:
$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)
all: modules
%:
$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)
modules_install:
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install

Dosyayı Görüntüle

@@ -97,6 +97,14 @@ config CNSS_REQ_FW_DIRECT
configuration file to avoid 60s timeout while search file under user
space failure.
config CNSS_SUPPORT_DUAL_DEV
bool "Enable cnss2 support dual wlan card"
depends on CNSS2 && !CNSS_ASYNC
help
This enables the changes from cnss2 platform driver to support dual
wlan card attach. Now just supports QCA6390 chip and does not support
asynchronous probe.
config CNSS2_CONDITIONAL_POWEROFF
bool "Enable/Disable conditional bus suspend and device power off"
depends on CNSS2

Dosyayı Görüntüle

@@ -48,6 +48,7 @@ enum cnss_dev_bus_type cnss_get_bus_type(struct cnss_plat_data *plat_priv)
case QCA6174_DEVICE_ID:
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
case QCA6490_DEVICE_ID:
case KIWI_DEVICE_ID:
case MANGO_DEVICE_ID:
@@ -635,6 +636,46 @@ int cnss_bus_update_time_sync_period(struct cnss_plat_data *plat_priv,
}
}
int cnss_bus_set_therm_cdev_state(struct cnss_plat_data *plat_priv,
unsigned long thermal_state,
int tcdev_id)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_set_therm_cdev_state(plat_priv->bus_priv,
thermal_state,
tcdev_id);
default:
cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_get_msi_assignment(struct cnss_plat_data *plat_priv,
char *msi_name,
int *num_vectors,
u32 *user_base_data,
u32 *base_vector)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_get_user_msi_assignment(plat_priv->bus_priv,
msi_name,
num_vectors,
user_base_data,
base_vector);
default:
cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type);
return -EINVAL;
}
}
#if IS_ENABLED(CONFIG_MHI_BUS_MISC)
void cnss_bus_disable_mhi_satellite_cfg(struct cnss_plat_data *plat_priv)
{

Dosyayı Görüntüle

@@ -20,6 +20,7 @@
#define QCA6390_DEVICE_ID 0x1101
#define QCA6490_VENDOR_ID 0x17CB
#define QCA6490_DEVICE_ID 0x1103
#define QCN7605_VENDOR_ID 0x17CB
#define QCN7605_DEVICE_ID 0x1102
#define KIWI_VENDOR_ID 0x17CB
#define KIWI_DEVICE_ID 0x1107
@@ -77,4 +78,12 @@ bool cnss_bus_is_smmu_s1_enabled(struct cnss_plat_data *plat_priv);
int cnss_bus_update_time_sync_period(struct cnss_plat_data *plat_priv,
unsigned int time_sync_period);
void cnss_bus_disable_mhi_satellite_cfg(struct cnss_plat_data *plat_priv);
int cnss_bus_set_therm_cdev_state(struct cnss_plat_data *plat_priv,
unsigned long thermal_state,
int tcdev_id);
int cnss_bus_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 */

Dosyayı Görüntüle

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */
/* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */
/* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */
#include <linux/err.h>
@@ -576,6 +576,8 @@ static ssize_t cnss_runtime_pm_debug_write(struct file *fp,
buf[len] = '\0';
cmd = buf;
cnss_pr_dbg("Received runtime_pm debug command: %s\n", cmd);
if (sysfs_streq(cmd, "usage_count")) {
cnss_pci_pm_runtime_show_usage_count(pci_priv);
} else if (sysfs_streq(cmd, "request_resume")) {
@@ -944,8 +946,15 @@ int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
{
int ret = 0;
struct dentry *root_dentry;
char name[CNSS_FS_NAME_SIZE];
root_dentry = debugfs_create_dir("cnss", 0);
if (cnss_is_dual_wlan_enabled())
snprintf(name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME "_%d",
plat_priv->plat_idx);
else
snprintf(name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME);
root_dentry = debugfs_create_dir(name, 0);
if (IS_ERR(root_dentry)) {
ret = PTR_ERR(root_dentry);
cnss_pr_err("Unable to create debugfs %d\n", ret);

Dosyayı Görüntüle

@@ -17,6 +17,7 @@
#include <linux/rwsem.h>
#include <linux/suspend.h>
#include <linux/timer.h>
#include <linux/thermal.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0))
#include <linux/panic_notifier.h>
@@ -88,7 +89,13 @@ enum cnss_recovery_type {
CNSS_PCSS_RECOVERY = 0x2,
};
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
#define CNSS_MAX_DEV_NUM 2
static struct cnss_plat_data *plat_env[CNSS_MAX_DEV_NUM];
static int plat_env_count;
#else
static struct cnss_plat_data *plat_env;
#endif
static bool cnss_allow_driver_loading;
@@ -111,22 +118,174 @@ struct cnss_driver_event {
void *data;
};
bool cnss_check_driver_loading_allowed(void)
{
return cnss_allow_driver_loading;
}
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
static void cnss_set_plat_priv(struct platform_device *plat_dev,
struct cnss_plat_data *plat_priv)
{
cnss_pr_dbg("Set plat_priv at %d", plat_env_count);
if (plat_priv) {
plat_priv->plat_idx = plat_env_count;
plat_env[plat_priv->plat_idx] = plat_priv;
plat_env_count++;
}
}
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device
*plat_dev)
{
int i;
if (!plat_dev)
return NULL;
for (i = 0; i < plat_env_count; i++) {
if (plat_env[i]->plat_dev == plat_dev)
return plat_env[i];
}
return NULL;
}
static void cnss_clear_plat_priv(struct cnss_plat_data *plat_priv)
{
cnss_pr_dbg("Clear plat_priv at %d", plat_priv->plat_idx);
plat_env[plat_priv->plat_idx] = NULL;
plat_env_count--;
}
static int cnss_set_device_name(struct cnss_plat_data *plat_priv)
{
snprintf(plat_priv->device_name, sizeof(plat_priv->device_name),
"wlan_%d", plat_priv->plat_idx);
return 0;
}
static int cnss_plat_env_available(void)
{
int ret = 0;
if (plat_env_count >= CNSS_MAX_DEV_NUM) {
cnss_pr_err("ERROR: No space to store plat_priv\n");
ret = -ENOMEM;
}
return ret;
}
int cnss_get_plat_env_count(void)
{
return plat_env_count;
}
struct cnss_plat_data *cnss_get_plat_env(int index)
{
return plat_env[index];
}
struct cnss_plat_data *cnss_get_plat_priv_by_rc_num(int rc_num)
{
int i;
for (i = 0; i < plat_env_count; i++) {
if (plat_env[i]->rc_num == rc_num)
return plat_env[i];
}
return NULL;
}
static inline int
cnss_get_qrtr_node_id(struct cnss_plat_data *plat_priv)
{
return of_property_read_u32(plat_priv->dev_node,
"qcom,qrtr_node_id", &plat_priv->qrtr_node_id);
}
void cnss_get_qrtr_info(struct cnss_plat_data *plat_priv)
{
int ret = 0;
ret = cnss_get_qrtr_node_id(plat_priv);
if (ret) {
cnss_pr_warn("Failed to find qrtr_node_id err=%d\n", ret);
plat_priv->qrtr_node_id = 0;
plat_priv->wlfw_service_instance_id = 0;
} else {
plat_priv->wlfw_service_instance_id = plat_priv->qrtr_node_id +
QRTR_NODE_FW_ID_BASE;
cnss_pr_dbg("service_instance_id=0x%x\n",
plat_priv->wlfw_service_instance_id);
}
}
static inline int
cnss_get_pld_bus_ops_name(struct cnss_plat_data *plat_priv)
{
return of_property_read_string(plat_priv->plat_dev->dev.of_node,
"qcom,pld_bus_ops_name",
&plat_priv->pld_bus_ops_name);
}
#else
static void cnss_set_plat_priv(struct platform_device *plat_dev,
struct cnss_plat_data *plat_priv)
{
plat_env = plat_priv;
}
bool cnss_check_driver_loading_allowed(void)
{
return cnss_allow_driver_loading;
}
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev)
{
return plat_env;
}
static void cnss_clear_plat_priv(struct cnss_plat_data *plat_priv)
{
plat_env = NULL;
}
static int cnss_set_device_name(struct cnss_plat_data *plat_priv)
{
snprintf(plat_priv->device_name, sizeof(plat_priv->device_name),
"wlan");
return 0;
}
static int cnss_plat_env_available(void)
{
return 0;
}
struct cnss_plat_data *cnss_get_plat_priv_by_rc_num(int rc_num)
{
return cnss_bus_dev_to_plat_priv(NULL);
}
void cnss_get_qrtr_info(struct cnss_plat_data *plat_priv)
{
}
static int
cnss_get_pld_bus_ops_name(struct cnss_plat_data *plat_priv)
{
return 0;
}
#endif
static inline int
cnss_get_rc_num(struct cnss_plat_data *plat_priv)
{
return of_property_read_u32(plat_priv->plat_dev->dev.of_node,
"qcom,wlan-rc-num", &plat_priv->rc_num);
}
bool cnss_is_dual_wlan_enabled(void)
{
return IS_ENABLED(CONFIG_CNSS_SUPPORT_DUAL_DEV);
}
/**
* cnss_get_mem_seg_count - Get segment count of memory
* @type: memory type
@@ -436,6 +595,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;
@@ -639,6 +801,9 @@ static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *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;
cnss_wlfw_ini_file_send_sync(plat_priv, WLFW_CONN_ROAM_INI_V01);
ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv,
@@ -646,6 +811,9 @@ static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
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;
@@ -1212,8 +1380,6 @@ EXPORT_SYMBOL(cnss_idle_restart);
int cnss_idle_shutdown(struct device *dev)
{
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
unsigned int timeout;
int ret;
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL\n");
@@ -1227,21 +1393,12 @@ int cnss_idle_shutdown(struct device *dev)
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);
timeout = cnss_get_timeout(plat_priv, CNSS_TIMEOUT_RECOVERY);
ret = wait_for_completion_timeout(&plat_priv->recovery_complete,
msecs_to_jiffies(timeout));
if (!ret) {
cnss_pr_err("Timeout (%ums) waiting for recovery to complete\n",
timeout);
CNSS_ASSERT(0);
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) ||
test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
cnss_pr_dbg("Recovery in progress. Ignore IDLE Shutdown\n");
return -EBUSY;
}
skip_wait:
return cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
@@ -2187,8 +2344,14 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv,
cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF);
cnss_bus_free_qdss_mem(plat_priv);
cnss_release_antenna_sharing(plat_priv);
if (plat_priv->device_id == QCN7605_DEVICE_ID)
goto skip_shutdown;
cnss_bus_dev_shutdown(plat_priv);
msleep(POWER_RESET_MIN_DELAY_MS);
skip_shutdown:
complete(&plat_priv->cal_complete);
clear_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state);
set_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state);
@@ -2482,7 +2645,7 @@ int cnss_register_subsys(struct cnss_plat_data *plat_priv)
subsys_info = &plat_priv->subsys_info;
subsys_info->subsys_desc.name = "wlan";
subsys_info->subsys_desc.name = plat_priv->device_name;
subsys_info->subsys_desc.owner = THIS_MODULE;
subsys_info->subsys_desc.powerup = cnss_subsys_powerup;
subsys_info->subsys_desc.shutdown = cnss_subsys_shutdown;
@@ -3225,6 +3388,7 @@ int cnss_register_ramdump(struct cnss_plat_data *plat_priv)
break;
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
case QCA6490_DEVICE_ID:
case KIWI_DEVICE_ID:
case MANGO_DEVICE_ID:
@@ -3247,6 +3411,7 @@ void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
break;
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
case QCA6490_DEVICE_ID:
case KIWI_DEVICE_ID:
case MANGO_DEVICE_ID:
@@ -3861,8 +4026,21 @@ static int cnss_create_sysfs_link(struct cnss_plat_data *plat_priv)
{
struct device *dev = &plat_priv->plat_dev->dev;
int ret;
char cnss_name[CNSS_FS_NAME_SIZE];
char shutdown_name[32];
ret = sysfs_create_link(kernel_kobj, &dev->kobj, "cnss");
if (cnss_is_dual_wlan_enabled()) {
snprintf(cnss_name, CNSS_FS_NAME_SIZE,
CNSS_FS_NAME "_%d", plat_priv->plat_idx);
snprintf(shutdown_name, sizeof(shutdown_name),
"shutdown_wlan_%d", plat_priv->plat_idx);
} else {
snprintf(cnss_name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME);
snprintf(shutdown_name, sizeof(shutdown_name),
"shutdown_wlan");
}
ret = sysfs_create_link(kernel_kobj, &dev->kobj, cnss_name);
if (ret) {
cnss_pr_err("Failed to create cnss link, err = %d\n",
ret);
@@ -3870,7 +4048,7 @@ static int cnss_create_sysfs_link(struct cnss_plat_data *plat_priv)
}
/* This is only for backward compatibility. */
ret = sysfs_create_link(kernel_kobj, &dev->kobj, "shutdown_wlan");
ret = sysfs_create_link(kernel_kobj, &dev->kobj, shutdown_name);
if (ret) {
cnss_pr_err("Failed to create shutdown_wlan link, err = %d\n",
ret);
@@ -3880,15 +4058,29 @@ static int cnss_create_sysfs_link(struct cnss_plat_data *plat_priv)
return 0;
rm_cnss_link:
sysfs_remove_link(kernel_kobj, "cnss");
sysfs_remove_link(kernel_kobj, cnss_name);
out:
return ret;
}
static void cnss_remove_sysfs_link(struct cnss_plat_data *plat_priv)
{
sysfs_remove_link(kernel_kobj, "shutdown_wlan");
sysfs_remove_link(kernel_kobj, "cnss");
char cnss_name[CNSS_FS_NAME_SIZE];
char shutdown_name[32];
if (cnss_is_dual_wlan_enabled()) {
snprintf(cnss_name, CNSS_FS_NAME_SIZE,
CNSS_FS_NAME "_%d", plat_priv->plat_idx);
snprintf(shutdown_name, sizeof(shutdown_name),
"shutdown_wlan_%d", plat_priv->plat_idx);
} else {
snprintf(cnss_name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME);
snprintf(shutdown_name, sizeof(shutdown_name),
"shutdown_wlan");
}
sysfs_remove_link(kernel_kobj, shutdown_name);
sysfs_remove_link(kernel_kobj, cnss_name);
}
static int cnss_create_sysfs(struct cnss_plat_data *plat_priv)
@@ -4095,6 +4287,7 @@ static void cnss_misc_deinit(struct cnss_plat_data *plat_priv)
wakeup_source_unregister(plat_priv->recovery_ws);
cnss_deinit_sol_gpio(plat_priv);
kfree(plat_priv->sram_dump);
kfree(plat_priv->on_chip_pmic_board_ids);
}
static void cnss_init_control_params(struct cnss_plat_data *plat_priv)
@@ -4358,6 +4551,195 @@ int cnss_set_wfc_mode(struct device *dev, struct cnss_wfc_cfg cfg)
}
EXPORT_SYMBOL(cnss_set_wfc_mode);
static int cnss_tcdev_get_max_state(struct thermal_cooling_device *tcdev,
unsigned long *thermal_state)
{
struct cnss_thermal_cdev *cnss_tcdev = NULL;
if (!tcdev || !tcdev->devdata) {
cnss_pr_err("tcdev or tcdev->devdata is null!\n");
return -EINVAL;
}
cnss_tcdev = tcdev->devdata;
*thermal_state = cnss_tcdev->max_thermal_state;
return 0;
}
static int cnss_tcdev_get_cur_state(struct thermal_cooling_device *tcdev,
unsigned long *thermal_state)
{
struct cnss_thermal_cdev *cnss_tcdev = NULL;
if (!tcdev || !tcdev->devdata) {
cnss_pr_err("tcdev or tcdev->devdata is null!\n");
return -EINVAL;
}
cnss_tcdev = tcdev->devdata;
*thermal_state = cnss_tcdev->curr_thermal_state;
return 0;
}
static int cnss_tcdev_set_cur_state(struct thermal_cooling_device *tcdev,
unsigned long thermal_state)
{
struct cnss_thermal_cdev *cnss_tcdev = NULL;
struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
int ret = 0;
if (!tcdev || !tcdev->devdata) {
cnss_pr_err("tcdev or tcdev->devdata is null!\n");
return -EINVAL;
}
cnss_tcdev = tcdev->devdata;
if (thermal_state > cnss_tcdev->max_thermal_state)
return -EINVAL;
cnss_pr_vdbg("Cooling device set current state: %ld,for cdev id %d",
thermal_state, cnss_tcdev->tcdev_id);
mutex_lock(&plat_priv->tcdev_lock);
ret = cnss_bus_set_therm_cdev_state(plat_priv,
thermal_state,
cnss_tcdev->tcdev_id);
if (!ret)
cnss_tcdev->curr_thermal_state = thermal_state;
mutex_unlock(&plat_priv->tcdev_lock);
if (ret) {
cnss_pr_err("Setting Current Thermal State Failed: %d,for cdev id %d",
ret, cnss_tcdev->tcdev_id);
return ret;
}
return 0;
}
static struct thermal_cooling_device_ops cnss_cooling_ops = {
.get_max_state = cnss_tcdev_get_max_state,
.get_cur_state = cnss_tcdev_get_cur_state,
.set_cur_state = cnss_tcdev_set_cur_state,
};
int cnss_thermal_cdev_register(struct device *dev, unsigned long max_state,
int tcdev_id)
{
struct cnss_plat_data *priv = cnss_get_plat_priv(NULL);
struct cnss_thermal_cdev *cnss_tcdev = NULL;
char cdev_node_name[THERMAL_NAME_LENGTH] = "";
struct device_node *dev_node;
int ret = 0;
if (!priv) {
cnss_pr_err("Platform driver is not initialized!\n");
return -ENODEV;
}
cnss_tcdev = kzalloc(sizeof(*cnss_tcdev), GFP_KERNEL);
if (!cnss_tcdev) {
cnss_pr_err("Failed to allocate cnss_tcdev object!\n");
return -ENOMEM;
}
cnss_tcdev->tcdev_id = tcdev_id;
cnss_tcdev->max_thermal_state = max_state;
snprintf(cdev_node_name, THERMAL_NAME_LENGTH,
"qcom,cnss_cdev%d", tcdev_id);
dev_node = of_find_node_by_name(NULL, cdev_node_name);
if (!dev_node) {
cnss_pr_err("Failed to get cooling device node\n");
kfree(cnss_tcdev);
return -EINVAL;
}
cnss_pr_dbg("tcdev node->name=%s\n", dev_node->name);
if (of_find_property(dev_node, "#cooling-cells", NULL)) {
cnss_tcdev->tcdev = thermal_of_cooling_device_register(dev_node,
cdev_node_name,
cnss_tcdev,
&cnss_cooling_ops);
if (IS_ERR_OR_NULL(cnss_tcdev->tcdev)) {
ret = PTR_ERR(cnss_tcdev->tcdev);
cnss_pr_err("Cooling device register failed: %d, for cdev id %d\n",
ret, cnss_tcdev->tcdev_id);
kfree(cnss_tcdev);
} else {
cnss_pr_dbg("Cooling device registered for cdev id %d",
cnss_tcdev->tcdev_id);
mutex_lock(&priv->tcdev_lock);
list_add(&cnss_tcdev->tcdev_list,
&priv->cnss_tcdev_list);
mutex_unlock(&priv->tcdev_lock);
}
} else {
cnss_pr_dbg("Cooling device registration not supported");
kfree(cnss_tcdev);
ret = -EOPNOTSUPP;
}
return ret;
}
EXPORT_SYMBOL(cnss_thermal_cdev_register);
void cnss_thermal_cdev_unregister(struct device *dev, int tcdev_id)
{
struct cnss_plat_data *priv = cnss_get_plat_priv(NULL);
struct cnss_thermal_cdev *cnss_tcdev = NULL;
if (!priv) {
cnss_pr_err("Platform driver is not initialized!\n");
return;
}
mutex_lock(&priv->tcdev_lock);
while (!list_empty(&priv->cnss_tcdev_list)) {
cnss_tcdev = list_first_entry(&priv->cnss_tcdev_list,
struct cnss_thermal_cdev,
tcdev_list);
thermal_cooling_device_unregister(cnss_tcdev->tcdev);
list_del(&cnss_tcdev->tcdev_list);
kfree(cnss_tcdev);
}
mutex_unlock(&priv->tcdev_lock);
}
EXPORT_SYMBOL(cnss_thermal_cdev_unregister);
int cnss_get_curr_therm_cdev_state(struct device *dev,
unsigned long *thermal_state,
int tcdev_id)
{
struct cnss_plat_data *priv = cnss_get_plat_priv(NULL);
struct cnss_thermal_cdev *cnss_tcdev = NULL;
if (!priv) {
cnss_pr_err("Platform driver is not initialized!\n");
return -ENODEV;
}
mutex_lock(&priv->tcdev_lock);
list_for_each_entry(cnss_tcdev, &priv->cnss_tcdev_list, tcdev_list) {
if (cnss_tcdev->tcdev_id != tcdev_id)
continue;
*thermal_state = cnss_tcdev->curr_thermal_state;
mutex_unlock(&priv->tcdev_lock);
cnss_pr_dbg("Cooling device current state: %ld, for cdev id %d",
cnss_tcdev->curr_thermal_state, tcdev_id);
return 0;
}
mutex_unlock(&priv->tcdev_lock);
cnss_pr_dbg("Cooling device ID not found: %d", tcdev_id);
return -EINVAL;
}
EXPORT_SYMBOL(cnss_get_curr_therm_cdev_state);
static int cnss_probe(struct platform_device *plat_dev)
{
int ret = 0;
@@ -4371,6 +4753,10 @@ static int cnss_probe(struct platform_device *plat_dev)
goto out;
}
ret = cnss_plat_env_available();
if (ret)
goto out;
of_id = of_match_device(cnss_of_match_table, &plat_dev->dev);
if (!of_id || !of_id->data) {
cnss_pr_err("Failed to find of match device!\n");
@@ -4403,10 +4789,23 @@ static int cnss_probe(struct platform_device *plat_dev)
goto reset_plat_dev;
}
ret = cnss_get_pld_bus_ops_name(plat_priv);
if (ret)
cnss_pr_err("Failed to find bus ops name, err = %d\n",
ret);
ret = cnss_get_rc_num(plat_priv);
if (ret)
cnss_pr_err("Failed to find PCIe RC number, err = %d\n", ret);
cnss_pr_dbg("rc_num=%d\n", plat_priv->rc_num);
plat_priv->bus_type = cnss_get_bus_type(plat_priv);
plat_priv->use_nv_mac = cnss_use_nv_mac(plat_priv);
plat_priv->driver_mode = CNSS_DRIVER_MODE_MAX;
cnss_set_plat_priv(plat_dev, plat_priv);
cnss_set_device_name(plat_priv);
platform_set_drvdata(plat_dev, plat_priv);
INIT_LIST_HEAD(&plat_priv->vreg_list);
INIT_LIST_HEAD(&plat_priv->clk_list);
@@ -4439,13 +4838,9 @@ static int cnss_probe(struct platform_device *plat_dev)
if (ret)
goto remove_sysfs;
ret = cnss_qmi_init(plat_priv);
if (ret)
goto deinit_event_work;
ret = cnss_dms_init(plat_priv);
if (ret)
goto deinit_qmi;
goto deinit_event_work;
ret = cnss_debugfs_create(plat_priv);
if (ret)
@@ -4472,9 +4867,8 @@ static int cnss_probe(struct platform_device *plat_dev)
cnss_register_coex_service(plat_priv);
cnss_register_ims_service(plat_priv);
ret = cnss_genl_init();
if (ret < 0)
cnss_pr_err("CNSS genl init failed %d\n", ret);
mutex_init(&plat_priv->tcdev_lock);
INIT_LIST_HEAD(&plat_priv->cnss_tcdev_list);
cnss_pr_info("Platform driver probed successfully.\n");
@@ -4486,8 +4880,6 @@ destroy_debugfs:
cnss_debugfs_destroy(plat_priv);
deinit_dms:
cnss_dms_deinit(plat_priv);
deinit_qmi:
cnss_qmi_deinit(plat_priv);
deinit_event_work:
cnss_event_work_deinit(plat_priv);
remove_sysfs:
@@ -4501,7 +4893,7 @@ free_res:
reset_ctx:
platform_set_drvdata(plat_dev, NULL);
reset_plat_dev:
cnss_set_plat_priv(plat_dev, NULL);
cnss_clear_plat_priv(plat_priv);
out:
return ret;
}
@@ -4530,7 +4922,7 @@ static int cnss_remove(struct platform_device *plat_dev)
mbox_free_channel(plat_priv->mbox_chan);
platform_set_drvdata(plat_dev, NULL);
plat_env = NULL;
cnss_clear_plat_priv(plat_priv);
return 0;
}
@@ -4599,11 +4991,16 @@ static int __init cnss_initialize(void)
if (ret)
cnss_debug_deinit();
ret = cnss_genl_init();
if (ret < 0)
cnss_pr_err("CNSS genl init failed %d\n", ret);
return ret;
}
static void __exit cnss_exit(void)
{
cnss_genl_exit();
platform_driver_unregister(&cnss_platform_driver);
cnss_debug_deinit();
}

Dosyayı Görüntüle

@@ -55,7 +55,17 @@
#define CNSS_RAMDUMP_VERSION 0
#define MAX_FIRMWARE_NAME_LEN 40
#define FW_V2_NUMBER 2
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
#define POWER_ON_RETRY_MAX_TIMES 2
#else
#define POWER_ON_RETRY_MAX_TIMES 4
#endif
#define POWER_ON_RETRY_DELAY_MS 500
#define CNSS_FS_NAME "cnss"
#define CNSS_FS_NAME_SIZE 15
#define CNSS_DEVICE_NAME_SIZE 16
#define QRTR_NODE_FW_ID_BASE 7
#define POWER_ON_RETRY_DELAY_MS 500
#define WLFW_MAX_HANG_EVENT_DATA_SIZE 384
@@ -458,6 +468,15 @@ struct cnss_sol_gpio {
int host_sol_gpio;
};
struct cnss_thermal_cdev {
struct list_head tcdev_list;
int tcdev_id;
unsigned long curr_thermal_state;
unsigned long max_thermal_state;
struct device_node *dev_node;
struct thermal_cooling_device *tcdev;
};
struct cnss_plat_data {
struct platform_device *plat_dev;
void *bus_priv;
@@ -490,6 +509,8 @@ struct cnss_plat_data {
u8 hds_enabled;
unsigned long driver_state;
struct list_head event_list;
struct list_head cnss_tcdev_list;
struct mutex tcdev_lock; /* mutex for cooling devices list access */
spinlock_t event_lock; /* spinlock for driver work event handling */
struct work_struct event_work;
struct workqueue_struct *event_wq;
@@ -578,6 +599,14 @@ struct cnss_plat_data {
uint32_t num_shadow_regs_v3;
bool sec_peri_feature_disable;
struct device_node *dev_node;
char device_name[CNSS_DEVICE_NAME_SIZE];
u32 plat_idx;
bool enumerate_done;
int qrtr_node_id;
unsigned int wlfw_service_instance_id;
const char *pld_bus_ops_name;
u32 on_chip_pmic_devices_count;
u32 *on_chip_pmic_board_ids;
};
#if IS_ENABLED(CONFIG_ARCH_QCOM)
@@ -605,6 +634,11 @@ int cnss_wlan_hw_enable(void);
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
void cnss_pm_stay_awake(struct cnss_plat_data *plat_priv);
void cnss_pm_relax(struct cnss_plat_data *plat_priv);
struct cnss_plat_data *cnss_get_plat_priv_by_rc_num(int rc_num);
int cnss_get_plat_env_count(void);
struct cnss_plat_data *cnss_get_plat_env(int index);
void cnss_get_qrtr_info(struct cnss_plat_data *plat_priv);
bool cnss_is_dual_wlan_enabled(void);
int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
enum cnss_driver_event_type type,
u32 flags, void *data);

Dosyayı Görüntüle

@@ -35,13 +35,14 @@
#define PCI_DMA_MASK_32_BIT DMA_BIT_MASK(32)
#define PCI_DMA_MASK_36_BIT DMA_BIT_MASK(36)
#define PCI_DMA_MASK_64_BIT DMA_BIT_MASK(64)
#define PCI_DMA_MASK_64_BIT ~0ULL
#define MHI_NODE_NAME "qcom,mhi"
#define MHI_MSI_NAME "MHI"
#define QCA6390_PATH_PREFIX "qca6390/"
#define QCA6490_PATH_PREFIX "qca6490/"
#define QCN7605_PATH_PREFIX "qcn7605/"
#define KIWI_PATH_PREFIX "kiwi/"
#define MANGO_PATH_PREFIX "mango/"
#define PEACH_PATH_PREFIX "peach/"
@@ -68,6 +69,8 @@
#define CNSS_256KB_SIZE 0x40000
#define DEVICE_RDDM_COOKIE 0xCAFECACE
static bool cnss_driver_registered;
static DEFINE_SPINLOCK(pci_link_down_lock);
static DEFINE_SPINLOCK(pci_reg_window_lock);
static DEFINE_SPINLOCK(time_sync_lock);
@@ -82,6 +85,8 @@ static DEFINE_SPINLOCK(time_sync_lock);
#define FORCE_WAKE_DELAY_MAX_US 6000
#define FORCE_WAKE_DELAY_TIMEOUT_US 60000
#define REG_RETRY_MAX_TIMES 3
#define MHI_SUSPEND_RETRY_MAX_TIMES 3
#define MHI_SUSPEND_RETRY_DELAY_US 5000
@@ -244,6 +249,93 @@ static const struct mhi_channel_config cnss_mhi_channels[] = {
#endif
};
static const struct mhi_channel_config cnss_mhi_channels_genoa[] = {
{
.num = 0,
.name = "LOOPBACK",
.num_elements = 32,
.event_ring = 1,
.dir = DMA_TO_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 1,
.name = "LOOPBACK",
.num_elements = 32,
.event_ring = 1,
.dir = DMA_FROM_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 4,
.name = "DIAG",
.num_elements = 64,
.event_ring = 1,
.dir = DMA_TO_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 5,
.name = "DIAG",
.num_elements = 64,
.event_ring = 1,
.dir = DMA_FROM_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 16,
.name = "IPCR",
.num_elements = 64,
.event_ring = 1,
.dir = DMA_TO_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 17,
.name = "IPCR",
.num_elements = 64,
.event_ring = 1,
.dir = DMA_FROM_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
},
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
static struct mhi_event_config cnss_mhi_events[] = {
#else
@@ -322,6 +414,20 @@ static const struct mhi_controller_config cnss_mhi_config_default = {
.m2_no_db = true,
};
static const struct mhi_controller_config cnss_mhi_config_genoa = {
.max_channels = 32,
.timeout_ms = 10000,
.use_bounce_buf = false,
.buf_len = 0x8000,
.num_channels = ARRAY_SIZE(cnss_mhi_channels_genoa),
.ch_cfg = cnss_mhi_channels_genoa,
.num_events = ARRAY_SIZE(cnss_mhi_events) -
CNSS_MHI_SATELLITE_EVT_COUNT,
.event_cfg = cnss_mhi_events,
.m2_no_db = true,
.bhie_offset = 0x0324,
};
static const struct mhi_controller_config cnss_mhi_config_no_satellite = {
.max_channels = 32,
.timeout_ms = 10000,
@@ -667,6 +773,9 @@ static struct cnss_print_optimize print_optimize;
#define SYSPM_REG_SIZE ARRAY_SIZE(syspm_reg_access_seq)
static int cnss_pci_update_fw_name(struct cnss_pci_data *pci_priv);
static void cnss_pci_suspend_pwroff(struct pci_dev *pci_dev);
static bool cnss_should_suspend_pwroff(struct pci_dev *pci_dev);
#if IS_ENABLED(CONFIG_MHI_BUS_MISC)
static void cnss_mhi_debug_reg_dump(struct cnss_pci_data *pci_priv)
@@ -826,6 +935,9 @@ static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset)
QCA6390_PCIE_REMAP_BAR_CTRL_OFFSET);
}
if (plat_priv->device_id == QCN7605_DEVICE_ID)
window_enable = QCN7605_WINDOW_ENABLE_BIT | window;
if (window != pci_priv->remap_window) {
pci_priv->remap_window = window;
cnss_pr_dbg("Config PCIe remap window register to 0x%x\n",
@@ -1809,6 +1921,18 @@ static void cnss_pci_set_mhi_state_bit(struct cnss_pci_data *pci_priv,
}
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0))
static int cnss_mhi_pm_force_resume(struct cnss_pci_data *pci_priv)
{
return mhi_pm_resume_force(pci_priv->mhi_ctrl);
}
#else
static int cnss_mhi_pm_force_resume(struct cnss_pci_data *pci_priv)
{
return mhi_pm_resume(pci_priv->mhi_ctrl);
}
#endif
static int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv,
enum cnss_mhi_state mhi_state)
{
@@ -1881,7 +2005,10 @@ retry_mhi_suspend:
ret = cnss_mhi_pm_fast_resume(pci_priv, true);
cnss_pci_allow_l1(&pci_priv->pci_dev->dev);
} else {
ret = mhi_pm_resume(pci_priv->mhi_ctrl);
if (pci_priv->device_id == QCA6390_DEVICE_ID)
ret = cnss_mhi_pm_force_resume(pci_priv);
else
ret = mhi_pm_resume(pci_priv->mhi_ctrl);
}
mutex_unlock(&pci_priv->mhi_ctrl->pm_mutex);
break;
@@ -1933,11 +2060,158 @@ static int cnss_pci_config_msi_data(struct cnss_pci_data *pci_priv)
return 0;
}
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
#define PLC_PCIE_NAME_LEN 14
static struct cnss_plat_data *
cnss_get_plat_priv_by_driver_ops(struct cnss_wlan_driver *driver_ops)
{
int plat_env_count = cnss_get_plat_env_count();
struct cnss_plat_data *plat_env;
struct cnss_pci_data *pci_priv;
int i = 0;
if (!driver_ops) {
cnss_pr_err("No cnss driver\n");
return NULL;
}
for (i = 0; i < plat_env_count; i++) {
plat_env = cnss_get_plat_env(i);
if (!plat_env)
continue;
if (driver_ops->name && plat_env->pld_bus_ops_name) {
/* driver_ops->name = PLD_PCIE_OPS_NAME
* #ifdef MULTI_IF_NAME
* #define PLD_PCIE_OPS_NAME "pld_pcie_" MULTI_IF_NAME
* #else
* #define PLD_PCIE_OPS_NAME "pld_pcie"
* #endif
*/
if (memcmp(driver_ops->name,
plat_env->pld_bus_ops_name,
PLC_PCIE_NAME_LEN) == 0)
return plat_env;
}
}
cnss_pr_err("Invalid cnss driver name from ko %s\n", driver_ops->name);
/* in the dual wlan card case, the pld_bus_ops_name from dts
* and driver_ops-> name from ko should match, otherwise
* wlanhost driver don't know which plat_env it can use;
* if doesn't find the match one, then get first available
* instance insteadly.
*/
for (i = 0; i < plat_env_count; i++) {
plat_env = cnss_get_plat_env(i);
if (!plat_env)
continue;
pci_priv = plat_env->bus_priv;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
continue;
}
if (driver_ops == pci_priv->driver_ops)
return plat_env;
}
/* Doesn't find the existing instance,
* so return the fist empty instance
*/
for (i = 0; i < plat_env_count; i++) {
plat_env = cnss_get_plat_env(i);
if (!plat_env)
continue;
pci_priv = plat_env->bus_priv;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
continue;
}
if (!pci_priv->driver_ops)
return plat_env;
}
return NULL;
}
static int cnss_pci_store_qrtr_node_id(struct cnss_pci_data *pci_priv)
{
int ret = 0;
u32 scratch = QCA6390_PCIE_SOC_PCIE_REG_PCIE_SCRATCH_2_SOC_PCIE_REG;
struct cnss_plat_data *plat_priv;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
return -ENODEV;
}
plat_priv = pci_priv->plat_priv;
/**
* in the single wlan chipset case, plat_priv->qrtr_node_id always is 0,
* wlan fw will use the hardcode 7 as the qrtr node id.
* in the dual Hastings case, we will read qrtr node id
* from device tree and pass to get plat_priv->qrtr_node_id,
* which always is not zero. And then store this new value
* to pcie register, wlan fw will read out this qrtr node id
* from this register and overwrite to the hardcode one
* while do initialization for ipc router.
* without this change, two Hastings will use the same
* qrtr node instance id, which will mess up qmi message
* exchange. According to qrtr spec, every node should
* have unique qrtr node id
*/
if (plat_priv->device_id == QCA6390_DEVICE_ID &&
plat_priv->qrtr_node_id) {
u32 val;
cnss_pr_dbg("write 0x%x to SCRATCH REG\n",
plat_priv->qrtr_node_id);
ret = cnss_pci_reg_write(pci_priv, scratch,
plat_priv->qrtr_node_id);
if (ret) {
cnss_pr_err("Failed to write register offset 0x%x, err = %d\n",
scratch, ret);
goto out;
}
ret = cnss_pci_reg_read(pci_priv, scratch, &val);
if (ret) {
cnss_pr_err("Failed to read SCRATCH REG");
goto out;
}
if (val != plat_priv->qrtr_node_id) {
cnss_pr_err("qrtr node id write to register doesn't match with readout value");
return -ERANGE;
}
}
out:
return ret;
}
#else
static struct cnss_plat_data *
cnss_get_plat_priv_by_driver_ops(struct cnss_wlan_driver *driver_ops)
{
return cnss_bus_dev_to_plat_priv(NULL);
}
static int cnss_pci_store_qrtr_node_id(struct cnss_pci_data *pci_priv)
{
return 0;
}
#endif
int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv)
{
int ret = 0;
struct cnss_plat_data *plat_priv;
unsigned int timeout = 0;
int retry = 0;
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL\n");
@@ -1963,6 +2237,15 @@ int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv)
else /* For perf builds the timeout is 10 (default) * 3 seconds */
pci_priv->mhi_ctrl->timeout_ms *= 3;
retry:
ret = cnss_pci_store_qrtr_node_id(pci_priv);
if (ret) {
if (retry++ < REG_RETRY_MAX_TIMES)
goto retry;
else
return ret;
}
/* Start the timer to dump MHI/PBL/SBL debug data periodically */
mod_timer(&pci_priv->boot_debug_timer,
jiffies + msecs_to_jiffies(BOOT_DEBUG_TIMEOUT_MS));
@@ -2312,6 +2595,25 @@ static void cnss_pci_stop_time_sync_update(struct cnss_pci_data *pci_priv)
cancel_delayed_work_sync(&pci_priv->time_sync_work);
}
int cnss_pci_set_therm_cdev_state(struct cnss_pci_data *pci_priv,
unsigned long thermal_state,
int tcdev_id)
{
if (!pci_priv) {
cnss_pr_err("pci_priv is NULL!\n");
return -ENODEV;
}
if (!pci_priv->driver_ops || !pci_priv->driver_ops->set_therm_cdev_state) {
cnss_pr_err("driver_ops or set_therm_cdev_state is NULL\n");
return -EINVAL;
}
return pci_priv->driver_ops->set_therm_cdev_state(pci_priv->pci_dev,
thermal_state,
tcdev_id);
}
int cnss_pci_update_time_sync_period(struct cnss_pci_data *pci_priv,
unsigned int time_sync_period)
{
@@ -2844,7 +3146,9 @@ static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
del_timer(&pci_priv->dev_rddm_timer);
cnss_pci_collect_dump_info(pci_priv, false);
CNSS_ASSERT(0);
if (!plat_priv->recovery_enabled)
CNSS_ASSERT(0);
}
if (!cnss_is_device_powered_on(plat_priv)) {
@@ -2937,6 +3241,7 @@ int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv)
break;
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
case QCA6490_DEVICE_ID:
case KIWI_DEVICE_ID:
case MANGO_DEVICE_ID:
@@ -2967,6 +3272,7 @@ int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv)
break;
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
case QCA6490_DEVICE_ID:
case KIWI_DEVICE_ID:
case MANGO_DEVICE_ID:
@@ -2997,6 +3303,7 @@ int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv)
break;
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
case QCA6490_DEVICE_ID:
case KIWI_DEVICE_ID:
case MANGO_DEVICE_ID:
@@ -3027,6 +3334,7 @@ int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv)
break;
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
case QCA6490_DEVICE_ID:
case KIWI_DEVICE_ID:
case MANGO_DEVICE_ID:
@@ -3111,7 +3419,7 @@ reg_driver:
int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
{
int ret = 0;
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
struct cnss_plat_data *plat_priv;
struct cnss_pci_data *pci_priv;
const struct pci_device_id *id_table = driver_ops->id_table;
unsigned int timeout;
@@ -3121,6 +3429,8 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
return -ENODEV;
}
plat_priv = cnss_get_plat_priv_by_driver_ops(driver_ops);
if (!plat_priv) {
cnss_pr_buf("plat_priv is not ready for register driver\n");
return -EAGAIN;
@@ -3216,10 +3526,11 @@ EXPORT_SYMBOL(cnss_wlan_register_driver);
void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
{
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
struct cnss_plat_data *plat_priv;
int ret = 0;
unsigned int timeout;
plat_priv = cnss_get_plat_priv_by_driver_ops(driver_ops);
if (!plat_priv) {
cnss_pr_err("plat_priv is NULL\n");
return;
@@ -3426,7 +3737,8 @@ out:
static int cnss_pci_suspend(struct device *dev)
{
int ret = 0;
struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
struct pci_dev *pci_dev = to_pci_dev(dev);
struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
struct cnss_plat_data *plat_priv;
if (!pci_priv)
@@ -3439,6 +3751,25 @@ static int cnss_pci_suspend(struct device *dev)
if (!cnss_is_device_powered_on(plat_priv))
goto out;
/* No mhi state bit set if only finish pcie enumeration,
* so test_bit is not applicable to check if it is INIT state.
*/
if (pci_priv->mhi_state == CNSS_MHI_INIT) {
bool suspend = cnss_should_suspend_pwroff(pci_dev);
/* Do PCI link suspend and power off in the LPM case
* if chipset didn't do that after pcie enumeration.
*/
if (!suspend) {
ret = cnss_suspend_pci_link(pci_priv);
if (ret)
cnss_pr_err("Failed to suspend PCI link, err = %d\n",
ret);
cnss_power_off_device(plat_priv);
goto out;
}
}
if (!test_bit(DISABLE_DRV, &plat_priv->ctrl_params.quirks) &&
pci_priv->drv_supported) {
pci_priv->drv_connected_last =
@@ -4614,6 +4945,19 @@ int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info)
}
EXPORT_SYMBOL(cnss_get_soc_info);
int cnss_pci_get_user_msi_assignment(struct cnss_pci_data *pci_priv,
char *user_name,
int *num_vectors,
u32 *user_base_data,
u32 *base_vector)
{
return cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
user_name,
num_vectors,
user_base_data,
base_vector);
}
static int cnss_pci_enable_msi(struct cnss_pci_data *pci_priv)
{
int ret = 0;
@@ -4852,6 +5196,9 @@ static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv)
case PEACH_DEVICE_ID:
pci_priv->dma_bit_mask = PCI_DMA_MASK_36_BIT;
break;
case QCN7605_DEVICE_ID:
pci_priv->dma_bit_mask = PCI_DMA_MASK_64_BIT;
break;
default:
pci_priv->dma_bit_mask = PCI_DMA_MASK_32_BIT;
break;
@@ -5483,6 +5830,10 @@ void cnss_pci_add_fw_prefix_name(struct cnss_pci_data *pci_priv,
}
switch (pci_priv->device_id) {
case QCN7605_DEVICE_ID:
scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN,
QCN7605_PATH_PREFIX "%s", name);
break;
case QCA6390_DEVICE_ID:
scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN,
QCA6390_PATH_PREFIX "%s", name);
@@ -5897,6 +6248,21 @@ exit:
return ret;
}
static bool cnss_is_tme_supported(struct cnss_pci_data *pci_priv)
{
if (!pci_priv) {
cnss_pr_dbg("pci_priv is NULL");
return false;
}
switch (pci_priv->device_id) {
case PEACH_DEVICE_ID:
return true;
default:
return false;
}
}
static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
{
int ret = 0;
@@ -5907,6 +6273,10 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
const struct mhi_controller_config *cnss_mhi_config =
&cnss_mhi_config_default;
ret = cnss_qmi_init(plat_priv);
if (ret)
return -EINVAL;
if (pci_priv->device_id == QCA6174_DEVICE_ID)
return 0;
@@ -5957,7 +6327,12 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
mhi_ctrl->rddm_size = pci_priv->plat_priv->ramdump_info_v2.ramdump_size;
if (!mhi_ctrl->rddm_size)
mhi_ctrl->rddm_size = RAMDUMP_SIZE_DEFAULT;
mhi_ctrl->sbl_size = SZ_512K;
if (plat_priv->device_id == QCN7605_DEVICE_ID)
mhi_ctrl->sbl_size = SZ_256K;
else
mhi_ctrl->sbl_size = SZ_512K;
mhi_ctrl->seg_len = SZ_512K;
mhi_ctrl->fbc_download = true;
@@ -5967,9 +6342,15 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
/* Satellite config only supported on KIWI V2 and later chipset */
if (plat_priv->device_id <= QCA6490_DEVICE_ID ||
(plat_priv->device_id == KIWI_DEVICE_ID &&
plat_priv->device_version.major_version == 1))
cnss_mhi_config = &cnss_mhi_config_no_satellite;
(plat_priv->device_id == KIWI_DEVICE_ID &&
plat_priv->device_version.major_version == 1)) {
if (plat_priv->device_id == QCN7605_DEVICE_ID)
cnss_mhi_config = &cnss_mhi_config_genoa;
else
cnss_mhi_config = &cnss_mhi_config_no_satellite;
}
mhi_ctrl->tme_supported_image = cnss_is_tme_supported(pci_priv);
ret = mhi_register_controller(mhi_ctrl, cnss_mhi_config);
if (ret) {
@@ -6150,6 +6531,57 @@ static void cnss_pci_wake_gpio_deinit(struct cnss_pci_data *pci_priv)
}
#endif
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
static int cnss_try_suspend(struct cnss_plat_data *plat_priv)
{
int ret = 0;
/* in the dual wlan card case, if call pci_register_driver after
* finishing the first pcie device enumeration, it will cause
* the cnss_pci_probe called in advance with the second wlan card,
* and the sequence like this:
* enter msm_pcie_enumerate -> pci_bus_add_devices -> cnss_pci_probe
* -> exit msm_pcie_enumerate.
* But the correct sequence we expected is like this:
* enter msm_pcie_enumerate -> pci_bus_add_devices ->
* exit msm_pcie_enumerate -> cnss_pci_probe.
* And this unexpected sequence will make the second wlan card do
* pcie link suspend while the pcie enumeration not finished.
* So need to add below logical to avoid doing pcie link suspend
* if the enumeration has not finish.
*/
plat_priv->enumerate_done = true;
/* Now enumeration is finished, try to suspend PCIe link */
if (plat_priv->bus_priv) {
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
struct pci_dev *pci_dev = pci_priv->pci_dev;
switch (pci_dev->device) {
case QCA6390_DEVICE_ID:
cnss_pci_set_wlaon_pwr_ctrl(pci_priv,
false,
true,
false);
cnss_pci_suspend_pwroff(pci_dev);
break;
default:
cnss_pr_err("Unknown PCI device found: 0x%x\n",
pci_dev->device);
ret = -ENODEV;
}
}
return ret;
}
#else
static int cnss_try_suspend(struct cnss_plat_data *plat_priv)
{
return 0;
}
#endif
/* Setting to use this cnss_pm_domain ops will let PM framework override the
* ops from dev->bus->pm which is pci_dev_pm_ops from pci-driver.c. This ops
* has to take care everything device driver needed which is currently done
@@ -6238,10 +6670,13 @@ static bool cnss_should_suspend_pwroff(struct pci_dev *pci_dev)
static void cnss_pci_suspend_pwroff(struct pci_dev *pci_dev)
{
struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
int rc_num = pci_dev->bus->domain_nr;
struct cnss_plat_data *plat_priv;
int ret = 0;
bool suspend_pwroff = cnss_should_suspend_pwroff(pci_dev);
plat_priv = cnss_get_plat_priv_by_rc_num(rc_num);
if (suspend_pwroff) {
ret = cnss_suspend_pci_link(pci_priv);
if (ret)
@@ -6259,11 +6694,17 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
{
int ret = 0;
struct cnss_pci_data *pci_priv;
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
struct device *dev = &pci_dev->dev;
int rc_num = pci_dev->bus->domain_nr;
struct cnss_plat_data *plat_priv = cnss_get_plat_priv_by_rc_num(rc_num);
cnss_pr_dbg("PCI is probing, vendor ID: 0x%x, device ID: 0x%x\n",
id->vendor, pci_dev->device);
cnss_pr_dbg("PCI is probing, vendor ID: 0x%x, device ID: 0x%x rc_num %d\n",
id->vendor, pci_dev->device, rc_num);
if (!plat_priv) {
cnss_pr_err("Find match plat_priv with rc number failure\n");
ret = -ENODEV;
goto out;
}
pci_priv = devm_kzalloc(dev, sizeof(*pci_priv), GFP_KERNEL);
if (!pci_priv) {
@@ -6332,11 +6773,16 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
break;
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
case QCA6490_DEVICE_ID:
case KIWI_DEVICE_ID:
case MANGO_DEVICE_ID:
case PEACH_DEVICE_ID:
cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false);
if ((cnss_is_dual_wlan_enabled() &&
plat_priv->enumerate_done) || !cnss_is_dual_wlan_enabled())
cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false,
false);
timer_setup(&pci_priv->dev_rddm_timer,
cnss_dev_rddm_timeout_hdlr, 0);
timer_setup(&pci_priv->boot_debug_timer,
@@ -6357,7 +6803,11 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
cnss_pci_config_regs(pci_priv);
if (EMULATION_HW)
goto out;
if (cnss_is_dual_wlan_enabled() && !plat_priv->enumerate_done)
goto probe_done;
cnss_pci_suspend_pwroff(pci_dev);
probe_done:
set_bit(CNSS_PCI_PROBE_DONE, &plat_priv->driver_state);
return 0;
@@ -6397,6 +6847,7 @@ static void cnss_pci_remove(struct pci_dev *pci_dev)
switch (pci_dev->device) {
case QCA6290_DEVICE_ID:
case QCA6390_DEVICE_ID:
case QCN7605_DEVICE_ID:
case QCA6490_DEVICE_ID:
case KIWI_DEVICE_ID:
case MANGO_DEVICE_ID:
@@ -6427,6 +6878,7 @@ static const struct pci_device_id cnss_pci_id_table[] = {
{ QCA6174_VENDOR_ID, QCA6174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ QCA6290_VENDOR_ID, QCA6290_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ QCA6390_VENDOR_ID, QCA6390_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ QCN7605_VENDOR_ID, QCN7605_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ QCA6490_VENDOR_ID, QCA6490_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ KIWI_VENDOR_ID, KIWI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
{ MANGO_VENDOR_ID, MANGO_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
@@ -6443,7 +6895,7 @@ static const struct dev_pm_ops cnss_pm_ops = {
cnss_pci_runtime_idle)
};
struct pci_driver cnss_pci_driver = {
static struct pci_driver cnss_pci_driver = {
.name = "cnss_pci",
.id_table = cnss_pci_id_table,
.probe = cnss_pci_probe,
@@ -6515,17 +6967,25 @@ int cnss_pci_init(struct cnss_plat_data *plat_priv)
goto out;
}
ret = pci_register_driver(&cnss_pci_driver);
ret = cnss_try_suspend(plat_priv);
if (ret) {
cnss_pr_err("Failed to register to PCI framework, err = %d\n",
ret);
cnss_pr_err("Failed to suspend, ret: %d\n", ret);
goto out;
}
if (!plat_priv->bus_priv) {
cnss_pr_err("Failed to probe PCI driver\n");
ret = -ENODEV;
goto unreg_pci;
if (!cnss_driver_registered) {
ret = pci_register_driver(&cnss_pci_driver);
if (ret) {
cnss_pr_err("Failed to register to PCI framework, err = %d\n",
ret);
goto out;
}
if (!plat_priv->bus_priv) {
cnss_pr_err("Failed to probe PCI driver\n");
ret = -ENODEV;
goto unreg_pci;
}
cnss_driver_registered = true;
}
return 0;
@@ -6538,5 +6998,8 @@ out:
void cnss_pci_deinit(struct cnss_plat_data *plat_priv)
{
pci_unregister_driver(&cnss_pci_driver);
if (cnss_driver_registered) {
pci_unregister_driver(&cnss_pci_driver);
cnss_driver_registered = false;
}
}

Dosyayı Görüntüle

@@ -23,7 +23,13 @@
#define PM_OPTIONS_DEFAULT 0
#define PCI_LINK_DOWN 0
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
#define LINK_TRAINING_RETRY_MAX_TIMES 2
#else
#define LINK_TRAINING_RETRY_MAX_TIMES 3
#endif
#define LINK_TRAINING_RETRY_DELAY_MS 500
#define MSI_USERS 4
@@ -295,4 +301,12 @@ void cnss_pci_handle_linkdown(struct cnss_pci_data *pci_priv);
int cnss_pci_update_time_sync_period(struct cnss_pci_data *pci_priv,
unsigned int time_sync_period);
int cnss_pci_set_therm_cdev_state(struct cnss_pci_data *pci_priv,
unsigned long thermal_state,
int tcdev_id);
int cnss_pci_get_user_msi_assignment(struct cnss_pci_data *pci_priv,
char *user_name,
int *num_vectors,
u32 *user_base_data,
u32 *base_vector);
#endif /* _CNSS_PCI_H */

Dosyayı Görüntüle

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/clk.h>
@@ -74,9 +74,11 @@ static struct cnss_clk_cfg cnss_clk_list[] = {
#define WLAN_EN_SLEEP "wlan_en_sleep"
#define WLAN_VREGS_PROP "wlan_vregs"
/* unit us */
#define BOOTSTRAP_DELAY 1000
#define WLAN_ENABLE_DELAY 1000
#define WLAN_ENABLE_DELAY_ROME 10000
/* unit ms */
#define WLAN_ENABLE_DELAY_ROME 10
#define TCS_CMD_DATA_ADDR_OFFSET 0x4
#define TCS_OFFSET 0xC8
@@ -1024,7 +1026,7 @@ static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
if (plat_priv->device_id == QCA6174_DEVICE_ID ||
plat_priv->device_id == 0)
udelay(WLAN_ENABLE_DELAY_ROME);
mdelay(WLAN_ENABLE_DELAY_ROME);
else
udelay(WLAN_ENABLE_DELAY);
@@ -1607,6 +1609,7 @@ void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
{
struct device *dev = &plat_priv->plat_dev->dev;
int ret;
u32 cfg_arr_size = 0, *cfg_arr = NULL;
/* common DT Entries */
plat_priv->pdc_init_table_len =
@@ -1616,13 +1619,16 @@ void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
plat_priv->pdc_init_table =
kcalloc(plat_priv->pdc_init_table_len,
sizeof(char *), GFP_KERNEL);
ret =
of_property_read_string_array(dev->of_node,
"qcom,pdc_init_table",
plat_priv->pdc_init_table,
plat_priv->pdc_init_table_len);
if (ret < 0)
cnss_pr_err("Failed to get PDC Init Table\n");
if (plat_priv->pdc_init_table) {
ret = of_property_read_string_array(dev->of_node,
"qcom,pdc_init_table",
plat_priv->pdc_init_table,
plat_priv->pdc_init_table_len);
if (ret < 0)
cnss_pr_err("Failed to get PDC Init Table\n");
} else {
cnss_pr_err("Failed to alloc PDC Init Table mem\n");
}
} else {
cnss_pr_dbg("PDC Init Table not configured\n");
}
@@ -1634,13 +1640,16 @@ void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
plat_priv->vreg_pdc_map =
kcalloc(plat_priv->vreg_pdc_map_len,
sizeof(char *), GFP_KERNEL);
ret =
of_property_read_string_array(dev->of_node,
"qcom,vreg_pdc_map",
plat_priv->vreg_pdc_map,
plat_priv->vreg_pdc_map_len);
if (ret < 0)
cnss_pr_err("Failed to get VReg PDC Mapping\n");
if (plat_priv->vreg_pdc_map) {
ret = of_property_read_string_array(dev->of_node,
"qcom,vreg_pdc_map",
plat_priv->vreg_pdc_map,
plat_priv->vreg_pdc_map_len);
if (ret < 0)
cnss_pr_err("Failed to get VReg PDC Mapping\n");
} else {
cnss_pr_err("Failed to alloc VReg PDC mem\n");
}
} else {
cnss_pr_dbg("VReg PDC Mapping not configured\n");
}
@@ -1651,12 +1660,16 @@ void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
if (plat_priv->pmu_vreg_map_len > 0) {
plat_priv->pmu_vreg_map = kcalloc(plat_priv->pmu_vreg_map_len,
sizeof(char *), GFP_KERNEL);
ret =
of_property_read_string_array(dev->of_node, "qcom,pmu_vreg_map",
plat_priv->pmu_vreg_map,
plat_priv->pmu_vreg_map_len);
if (ret < 0)
cnss_pr_err("Fail to get PMU VReg Mapping\n");
if (plat_priv->pmu_vreg_map) {
ret = of_property_read_string_array(dev->of_node,
"qcom,pmu_vreg_map",
plat_priv->pmu_vreg_map,
plat_priv->pmu_vreg_map_len);
if (ret < 0)
cnss_pr_err("Fail to get PMU VReg Mapping\n");
} else {
cnss_pr_err("Failed to alloc PMU VReg mem\n");
}
} else {
cnss_pr_dbg("PMU VReg Mapping not configured\n");
}
@@ -1676,6 +1689,25 @@ void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
if (ret)
cnss_pr_dbg("VReg for QCA6490 Int Power Amp not configured\n");
}
ret = of_property_count_u32_elems(plat_priv->plat_dev->dev.of_node,
"qcom,on-chip-pmic-support");
if (ret > 0) {
cfg_arr_size = ret;
cfg_arr = kcalloc(cfg_arr_size, sizeof(*cfg_arr), GFP_KERNEL);
if (cfg_arr) {
ret = of_property_read_u32_array(plat_priv->plat_dev->dev.of_node,
"qcom,on-chip-pmic-support",
cfg_arr, cfg_arr_size);
if (!ret) {
plat_priv->on_chip_pmic_devices_count = cfg_arr_size;
plat_priv->on_chip_pmic_board_ids = cfg_arr;
}
} else {
cnss_pr_err("Failed to alloc cfg table mem\n");
}
} else {
cnss_pr_dbg("On chip PMIC device ids not configured\n");
}
}
int cnss_update_cpr_info(struct cnss_plat_data *plat_priv)

Dosyayı Görüntüle

@@ -40,6 +40,7 @@
#endif
#define HW_V1_NUMBER "v1"
#define HW_V2_NUMBER "v2"
#define CE_MSI_NAME "CE"
#define QMI_WLFW_TIMEOUT_MS (plat_priv->ctrl_params.qmi_timeout)
#define QMI_WLFW_TIMEOUT_JF msecs_to_jiffies(QMI_WLFW_TIMEOUT_MS)
@@ -597,6 +598,22 @@ int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv)
if (resp->ol_cpr_cfg_valid)
cnss_aop_ol_cpr_cfg_setup(plat_priv, &resp->ol_cpr_cfg);
/* Disable WLAN PDC in AOP firmware for boards which support on chip PMIC
* so AOP will ignore SW_CTRL changes and do not update regulator votes.
**/
for (i = 0; i < plat_priv->on_chip_pmic_devices_count; i++) {
if (plat_priv->board_info.board_id ==
plat_priv->on_chip_pmic_board_ids[i]) {
cnss_pr_dbg("Disabling WLAN PDC for board_id: %02x\n",
plat_priv->board_info.board_id);
ret = cnss_aop_send_msg(plat_priv,
"{class: wlan_pdc, ss: rf, res: pdc, enable: 0}");
if (ret < 0)
cnss_pr_dbg("Failed to Send AOP Msg");
break;
}
}
cnss_pr_dbg("Target capability: chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x, otp_version: 0x%x\n",
plat_priv->chip_info.chip_id,
plat_priv->chip_info.chip_family,
@@ -622,6 +639,21 @@ out:
return ret;
}
static char *cnss_bdf_type_to_str(enum cnss_bdf_type bdf_type)
{
switch (bdf_type) {
case CNSS_BDF_BIN:
case CNSS_BDF_ELF:
return "BDF";
case CNSS_BDF_REGDB:
return "REGDB";
case CNSS_BDF_HDS:
return "HDS";
default:
return "UNKNOWN";
}
}
static int cnss_get_bdf_file_name(struct cnss_plat_data *plat_priv,
u32 bdf_type, char *filename,
u32 filename_len)
@@ -841,8 +873,8 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
unsigned int remaining;
int ret = 0;
cnss_pr_dbg("Sending BDF download message, state: 0x%lx, type: %d\n",
plat_priv->driver_state, bdf_type);
cnss_pr_dbg("Sending QMI_WLFW_BDF_DOWNLOAD_REQ_V01 message for bdf_type: %d (%s), state: 0x%lx\n",
bdf_type, cnss_bdf_type_to_str(bdf_type), plat_priv->driver_state);
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req)
@@ -867,14 +899,16 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
&plat_priv->plat_dev->dev);
if (ret) {
cnss_pr_err("Failed to load BDF: %s, ret: %d\n", filename, ret);
cnss_pr_err("Failed to load %s: %s, ret: %d\n",
cnss_bdf_type_to_str(bdf_type), filename, ret);
goto err_req_fw;
}
temp = fw_entry->data;
remaining = fw_entry->size;
cnss_pr_dbg("Downloading BDF: %s, size: %u\n", filename, remaining);
cnss_pr_dbg("Downloading %s: %s, size: %u\n",
cnss_bdf_type_to_str(bdf_type), filename, remaining);
while (remaining) {
req->valid = 1;
@@ -900,8 +934,8 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
wlfw_bdf_download_resp_msg_v01_ei, resp);
if (ret < 0) {
cnss_pr_err("Failed to initialize txn for BDF download request, err: %d\n",
ret);
cnss_pr_err("Failed to initialize txn for QMI_WLFW_BDF_DOWNLOAD_REQ_V01 request for %s, error: %d\n",
cnss_bdf_type_to_str(bdf_type), ret);
goto err_send;
}
@@ -912,21 +946,22 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
wlfw_bdf_download_req_msg_v01_ei, req);
if (ret < 0) {
qmi_txn_cancel(&txn);
cnss_pr_err("Failed to send respond BDF download request, err: %d\n",
ret);
cnss_pr_err("Failed to send QMI_WLFW_BDF_DOWNLOAD_REQ_V01 request for %s, error: %d\n",
cnss_bdf_type_to_str(bdf_type), ret);
goto err_send;
}
ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
if (ret < 0) {
cnss_pr_err("Failed to wait for response of BDF download request, err: %d\n",
ret);
cnss_pr_err("Timeout while waiting for FW response for QMI_WLFW_BDF_DOWNLOAD_REQ_V01 request for %s, err: %d\n",
cnss_bdf_type_to_str(bdf_type), ret);
goto err_send;
}
if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
cnss_pr_err("BDF download request failed, result: %d, err: %d\n",
resp->resp.result, resp->resp.error);
cnss_pr_err("FW response for QMI_WLFW_BDF_DOWNLOAD_REQ_V01 request for %s failed, result: %d, err: %d\n",
cnss_bdf_type_to_str(bdf_type), resp->resp.result,
resp->resp.error);
ret = -resp->resp.result;
goto err_send;
}
@@ -1533,7 +1568,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 qmi_txn txn;
u32 i;
u32 i, ce_id, num_vectors, user_base_data, base_vector;
int ret = 0;
if (!plat_priv)
@@ -1583,16 +1618,34 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
if (plat_priv->device_id != KIWI_DEVICE_ID &&
plat_priv->device_id != MANGO_DEVICE_ID &&
plat_priv->device_id != PEACH_DEVICE_ID) {
req->shadow_reg_v2_valid = 1;
if (config->num_shadow_reg_v2_cfg >
QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01)
req->shadow_reg_v2_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01;
else
req->shadow_reg_v2_len = config->num_shadow_reg_v2_cfg;
if (plat_priv->device_id == QCN7605_DEVICE_ID &&
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);
} else {
req->shadow_reg_v2_valid = 1;
memcpy(req->shadow_reg_v2, config->shadow_reg_v2_cfg,
sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01)
* req->shadow_reg_v2_len);
if (config->num_shadow_reg_v2_cfg >
QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01)
req->shadow_reg_v2_len =
QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01;
else
req->shadow_reg_v2_len =
config->num_shadow_reg_v2_cfg;
memcpy(req->shadow_reg_v2, config->shadow_reg_v2_cfg,
sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01) *
req->shadow_reg_v2_len);
}
} else {
req->shadow_reg_v3_valid = 1;
if (config->num_shadow_reg_v3_cfg >
@@ -1607,8 +1660,33 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
plat_priv->num_shadow_regs_v3);
memcpy(req->shadow_reg_v3, config->shadow_reg_v3_cfg,
sizeof(struct wlfw_shadow_reg_v3_cfg_s_v01)
* req->shadow_reg_v3_len);
sizeof(struct wlfw_shadow_reg_v3_cfg_s_v01) *
req->shadow_reg_v3_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_bus_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;
}
}
}
ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
@@ -3211,9 +3289,25 @@ static struct qmi_ops qmi_wlfw_ops = {
.del_server = wlfw_del_server,
};
static int cnss_qmi_add_lookup(struct cnss_plat_data *plat_priv)
{
unsigned int id = WLFW_SERVICE_INS_ID_V01;
/* In order to support dual wlan card attach case,
* need separate qmi service instance id for each dev
*/
if (cnss_is_dual_wlan_enabled() && plat_priv->qrtr_node_id != 0 &&
plat_priv->wlfw_service_instance_id != 0)
id = plat_priv->wlfw_service_instance_id;
return qmi_add_lookup(&plat_priv->qmi_wlfw, WLFW_SERVICE_ID_V01,
WLFW_SERVICE_VERS_V01, id);
}
int cnss_qmi_init(struct cnss_plat_data *plat_priv)
{
int ret = 0;
cnss_get_qrtr_info(plat_priv);
ret = qmi_handle_init(&plat_priv->qmi_wlfw,
QMI_WLFW_MAX_RECV_BUF_SIZE,
@@ -3224,8 +3318,7 @@ int cnss_qmi_init(struct cnss_plat_data *plat_priv)
goto out;
}
ret = qmi_add_lookup(&plat_priv->qmi_wlfw, WLFW_SERVICE_ID_V01,
WLFW_SERVICE_VERS_V01, WLFW_SERVICE_INS_ID_V01);
ret = cnss_qmi_add_lookup(plat_priv);
if (ret < 0)
cnss_pr_err("Failed to add WLFW QMI lookup, err: %d\n", ret);

Dosyayı Görüntüle

@@ -124,6 +124,7 @@
#define QCA6390_PCIE_SOC_PCIE_WRAP_INTR_STATUS_SOC_PCIE_REG 0x1E04058
#define QCA6390_PCIE_SOC_COMMIT_REPLAY_SOC_PCIE_REG 0x01E05090
#define PEACH_PCIE_SOC_COMMIT_REPLAY_SOC_PCIE_REG 0x01E01100
#define QCA6390_PCIE_SOC_PCIE_REG_PCIE_SCRATCH_2_SOC_PCIE_REG 0x01E0405C
#define QCA6390_PCIE_PCIE_PARF_LTSSM 0x01E081B0
#define QCA6390_PCIE_PCIE_PARF_PM_STTS 0x01E08024
#define QCA6390_PCIE_PCIE_PARF_PM_STTS_1 0x01E08028
@@ -360,4 +361,6 @@
#define GCC_GCC_SPARE_REG_1 0x1E40310
#define GCC_PRE_ARES_DEBUG_TIMER_VAL 0x1E40270
#define QCN7605_WINDOW_ENABLE_BIT 0x80000000
#endif

Dosyayı Görüntüle

@@ -422,6 +422,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
continue;
case ICNSS_SLATE_UP:
seq_puts(s, "ICNSS SLATE UP");
continue;
case ICNSS_LOW_POWER:
seq_puts(s, "ICNSS LOW POWER");
}
seq_printf(s, "UNKNOWN-%d", i);
@@ -472,7 +475,7 @@ static int icnss_stats_show(struct seq_file *s, void *data)
ICNSS_STATS_DUMP(s, priv, pm_stay_awake);
ICNSS_STATS_DUMP(s, priv, pm_relax);
if (priv->device_id != WCN6750_DEVICE_ID) {
if (priv->device_id == ADRASTEA_DEVICE_ID) {
seq_puts(s, "\n<------------------ MSA stats ------------------->\n");
ICNSS_STATS_DUMP(s, priv, msa_info_req);
ICNSS_STATS_DUMP(s, priv, msa_info_resp);

Dosyayı Görüntüle

@@ -45,7 +45,7 @@
#include <linux/soc/qcom/pdr.h>
#include <linux/remoteproc.h>
#include <trace/hooks/remoteproc.h>
#include <../drivers/soc/qcom/slatecom_interface.h>
#include <linux/soc/qcom/slatecom_interface.h>
#include "main.h"
#include "qmi.h"
#include "debug.h"
@@ -83,8 +83,13 @@ module_param(qmi_timeout, ulong, 0600);
#define WLFW_TIMEOUT msecs_to_jiffies(3000)
#endif
#define ICNSS_RECOVERY_TIMEOUT 60000
#define ICNSS_WPSS_SSR_TIMEOUT 5000
#define ICNSS_CAL_TIMEOUT 40000
static struct icnss_priv *penv;
static struct work_struct wpss_loader;
static struct work_struct wpss_ssr_work;
uint64_t dynamic_feature_mask = ICNSS_DEFAULT_FEATURE_MASK;
#define ICNSS_EVENT_PENDING 2989
@@ -132,14 +137,29 @@ static struct icnss_priv *icnss_get_plat_priv(void)
return penv;
}
static inline void icnss_wpss_unload(struct icnss_priv *priv)
{
if (priv && priv->rproc) {
rproc_shutdown(priv->rproc);
rproc_put(priv->rproc);
priv->rproc = NULL;
}
}
static ssize_t icnss_sysfs_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct icnss_priv *priv = icnss_get_plat_priv();
atomic_set(&priv->is_shutdown, true);
if (!priv)
return count;
icnss_pr_dbg("Received shutdown indication");
atomic_set(&priv->is_shutdown, true);
if (priv->wpss_supported && priv->device_id == ADRASTEA_DEVICE_ID)
icnss_wpss_unload(priv);
return count;
}
@@ -449,7 +469,7 @@ static int icnss_send_smp2p(struct icnss_priv *priv,
unsigned int value = 0;
int ret;
if (IS_ERR(priv->smp2p_info[smp2p_entry].smem_state))
if (!priv || IS_ERR(priv->smp2p_info[smp2p_entry].smem_state))
return -EINVAL;
/* No Need to check FW_DOWN for ICNSS_RESET_MSG */
@@ -502,6 +522,15 @@ static int icnss_send_smp2p(struct icnss_priv *priv,
return ret;
}
bool icnss_is_low_power(void)
{
if (!penv)
return false;
else
return test_bit(ICNSS_LOW_POWER, &penv->state);
}
EXPORT_SYMBOL(icnss_is_low_power);
static irqreturn_t fw_error_fatal_handler(int irq, void *ctx)
{
struct icnss_priv *priv = ctx;
@@ -522,6 +551,10 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx)
icnss_pr_err("Received early crash indication from FW\n");
if (priv) {
if (priv->wpss_self_recovery_enabled)
mod_timer(&priv->wpss_ssr_timer,
jiffies + msecs_to_jiffies(ICNSS_WPSS_SSR_TIMEOUT));
set_bit(ICNSS_FW_DOWN, &priv->state);
icnss_ignore_fw_timeout(true);
@@ -863,7 +896,8 @@ static int icnss_driver_event_server_arrive(struct icnss_priv *priv,
}
}
if (priv->device_id == WCN6750_DEVICE_ID) {
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
if (!icnss_get_temperature(priv, &temp)) {
icnss_pr_dbg("Temperature: %d\n", temp);
if (temp < WLAN_EN_TEMP_THRESHOLD)
@@ -895,6 +929,9 @@ static int icnss_driver_event_server_arrive(struct icnss_priv *priv,
}
}
if (priv->device_id == WCN6450_DEVICE_ID)
icnss_hw_power_off(priv);
ret = wlfw_cap_send_sync_msg(priv);
if (ret < 0) {
ignore_assert = true;
@@ -905,7 +942,8 @@ static int icnss_driver_event_server_arrive(struct icnss_priv *priv,
if (ret)
goto fail;
if (priv->device_id == WCN6750_DEVICE_ID) {
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
ret = wlfw_device_info_send_msg(priv);
if (ret < 0) {
ignore_assert = true;
@@ -945,7 +983,15 @@ static int icnss_driver_event_server_arrive(struct icnss_priv *priv,
goto device_info_failure;
}
if (priv->device_id == WCN6750_DEVICE_ID) {
if (priv->device_id == WCN6450_DEVICE_ID) {
ret = icnss_wlfw_qdss_dnld_send_sync(priv);
if (ret < 0)
icnss_pr_info("Failed to download qdss config file for WCN6450, ret = %d\n",
ret);
}
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
if (!priv->fw_soc_wake_ack_irq)
register_soc_wake_notif(&priv->pdev->dev);
@@ -1071,6 +1117,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv)
clear_bit(ICNSS_PDR, &priv->state);
clear_bit(ICNSS_REJUVENATE, &priv->state);
clear_bit(ICNSS_PD_RESTART, &priv->state);
clear_bit(ICNSS_LOW_POWER, &priv->state);
priv->early_crash_ind = false;
priv->is_ssr = false;
@@ -1124,11 +1171,13 @@ static int icnss_driver_event_fw_ready_ind(struct icnss_priv *priv, void *data)
if (!priv)
return -ENODEV;
del_timer(&priv->recovery_timer);
set_bit(ICNSS_FW_READY, &priv->state);
clear_bit(ICNSS_MODE_ON, &priv->state);
atomic_set(&priv->soc_wake_ref_count, 0);
if (priv->device_id == WCN6750_DEVICE_ID)
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID)
icnss_free_qdss_mem(priv);
icnss_pr_info("WLAN FW is ready: 0x%lx\n", priv->state);
@@ -1169,14 +1218,21 @@ static int icnss_driver_event_fw_init_done(struct icnss_priv *priv, void *data)
icnss_pr_info("WLAN FW Initialization done: 0x%lx\n", priv->state);
if (icnss_wlfw_qdss_dnld_send_sync(priv))
icnss_pr_info("Failed to download qdss configuration file");
if (priv->device_id == WCN6750_DEVICE_ID) {
ret = icnss_wlfw_qdss_dnld_send_sync(priv);
if (ret < 0)
icnss_pr_info("Failed to download qdss config file for WCN6750, ret = %d\n",
ret);
}
if (test_bit(ICNSS_COLD_BOOT_CAL, &priv->state))
if (test_bit(ICNSS_COLD_BOOT_CAL, &priv->state)) {
mod_timer(&priv->recovery_timer,
jiffies + msecs_to_jiffies(ICNSS_CAL_TIMEOUT));
ret = wlfw_wlan_mode_send_sync_msg(priv,
(enum wlfw_driver_mode_enum_v01)ICNSS_CALIBRATION);
else
} else {
icnss_driver_event_fw_ready_ind(priv, NULL);
}
return ret;
}
@@ -1560,7 +1616,8 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv,
if (priv->force_err_fatal)
ICNSS_ASSERT(0);
if (priv->device_id == WCN6750_DEVICE_ID) {
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
icnss_send_smp2p(priv, ICNSS_RESET_MSG,
ICNSS_SMP2P_OUT_SOC_WAKE);
icnss_send_smp2p(priv, ICNSS_RESET_MSG,
@@ -1759,6 +1816,19 @@ static int icnss_subsys_restart_level(struct icnss_priv *priv, void *data)
return ret;
}
static void icnss_wpss_self_recovery(struct work_struct *wpss_load_work)
{
int ret;
struct icnss_priv *priv = icnss_get_plat_priv();
rproc_shutdown(priv->rproc);
ret = rproc_boot(priv->rproc);
if (ret) {
icnss_pr_err("Failed to self recover wpss rproc, ret: %d", ret);
rproc_put(priv->rproc);
}
}
static void icnss_driver_event_work(struct work_struct *work)
{
struct icnss_priv *priv =
@@ -2063,20 +2133,25 @@ static int icnss_wpss_notifier_nb(struct notifier_block *nb,
if (code != QCOM_SSR_BEFORE_SHUTDOWN)
goto out;
if (priv->wpss_self_recovery_enabled)
del_timer(&priv->wpss_ssr_timer);
priv->is_ssr = true;
icnss_pr_info("WPSS went down, state: 0x%lx, crashed: %d\n",
priv->state, notif->crashed);
if (priv->device_id == ADRASTEA_DEVICE_ID)
icnss_update_state_send_modem_shutdown(priv, data);
set_bit(ICNSS_FW_DOWN, &priv->state);
icnss_ignore_fw_timeout(true);
if (notif->crashed)
priv->stats.recovery.root_pd_crash++;
else
priv->stats.recovery.root_pd_shutdown++;
icnss_ignore_fw_timeout(true);
event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
if (event_data == NULL)
@@ -2094,6 +2169,10 @@ static int icnss_wpss_notifier_nb(struct notifier_block *nb,
}
icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
if (notif->crashed)
mod_timer(&priv->recovery_timer,
jiffies + msecs_to_jiffies(ICNSS_RECOVERY_TIMEOUT));
out:
icnss_pr_vdbg("Exit %s,state: 0x%lx\n", __func__, priv->state);
return NOTIFY_OK;
@@ -2112,15 +2191,29 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
icnss_pr_vdbg("Modem-Notify: event %s(%lu)\n",
icnss_qcom_ssr_notify_state_to_str(code), code);
if (code == QCOM_SSR_AFTER_SHUTDOWN) {
icnss_pr_info("Collecting msa0 segment dump\n");
icnss_msa0_ramdump(priv);
switch (code) {
case QCOM_SSR_BEFORE_SHUTDOWN:
if (!notif->crashed &&
priv->low_power_support) { /* Hibernate */
if (test_bit(ICNSS_MODE_ON, &priv->state))
icnss_driver_event_post(
priv, ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
set_bit(ICNSS_LOW_POWER, &priv->state);
}
break;
case QCOM_SSR_AFTER_SHUTDOWN:
/* Collect ramdump only when there was a crash. */
if (notif->crashed) {
icnss_pr_info("Collecting msa0 segment dump\n");
icnss_msa0_ramdump(priv);
}
goto out;
default:
goto out;
}
if (code != QCOM_SSR_BEFORE_SHUTDOWN)
goto out;
priv->is_ssr = true;
if (notif->crashed) {
@@ -2171,6 +2264,10 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
}
icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
if (notif->crashed)
mod_timer(&priv->recovery_timer,
jiffies + msecs_to_jiffies(ICNSS_RECOVERY_TIMEOUT));
out:
icnss_pr_vdbg("Exit %s,state: 0x%lx\n", __func__, priv->state);
return NOTIFY_OK;
@@ -2351,6 +2448,9 @@ static void icnss_pdr_notifier_cb(int state, char *service_path, void *priv_cb)
struct icnss_uevent_fw_down_data fw_down_data = {0};
enum icnss_pdr_cause_index cause = ICNSS_ROOT_PD_CRASH;
if (!priv)
return;
icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n",
state, priv->state);
@@ -2393,6 +2493,12 @@ static void icnss_pdr_notifier_cb(int state, char *service_path, void *priv_cb)
}
}
clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
if (event_data->crashed)
mod_timer(&priv->recovery_timer,
jiffies +
msecs_to_jiffies(ICNSS_RECOVERY_TIMEOUT));
icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
break;
@@ -2527,7 +2633,8 @@ static int icnss_register_ramdump_devices(struct icnss_priv *priv)
return -ENOMEM;
}
if (priv->device_id == WCN6750_DEVICE_ID) {
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
priv->m3_dump_phyareg = icnss_create_ramdump_device(priv,
ICNSS_M3_SEGMENT(
ICNSS_M3_SEGMENT_PHYAREG));
@@ -2883,7 +2990,7 @@ out:
}
EXPORT_SYMBOL(icnss_unregister_driver);
static struct icnss_msi_config msi_config = {
static struct icnss_msi_config msi_config_wcn6750 = {
.total_vectors = 28,
.total_users = 2,
.users = (struct icnss_msi_user[]) {
@@ -2892,9 +2999,20 @@ static struct icnss_msi_config msi_config = {
},
};
static struct icnss_msi_config msi_config_wcn6450 = {
.total_vectors = 10,
.total_users = 1,
.users = (struct icnss_msi_user[]) {
{ .name = "CE", .num_vectors = 10, .base_vector = 0 },
},
};
static int icnss_get_msi_assignment(struct icnss_priv *priv)
{
priv->msi_config = &msi_config;
if (priv->device_id == WCN6750_DEVICE_ID)
priv->msi_config = &msi_config_wcn6750;
else
priv->msi_config = &msi_config_wcn6450;
return 0;
}
@@ -3336,7 +3454,7 @@ int icnss_wlan_enable(struct device *dev, struct icnss_wlan_enable_cfg *config,
const char *host_version)
{
struct icnss_priv *priv = dev_get_drvdata(dev);
int temp = 0;
int temp = 0, ret = 0;
if (test_bit(ICNSS_FW_DOWN, &priv->state) ||
!test_bit(ICNSS_FW_READY, &priv->state)) {
@@ -3363,7 +3481,15 @@ int icnss_wlan_enable(struct device *dev, struct icnss_wlan_enable_cfg *config,
}
}
return icnss_send_wlan_enable_to_fw(priv, config, mode, host_version);
if (priv->device_id == WCN6450_DEVICE_ID)
icnss_hw_power_off(priv);
ret = icnss_send_wlan_enable_to_fw(priv, config, mode, host_version);
if (priv->device_id == WCN6450_DEVICE_ID)
icnss_hw_power_on(priv);
return ret;
}
EXPORT_SYMBOL(icnss_wlan_enable);
@@ -3799,15 +3925,6 @@ static void icnss_wpss_load(struct work_struct *wpss_load_work)
}
}
static inline void icnss_wpss_unload(struct icnss_priv *priv)
{
if (priv && priv->rproc) {
rproc_shutdown(priv->rproc);
rproc_put(priv->rproc);
priv->rproc = NULL;
}
}
static ssize_t wpss_boot_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -3840,7 +3957,7 @@ static ssize_t wlan_en_delay_store(struct device *dev,
struct icnss_priv *priv = dev_get_drvdata(dev);
uint32_t wlan_en_delay = 0;
if (priv->device_id != WCN6750_DEVICE_ID)
if (priv->device_id == ADRASTEA_DEVICE_ID)
return count;
if (sscanf(buf, "%du", &wlan_en_delay) != 1) {
@@ -3990,6 +4107,12 @@ static int icnss_resource_parse(struct icnss_priv *priv)
}
}
if (of_property_read_bool(pdev->dev.of_node,
"qcom,is_low_power")) {
priv->low_power_support = true;
icnss_pr_dbg("Deep Sleep/Hibernate mode supported\n");
}
if (of_property_read_u32(pdev->dev.of_node, "qcom,rf_subtype",
&priv->rf_subtype) == 0) {
priv->is_rf_subtype_valid = true;
@@ -4001,7 +4124,8 @@ static int icnss_resource_parse(struct icnss_priv *priv)
priv->is_slate_rfa = true;
icnss_pr_err("SLATE rfa is enabled\n");
}
} else if (priv->device_id == WCN6750_DEVICE_ID) {
} else if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"msi_addr");
if (!res) {
@@ -4038,7 +4162,7 @@ static int icnss_resource_parse(struct icnss_priv *priv)
priv->msi_base_data, int_prop);
icnss_get_msi_assignment(priv);
for (i = 0; i < msi_config.total_vectors; i++) {
for (i = 0; i < priv->msi_config->total_vectors; i++) {
res = platform_get_resource(priv->pdev,
IORESOURCE_IRQ, i);
if (!res) {
@@ -4189,7 +4313,8 @@ static int icnss_smmu_dt_parse(struct icnss_priv *priv)
if (!ret && !strcmp("fastmap", iommu_dma_type)) {
icnss_pr_dbg("SMMU S1 stage enabled\n");
priv->smmu_s1_enable = true;
if (priv->device_id == WCN6750_DEVICE_ID)
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID)
iommu_set_fault_handler(priv->iommu_domain,
icnss_smmu_fault_handler,
priv);
@@ -4255,16 +4380,19 @@ void icnss_add_fw_prefix_name(struct icnss_priv *priv, char *prefix_name,
if (priv->device_id == ADRASTEA_DEVICE_ID)
scnprintf(prefix_name, ICNSS_MAX_FILE_NAME,
ADRASTEA_PATH_PREFIX "%s", name);
else
else if (priv->device_id == WCN6750_DEVICE_ID)
scnprintf(prefix_name, ICNSS_MAX_FILE_NAME,
QCA6750_PATH_PREFIX "%s", name);
else if (priv->device_id == WCN6450_DEVICE_ID)
scnprintf(prefix_name, ICNSS_MAX_FILE_NAME,
WCN6450_PATH_PREFIX "%s", name);
icnss_pr_dbg("File added with prefix: %s\n", prefix_name);
}
static const struct platform_device_id icnss_platform_id_table[] = {
{ .name = "wcn6750", .driver_data = WCN6750_DEVICE_ID, },
{ .name = "adrastea", .driver_data = ADRASTEA_DEVICE_ID, },
{ .name = "wcn6450", .driver_data = WCN6450_DEVICE_ID, },
{ },
};
@@ -4275,6 +4403,9 @@ static const struct of_device_id icnss_dt_match[] = {
{
.compatible = "qcom,icnss",
.data = (void *)&icnss_platform_id_table[1]},
{
.compatible = "qcom,wcn6450",
.data = (void *)&icnss_platform_id_table[2]},
{ },
};
@@ -4305,6 +4436,10 @@ static void icnss_read_device_configs(struct icnss_priv *priv)
"wlan-ipa-disabled")) {
set_bit(ICNSS_IPA_DISABLED, &priv->device_config);
}
if (of_property_read_bool(priv->pdev->dev.of_node,
"qcom,wpss-self-recovery"))
priv->wpss_self_recovery_enabled = true;
}
static inline void icnss_runtime_pm_init(struct icnss_priv *priv)
@@ -4444,7 +4579,8 @@ static int icnss_probe(struct platform_device *pdev)
if (priv->is_slate_rfa)
init_completion(&priv->slate_boot_complete);
if (priv->device_id == WCN6750_DEVICE_ID) {
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
priv->soc_wake_wq = alloc_workqueue("icnss_soc_wake_event",
WQ_UNBOUND|WQ_HIGHPRI, 1);
if (!priv->soc_wake_wq) {
@@ -4478,6 +4614,15 @@ static int icnss_probe(struct platform_device *pdev)
INIT_WORK(&wpss_loader, icnss_wpss_load);
}
timer_setup(&priv->recovery_timer,
icnss_recovery_timeout_hdlr, 0);
if (priv->wpss_self_recovery_enabled) {
INIT_WORK(&wpss_ssr_work, icnss_wpss_self_recovery);
timer_setup(&priv->wpss_ssr_timer,
icnss_wpss_ssr_timeout_hdlr, 0);
}
INIT_LIST_HEAD(&priv->icnss_tcdev_list);
icnss_pr_info("Platform driver probed successfully\n");
@@ -4528,6 +4673,11 @@ static int icnss_remove(struct platform_device *pdev)
icnss_pr_info("Removing driver: state: 0x%lx\n", priv->state);
del_timer(&priv->recovery_timer);
if (priv->wpss_self_recovery_enabled)
del_timer(&priv->wpss_ssr_timer);
device_init_wakeup(&priv->pdev->dev, false);
icnss_debugfs_destroy(priv);
@@ -4552,7 +4702,8 @@ static int icnss_remove(struct platform_device *pdev)
icnss_pdr_unregister_notifier(priv);
}
if (priv->device_id == WCN6750_DEVICE_ID) {
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
icnss_genl_exit();
icnss_runtime_pm_deinit(priv);
if (!IS_ERR_OR_NULL(priv->mbox_chan))
@@ -4586,6 +4737,23 @@ static int icnss_remove(struct platform_device *pdev)
return 0;
}
void icnss_recovery_timeout_hdlr(struct timer_list *t)
{
struct icnss_priv *priv = from_timer(priv, t, recovery_timer);
icnss_pr_err("Timeout waiting for FW Ready 0x%lx\n", priv->state);
ICNSS_ASSERT(0);
}
void icnss_wpss_ssr_timeout_hdlr(struct timer_list *t)
{
struct icnss_priv *priv = from_timer(priv, t, wpss_ssr_timer);
icnss_pr_err("Timeout waiting for WPSS SSR notification 0x%lx\n",
priv->state);
schedule_work(&wpss_ssr_work);
}
#ifdef CONFIG_PM_SLEEP
static int icnss_pm_suspend(struct device *dev)
{
@@ -4608,7 +4776,8 @@ static int icnss_pm_suspend(struct device *dev)
ret = priv->ops->pm_suspend(dev);
if (ret == 0) {
if (priv->device_id == WCN6750_DEVICE_ID) {
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
if (test_bit(ICNSS_PD_RESTART, &priv->state) ||
!test_bit(ICNSS_MODE_ON, &priv->state))
return 0;
@@ -4717,7 +4886,7 @@ static int icnss_pm_runtime_suspend(struct device *dev)
struct icnss_priv *priv = dev_get_drvdata(dev);
int ret = 0;
if (priv->device_id != WCN6750_DEVICE_ID) {
if (priv->device_id == ADRASTEA_DEVICE_ID) {
icnss_pr_err("Ignore runtime suspend:\n");
goto out;
}
@@ -4751,8 +4920,8 @@ static int icnss_pm_runtime_resume(struct device *dev)
struct icnss_priv *priv = dev_get_drvdata(dev);
int ret = 0;
if (priv->device_id != WCN6750_DEVICE_ID) {
icnss_pr_err("Ignore runtime resume:\n");
if (priv->device_id == ADRASTEA_DEVICE_ID) {
icnss_pr_err("Ignore runtime resume\n");
goto out;
}
@@ -4778,8 +4947,8 @@ static int icnss_pm_runtime_idle(struct device *dev)
{
struct icnss_priv *priv = dev_get_drvdata(dev);
if (priv->device_id != WCN6750_DEVICE_ID) {
icnss_pr_err("Ignore runtime idle:\n");
if (priv->device_id == ADRASTEA_DEVICE_ID) {
icnss_pr_err("Ignore runtime idle\n");
goto out;
}

Dosyayı Görüntüle

@@ -19,14 +19,17 @@
#endif
#include "wlan_firmware_service_v01.h"
#include <linux/mailbox_client.h>
#include <linux/timer.h>
#define WCN6750_DEVICE_ID 0x6750
#define WCN6450_DEVICE_ID 0x6450
#define ADRASTEA_DEVICE_ID 0xabcd
#define THERMAL_NAME_LENGTH 20
#define ICNSS_SMEM_VALUE_MASK 0xFFFFFFFF
#define ICNSS_SMEM_SEQ_NO_POS 16
#define QCA6750_PATH_PREFIX "qca6750/"
#define ADRASTEA_PATH_PREFIX "adrastea/"
#define WCN6450_PATH_PREFIX "wcn6450/"
#define ICNSS_MAX_FILE_NAME 35
#define ICNSS_PCI_EP_WAKE_OFFSET 4
#define ICNSS_DISABLE_M3_SSR 0
@@ -127,6 +130,7 @@ enum icnss_driver_state {
ICNSS_QMI_DMS_CONNECTED,
ICNSS_SLATE_SSR_REGISTERED,
ICNSS_SLATE_UP,
ICNSS_LOW_POWER,
};
struct ce_irq_list {
@@ -497,10 +501,14 @@ struct icnss_priv {
struct workqueue_struct *soc_update_wq;
unsigned long device_config;
bool wpss_supported;
u8 low_power_support;
bool is_rf_subtype_valid;
u32 rf_subtype;
u8 is_slate_rfa;
struct completion slate_boot_complete;
struct timer_list recovery_timer;
struct timer_list wpss_ssr_timer;
bool wpss_self_recovery_enabled;
};
struct icnss_reg_info {
@@ -528,5 +536,7 @@ int icnss_update_cpr_info(struct icnss_priv *priv);
void icnss_add_fw_prefix_name(struct icnss_priv *priv, char *prefix_name,
char *name);
int icnss_aop_mbox_init(struct icnss_priv *priv);
void icnss_recovery_timeout_hdlr(struct timer_list *t);
void icnss_wpss_ssr_timeout_hdlr(struct timer_list *t);
#endif

Dosyayı Görüntüle

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/delay.h>
@@ -38,6 +39,13 @@ static struct icnss_battery_level icnss_battery_level[] = {
{0, 2850000},
};
static struct icnss_vreg_cfg icnss_wcn6450_vreg_list[] = {
{"vdd-cx-mx", 824000, 952000, 0, 0, 0, false, true},
{"vdd-1.8-xo", 1872000, 1872000, 0, 0, 0, false, true},
{"vdd-1.3-rfa", 1256000, 1352000, 0, 0, 0, false, true},
{"vdd-aon", 1256000, 1352000, 0, 0, 0, false, true},
};
static struct icnss_clk_cfg icnss_clk_list[] = {
{"rf_clk", 0, 0},
};
@@ -48,6 +56,7 @@ static struct icnss_clk_cfg icnss_adrestea_clk_list[] = {
#define ICNSS_VREG_LIST_SIZE ARRAY_SIZE(icnss_wcn6750_vreg_list)
#define ICNSS_VREG_ADRESTEA_LIST_SIZE ARRAY_SIZE(icnss_adrestea_vreg_list)
#define ICNSS_VREG_EVROS_LIST_SIZE ARRAY_SIZE(icnss_wcn6450_vreg_list)
#define ICNSS_CLK_LIST_SIZE ARRAY_SIZE(icnss_clk_list)
#define ICNSS_CLK_ADRESTEA_LIST_SIZE ARRAY_SIZE(icnss_adrestea_clk_list)
@@ -311,6 +320,10 @@ static struct icnss_vreg_cfg *get_vreg_list(u32 *vreg_list_size,
*vreg_list_size = ICNSS_VREG_ADRESTEA_LIST_SIZE;
return icnss_adrestea_vreg_list;
case WCN6450_DEVICE_ID:
*vreg_list_size = ICNSS_VREG_EVROS_LIST_SIZE;
return icnss_wcn6450_vreg_list;
default:
icnss_pr_err("Unsupported device_id 0x%x\n", device_id);
*vreg_list_size = 0;
@@ -524,7 +537,8 @@ int icnss_get_clk(struct icnss_priv *priv)
if (priv->device_id == ADRASTEA_DEVICE_ID) {
clk_cfg = icnss_adrestea_clk_list;
clk_list_size = ICNSS_CLK_ADRESTEA_LIST_SIZE;
} else if (priv->device_id == WCN6750_DEVICE_ID) {
} else if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
clk_cfg = icnss_clk_list;
clk_list_size = ICNSS_CLK_LIST_SIZE;
}

Dosyayı Görüntüle

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define pr_fmt(fmt) "icnss2_qmi: " fmt
@@ -55,6 +55,9 @@
#define DMS_MAC_NOT_PROVISIONED 16
#define BDWLAN_SIZE 6
#define UMC_CHIP_ID 0x4320
#define MAX_SHADOW_REG_RESERVED 2
#define MAX_NUM_SHADOW_REG_V3 (QMI_WLFW_MAX_NUM_SHADOW_REG_V3_USAGE_V01 - \
MAX_SHADOW_REG_RESERVED)
#ifdef CONFIG_ICNSS2_DEBUG
bool ignore_fw_timeout;
@@ -546,7 +549,8 @@ int wlfw_ind_register_send_sync_msg(struct icnss_priv *priv)
req->rejuvenate_enable_valid = 1;
req->rejuvenate_enable = 1;
}
} else if (priv->device_id == WCN6750_DEVICE_ID) {
} else if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID) {
req->fw_init_done_enable_valid = 1;
req->fw_init_done_enable = 1;
req->cal_done_enable_valid = 1;
@@ -2969,7 +2973,8 @@ int icnss_register_fw_service(struct icnss_priv *priv)
if (ret < 0)
return ret;
if (priv->device_id == WCN6750_DEVICE_ID)
if (priv->device_id == WCN6750_DEVICE_ID ||
priv->device_id == WCN6450_DEVICE_ID)
ret = qmi_add_lookup(&priv->qmi, WLFW_SERVICE_ID_V01,
WLFW_SERVICE_VERS_V01,
WLFW_SERVICE_WCN_INS_ID_V01);
@@ -3060,6 +3065,17 @@ int icnss_send_wlan_enable_to_fw(struct icnss_priv *priv,
memcpy(req.shadow_reg, config->shadow_reg_cfg,
sizeof(struct wlfw_msi_cfg_s_v01) * req.shadow_reg_len);
} else if (priv->device_id == WCN6450_DEVICE_ID) {
req.shadow_reg_v3_valid = 1;
if (config->num_shadow_reg_v3_cfg >
MAX_NUM_SHADOW_REG_V3)
req.shadow_reg_v3_len = MAX_NUM_SHADOW_REG_V3;
else
req.shadow_reg_v3_len = config->num_shadow_reg_v3_cfg;
memcpy(req.shadow_reg_v3, config->shadow_reg_v3_cfg,
sizeof(struct wlfw_shadow_reg_v3_cfg_s_v01)
* req.shadow_reg_v3_len);
}
ret = wlfw_wlan_cfg_send_sync_msg(priv, &req);

Dosyayı Görüntüle

@@ -15,12 +15,6 @@
#define CNSS_MAX_DEV_MEM_NUM 4
#define CNSS_CHIP_VER_ANY 0
/*
* Temporary change for compilation, will be removed
* after WLAN host driver switched to use new APIs
*/
#define CNSS_API_WITH_DEV
#define CNSS_SSR_DRIVER_DUMP_MAX_REGIONS 32
enum cnss_bus_width_type {
@@ -179,6 +173,9 @@ struct cnss_wlan_driver {
int (*collect_driver_dump)(struct pci_dev *pdev,
struct cnss_ssr_driver_dump_entry *input_array,
size_t *num_entries_loaded);
int (*set_therm_cdev_state)(struct pci_dev *pci_dev,
unsigned long thermal_state,
int tcdev_id);
};
struct cnss_ce_tgt_pipe_cfg {
@@ -227,6 +224,7 @@ struct cnss_wlan_enable_cfg {
struct cnss_rri_over_ddr_cfg rri_over_ddr_cfg;
u32 num_shadow_reg_v3_cfg;
struct cnss_shadow_reg_v3_cfg *shadow_reg_v3_cfg;
bool send_msi_ce;
};
enum cnss_driver_mode {
@@ -353,4 +351,11 @@ extern int cnss_send_buffer_to_afcmem(struct device *dev, char *afcdb,
extern int cnss_reset_afcmem(struct device *dev, uint8_t slotid);
extern bool cnss_get_fw_cap(struct device *dev, enum cnss_fw_caps fw_cap);
extern int cnss_set_wfc_mode(struct device *dev, struct cnss_wfc_cfg cfg);
extern int cnss_thermal_cdev_register(struct device *dev,
unsigned long max_state,
int tcdev_id);
extern void cnss_thermal_cdev_unregister(struct device *dev, int tcdev_id);
extern int cnss_get_curr_therm_cdev_state(struct device *dev,
unsigned long *thermal_state,
int tcdev_id);
#endif /* _NET_CNSS2_H */

Dosyayı Görüntüle

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ICNSS_WLAN_H_
#define _ICNSS_WLAN_H_
@@ -13,10 +14,6 @@
#define ICNSS_MAX_TIMESTAMP_LEN 32
#define ICNSS_WLFW_MAX_BUILD_ID_LEN 128
#ifndef ICNSS_API_WITH_DEV
#define ICNSS_API_WITH_DEV
#endif
#define DEVICE_NAME_MAX 10
enum icnss_uevent {
ICNSS_UEVENT_FW_CRASHED,
@@ -98,6 +95,10 @@ struct icnss_shadow_reg_v2_cfg {
u32 addr;
};
struct icnss_shadow_reg_v3_cfg {
u32 addr;
};
struct icnss_rri_over_ddr_cfg {
u32 base_addr_low;
u32 base_addr_high;
@@ -112,6 +113,8 @@ struct icnss_wlan_enable_cfg {
struct icnss_shadow_reg_cfg *shadow_reg_cfg;
u32 num_shadow_reg_v2_cfg;
struct icnss_shadow_reg_v2_cfg *shadow_reg_v2_cfg;
u32 num_shadow_reg_v3_cfg;
struct icnss_shadow_reg_v3_cfg *shadow_reg_v3_cfg;
bool rri_over_ddr_cfg_valid;
struct icnss_rri_over_ddr_cfg rri_over_ddr_cfg;
};
@@ -180,6 +183,7 @@ extern unsigned int icnss_socinfo_get_serial_number(struct device *dev);
extern bool icnss_is_qmi_disable(struct device *dev);
extern bool icnss_is_fw_ready(void);
extern bool icnss_is_fw_down(void);
extern bool icnss_is_low_power(void);
extern bool icnss_is_rejuvenate(void);
extern int icnss_trigger_recovery(struct device *dev);
extern void icnss_block_shutdown(bool status);