// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
*/
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/idr.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/module.h>
#include <linux/net.h>
#include <linux/platform_device.h>
#include <linux/qcom_scm.h>
#include <linux/string.h>
#include <net/sock.h>
#include "debug.h"
#include "snoc.h"
#define ATH10K_QMI_CLIENT_ID 0x4b4e454c
#define ATH10K_QMI_TIMEOUT 30
static int ath10k_qmi_map_msa_permission(struct ath10k_qmi *qmi,
struct ath10k_msa_mem_info *mem_info)
{
struct qcom_scm_vmperm dst_perms[3];
struct ath10k *ar = qmi->ar;
unsigned int src_perms;
u32 perm_count;
int ret;
src_perms = BIT(QCOM_SCM_VMID_HLOS);
dst_perms[0].vmid = QCOM_SCM_VMID_MSS_MSA;
dst_perms[0].perm = QCOM_SCM_PERM_RW;
dst_perms[1].vmid = QCOM_SCM_VMID_WLAN;
dst_perms[1].perm = QCOM_SCM_PERM_RW;
if (mem_info->secure) {
perm_count = 2;
} else {
dst_perms[2].vmid = QCOM_SCM_VMID_WLAN_CE;
dst_perms[2].perm = QCOM_SCM_PERM_RW;
perm_count = 3;
}
ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size,
&src_perms, dst_perms, perm_count);
if (ret < 0)
ath10k_err(ar, "failed to assign msa map permissions: %d\n", ret);
return ret;
}
static int ath10k_qmi_unmap_msa_permission(struct ath10k_qmi *qmi,
struct ath10k_msa_mem_info *mem_info)
{
struct qcom_scm_vmperm dst_perms;
struct ath10k *ar = qmi->ar;
unsigned int src_perms;
int ret;
src_perms = BIT(QCOM_SCM_VMID_MSS_MSA) | BIT(QCOM_SCM_VMID_WLAN);
if (!mem_info->secure)
src_perms |= BIT(QCOM_SCM_VMID_WLAN_CE);
dst_perms.vmid = QCOM_SCM_VMID_HLOS;
dst_perms.perm = QCOM_SCM_PERM_RW;
ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size,
&src_perms, &dst_perms, 1);
if (ret < 0)
ath10k_err(ar, "failed to unmap msa permissions: %d\n", ret);
return ret;
}
static int ath10k_qmi_setup_msa_permissions(struct ath10k_qmi *qmi)
{
int ret;
int i;
for (i = 0; i < qmi->nr_mem_region; i++) {
ret = ath10k_qmi_map_msa_permission(qmi, &qmi->mem_region[i]);
if (ret)
goto err_unmap;
}
return 0;
err_unmap:
for (i--; i >= 0; i--)
ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]);
return ret;
}
static void ath10k_qmi_remove_msa_permission(struct ath10k_qmi *qmi)
{
int i;
for (i = 0; i < qmi->nr_mem_region; i++)
ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]);
}
static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi)
{
struct wlfw_msa_info_resp_msg_v01 resp = {};
struct wlfw_msa_info_req_msg_v01 req = {};
struct ath10k *ar = qmi->ar;
phys_addr_t max_mapped_addr;
struct qmi_txn txn;
int ret;
int i;