Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 420c76be authored by Yuanyuan Liu's avatar Yuanyuan Liu
Browse files

cnss2: Add debugfs for dynamic feature



Add a debugfs for dynamic feature. User can enable/disable certain
features in WLAN FW by writing to this debugfs.

CRs-Fixed: 2468610
Change-Id: Iefaa905c52011edcf9619d5ddbe8e356dfce04ba
Signed-off-by: default avatarYuanyuan Liu <yuanliu@codeaurora.org>
parent 9b7165c0
Loading
Loading
Loading
Loading
+47 −0
Original line number Original line Diff line number Diff line
@@ -650,6 +650,51 @@ static const struct file_operations cnss_control_params_debug_fops = {
	.llseek = seq_lseek,
	.llseek = seq_lseek,
};
};


static ssize_t cnss_dynamic_feature_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;
	int ret = 0;
	u64 val;

	ret = kstrtou64_from_user(user_buf, count, 0, &val);
	if (ret)
		return ret;

	plat_priv->dynamic_feature = val;
	ret = cnss_wlfw_dynamic_feature_mask_send_sync(plat_priv);
	if (ret < 0)
		return ret;

	return count;
}

static int cnss_dynamic_feature_show(struct seq_file *s, void *data)
{
	struct cnss_plat_data *cnss_priv = s->private;

	seq_printf(s, "dynamic_feature: 0x%llx\n", cnss_priv->dynamic_feature);

	return 0;
}

static int cnss_dynamic_feature_open(struct inode *inode,
				     struct file *file)
{
	return single_open(file, cnss_dynamic_feature_show,
			   inode->i_private);
}

static const struct file_operations cnss_dynamic_feature_fops = {
	.read = seq_read,
	.write = cnss_dynamic_feature_write,
	.open = cnss_dynamic_feature_open,
	.owner = THIS_MODULE,
	.llseek = seq_lseek,
};

#ifdef CONFIG_CNSS2_DEBUG
#ifdef CONFIG_CNSS2_DEBUG
static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
{
{
@@ -665,6 +710,8 @@ static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
			    &cnss_runtime_pm_debug_fops);
			    &cnss_runtime_pm_debug_fops);
	debugfs_create_file("control_params", 0600, root_dentry, plat_priv,
	debugfs_create_file("control_params", 0600, root_dentry, plat_priv,
			    &cnss_control_params_debug_fops);
			    &cnss_control_params_debug_fops);
	debugfs_create_file("dynamic_feature", 0600, root_dentry, plat_priv,
			    &cnss_dynamic_feature_fops);


	return 0;
	return 0;
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -339,6 +339,7 @@ struct cnss_plat_data {
	struct qmi_handle coex_qmi;
	struct qmi_handle coex_qmi;
	struct qmi_handle ims_qmi;
	struct qmi_handle ims_qmi;
	struct qmi_txn txn;
	struct qmi_txn txn;
	u64 dynamic_feature;
};
};


#ifdef CONFIG_ARCH_QCOM
#ifdef CONFIG_ARCH_QCOM
+64 −0
Original line number Original line Diff line number Diff line
@@ -1368,6 +1368,70 @@ static int cnss_wlfw_wfc_call_status_send_sync(struct cnss_plat_data *plat_priv,
	return ret;
	return ret;
}
}


int cnss_wlfw_dynamic_feature_mask_send_sync(struct cnss_plat_data *plat_priv)
{
	struct wlfw_dynamic_feature_mask_req_msg_v01 *req;
	struct wlfw_dynamic_feature_mask_resp_msg_v01 *resp;
	struct qmi_txn txn;
	int ret = 0;

	cnss_pr_dbg("Sending dynamic feature mask 0x%llx, state: 0x%lx\n",
		    plat_priv->dynamic_feature,
		    plat_priv->driver_state);

	req = kzalloc(sizeof(*req), GFP_KERNEL);
	if (!req)
		return -ENOMEM;

	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
	if (!resp) {
		kfree(req);
		return -ENOMEM;
	}

	req->mask_valid = 1;
	req->mask = plat_priv->dynamic_feature;

	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
			   wlfw_dynamic_feature_mask_resp_msg_v01_ei, resp);
	if (ret < 0) {
		cnss_pr_err("Fail to initialize txn for dynamic feature mask request: err %d\n",
			    ret);
		goto out;
	}

	ret = qmi_send_request
		(&plat_priv->qmi_wlfw, NULL, &txn,
		 QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01,
		 WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN,
		 wlfw_dynamic_feature_mask_req_msg_v01_ei, req);
	if (ret < 0) {
		qmi_txn_cancel(&txn);
		cnss_pr_err("Fail to send dynamic feature mask request: err %d\n",
			    ret);
		goto out;
	}

	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
	if (ret < 0) {
		cnss_pr_err("Fail to wait for response of dynamic feature mask request, err %d\n",
			    ret);
		goto out;
	}

	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
		cnss_pr_err("Dynamic feature mask request failed, result: %d, err: %d\n",
			    resp->resp.result, resp->resp.error);
		ret = -resp->resp.result;
		goto out;
	}

out:
	kfree(req);
	kfree(resp);
	return ret;
}

unsigned int cnss_get_qmi_timeout(struct cnss_plat_data *plat_priv)
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);
	cnss_pr_dbg("QMI timeout is %u ms\n", QMI_WLFW_TIMEOUT_MS);
+7 −0
Original line number Original line Diff line number Diff line
@@ -58,6 +58,7 @@ int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
			    u8 fw_log_mode);
			    u8 fw_log_mode);
int cnss_wlfw_antenna_switch_send_sync(struct cnss_plat_data *plat_priv);
int cnss_wlfw_antenna_switch_send_sync(struct cnss_plat_data *plat_priv);
int cnss_wlfw_antenna_grant_send_sync(struct cnss_plat_data *plat_priv);
int cnss_wlfw_antenna_grant_send_sync(struct cnss_plat_data *plat_priv);
int cnss_wlfw_dynamic_feature_mask_send_sync(struct cnss_plat_data *plat_priv);
int cnss_register_coex_service(struct cnss_plat_data *plat_priv);
int cnss_register_coex_service(struct cnss_plat_data *plat_priv);
void cnss_unregister_coex_service(struct cnss_plat_data *plat_priv);
void cnss_unregister_coex_service(struct cnss_plat_data *plat_priv);
int coex_antenna_switch_to_wlan_send_sync_msg(struct cnss_plat_data *plat_priv);
int coex_antenna_switch_to_wlan_send_sync_msg(struct cnss_plat_data *plat_priv);
@@ -166,6 +167,12 @@ int cnss_wlfw_antenna_grant_send_sync(struct cnss_plat_data *plat_priv)
	return 0;
	return 0;
}
}


static inline
int cnss_wlfw_dynamic_feature_mask_send_sync(struct cnss_plat_data *plat_priv)
{
	return 0;
}

static inline
static inline
int cnss_register_coex_service(struct cnss_plat_data *plat_priv)
int cnss_register_coex_service(struct cnss_plat_data *plat_priv)
{
{