summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/soc/qcom/icnss.c112
1 files changed, 110 insertions, 2 deletions
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 807349533dd1..883f23d8234d 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -36,6 +36,7 @@
#include <soc/qcom/memory_dump.h>
#include <soc/qcom/icnss.h>
#include <soc/qcom/msm_qmi_interface.h>
+#include <soc/qcom/secure_buffer.h>
#include "wlan_firmware_service_v01.h"
@@ -533,6 +534,105 @@ int icnss_power_off(struct device *dev)
}
EXPORT_SYMBOL(icnss_power_off);
+int icnss_map_msa_permissions(struct icnss_data *priv, u32 index)
+{
+ int ret = 0;
+ phys_addr_t addr;
+ u32 size;
+ u32 source_vmlist[1] = {VMID_HLOS};
+ int dest_vmids[3] = {VMID_MSS_MSA, VMID_WLAN, 0};
+ int dest_perms[3] = {PERM_READ|PERM_WRITE,
+ PERM_READ|PERM_WRITE,
+ PERM_READ|PERM_WRITE};
+ int source_nelems = sizeof(source_vmlist)/sizeof(u32);
+ int dest_nelems = 0;
+
+ addr = priv->icnss_mem_region[index].reg_addr;
+ size = priv->icnss_mem_region[index].size;
+
+ if (!priv->icnss_mem_region[index].secure_flag) {
+ dest_vmids[2] = VMID_WLAN_CE;
+ dest_nelems = 3;
+ } else {
+ dest_vmids[2] = 0;
+ dest_nelems = 2;
+ }
+ ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems,
+ dest_vmids, dest_perms, dest_nelems);
+ if (ret) {
+ icnss_pr_err("region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n",
+ index, &addr, size, ret);
+ goto out;
+ }
+ icnss_pr_dbg("hypervisor map for region %u: source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n",
+ index, source_vmlist[0], dest_nelems,
+ dest_vmids[0], dest_vmids[1], dest_vmids[2]);
+out:
+ return ret;
+
+}
+
+int icnss_unmap_msa_permissions(struct icnss_data *priv, u32 index)
+{
+ int ret = 0;
+ phys_addr_t addr;
+ u32 size;
+ u32 dest_vmids[1] = {VMID_HLOS};
+ int source_vmlist[3] = {VMID_MSS_MSA, VMID_WLAN, 0};
+ int dest_perms[1] = {PERM_READ|PERM_WRITE};
+ int source_nelems = 0;
+ int dest_nelems = sizeof(dest_vmids)/sizeof(u32);
+
+ addr = priv->icnss_mem_region[index].reg_addr;
+ size = priv->icnss_mem_region[index].size;
+ if (!priv->icnss_mem_region[index].secure_flag) {
+ source_vmlist[2] = VMID_WLAN_CE;
+ source_nelems = 3;
+ } else {
+ source_vmlist[2] = 0;
+ source_nelems = 2;
+ }
+
+ ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems,
+ dest_vmids, dest_perms, dest_nelems);
+ if (ret) {
+ icnss_pr_err("region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n",
+ index, &addr, size, ret);
+ goto out;
+ }
+ icnss_pr_dbg("hypervisor unmap for region %u, source_nelems=%d, source[0]=%x, source[1]=%x, source[2]=%x, dest=%x\n",
+ index, source_nelems,
+ source_vmlist[0], source_vmlist[1], source_vmlist[2],
+ dest_vmids[0]);
+out:
+ return ret;
+}
+
+static int icnss_setup_msa_permissions(struct icnss_data *priv)
+{
+ int ret = 0;
+
+ ret = icnss_map_msa_permissions(priv, 0);
+ if (ret)
+ return ret;
+
+ ret = icnss_map_msa_permissions(priv, 1);
+ if (ret)
+ goto err_map_msa;
+
+ return ret;
+
+err_map_msa:
+ icnss_unmap_msa_permissions(priv, 0);
+ return ret;
+}
+
+static void icnss_remove_msa_permissions(struct icnss_data *priv)
+{
+ icnss_unmap_msa_permissions(priv, 0);
+ icnss_unmap_msa_permissions(priv, 1);
+}
+
static int wlfw_msa_mem_info_send_sync_msg(void)
{
int ret = 0;
@@ -1049,19 +1149,27 @@ static int icnss_driver_event_server_arrive(void *data)
icnss_pr_err("Failed to send MSA info: %d\n", ret);
goto err_power_on;
}
+ ret = icnss_setup_msa_permissions(penv);
+ if (ret < 0) {
+ icnss_pr_err("Failed to setup msa permissions: %d\n",
+ ret);
+ goto err_power_on;
+ }
ret = wlfw_msa_ready_send_sync_msg();
if (ret < 0) {
icnss_pr_err("Failed to send MSA ready : %d\n", ret);
- goto err_power_on;
+ goto err_setup_msa;
}
ret = wlfw_cap_send_sync_msg();
if (ret < 0) {
icnss_pr_err("Failed to get capability: %d\n", ret);
- goto err_power_on;
+ goto err_setup_msa;
}
return ret;
+err_setup_msa:
+ icnss_remove_msa_permissions(penv);
err_power_on:
icnss_hw_power_off(penv);
fail: