diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt index f3166d33f9e4..a8db893f6709 100644 --- a/Documentation/devicetree/bindings/platform/msm/ipa.txt +++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt @@ -80,6 +80,8 @@ memory allocation over a PCIe bridge - qcom,rx-polling-sleep-ms: Receive Polling Timeout in millisecond, default is 1 millisecond. - qcom,ipa-polling-iteration: IPA Polling Iteration Count,default is 40. +- qcom,ipa-tz-unlock-reg: Register start addresses and ranges which + need to be unlocked by TZ. IPA pipe sub nodes (A2 static pipes configurations): diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index a7089f5e6c3c..24fbc5c738d8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -38,6 +38,16 @@ #include #include #include +#include + +#ifdef CONFIG_ARM64 + +/* Outer caches unsupported on ARM64 platforms */ +#define outer_flush_range(x, y) +#define __cpuc_flush_dcache_area __flush_dcache_area + +#endif + #define IPA_SUBSYSTEM_NAME "ipa_fws" #include "ipa_i.h" #include "../ipa_rm_i.h" @@ -199,6 +209,21 @@ struct ipa3_ioc_nat_alloc_mem32 { }; #endif +#define IPA_TZ_UNLOCK_ATTRIBUTE 0x0C0311 +#define TZ_MEM_PROTECT_REGION_ID 0x10 + +struct tz_smmu_ipa_protect_region_iovec_s { + u64 input_addr; + u64 output_addr; + u64 size; + u32 attr; +} __packed; + +struct tz_smmu_ipa_protect_region_s { + phys_addr_t iovec_buf; + u32 size_bytes; +} __packed; + static void ipa3_start_tag_process(struct work_struct *work); static DECLARE_WORK(ipa3_tag_work, ipa3_start_tag_process); @@ -4036,6 +4061,53 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf, return count; } +static int ipa3_tz_unlock_reg(struct ipa3_context *ipa3_ctx) +{ + int i, size, ret, resp; + struct tz_smmu_ipa_protect_region_iovec_s *ipa_tz_unlock_vec; + struct tz_smmu_ipa_protect_region_s cmd_buf; + + if (ipa3_ctx && ipa3_ctx->ipa_tz_unlock_reg_num > 0) { + size = ipa3_ctx->ipa_tz_unlock_reg_num * + sizeof(struct tz_smmu_ipa_protect_region_iovec_s); + ipa_tz_unlock_vec = kzalloc(PAGE_ALIGN(size), GFP_KERNEL); + if (ipa_tz_unlock_vec == NULL) + return -ENOMEM; + + for (i = 0; i < ipa3_ctx->ipa_tz_unlock_reg_num; i++) { + ipa_tz_unlock_vec[i].input_addr = + ipa3_ctx->ipa_tz_unlock_reg[i].reg_addr ^ + (ipa3_ctx->ipa_tz_unlock_reg[i].reg_addr & + 0xFFF); + ipa_tz_unlock_vec[i].output_addr = + ipa3_ctx->ipa_tz_unlock_reg[i].reg_addr ^ + (ipa3_ctx->ipa_tz_unlock_reg[i].reg_addr & + 0xFFF); + ipa_tz_unlock_vec[i].size = + ipa3_ctx->ipa_tz_unlock_reg[i].size; + ipa_tz_unlock_vec[i].attr = IPA_TZ_UNLOCK_ATTRIBUTE; + } + + /* pass physical address of command buffer */ + cmd_buf.iovec_buf = virt_to_phys((void *)ipa_tz_unlock_vec); + cmd_buf.size_bytes = size; + + /* flush cache to DDR */ + __cpuc_flush_dcache_area((void *)ipa_tz_unlock_vec, size); + outer_flush_range(cmd_buf.iovec_buf, cmd_buf.iovec_buf + size); + + ret = scm_call(SCM_SVC_MP, TZ_MEM_PROTECT_REGION_ID, &cmd_buf, + sizeof(cmd_buf), &resp, sizeof(resp)); + if (ret) { + IPAERR("scm call SCM_SVC_MP failed: %d\n", ret); + kfree(ipa_tz_unlock_vec); + return -EFAULT; + } + kfree(ipa_tz_unlock_vec); + } + return 0; +} + /** * ipa3_pre_init() - Initialize the IPA Driver. * This part contains all initialization which doesn't require IPA HW, such @@ -4120,6 +4192,27 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa; ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa; ipa3_ctx->ipa3_active_clients_logging.log_rdy = false; + if (resource_p->ipa_tz_unlock_reg) { + ipa3_ctx->ipa_tz_unlock_reg_num = + resource_p->ipa_tz_unlock_reg_num; + ipa3_ctx->ipa_tz_unlock_reg = kcalloc( + ipa3_ctx->ipa_tz_unlock_reg_num, + sizeof(*ipa3_ctx->ipa_tz_unlock_reg), + GFP_KERNEL); + if (ipa3_ctx->ipa_tz_unlock_reg == NULL) { + result = -ENOMEM; + goto fail_tz_unlock_reg; + } + for (i = 0; i < ipa3_ctx->ipa_tz_unlock_reg_num; i++) { + ipa3_ctx->ipa_tz_unlock_reg[i].reg_addr = + resource_p->ipa_tz_unlock_reg[i].reg_addr; + ipa3_ctx->ipa_tz_unlock_reg[i].size = + resource_p->ipa_tz_unlock_reg[i].size; + } + } + + /* unlock registers for uc */ + ipa3_tz_unlock_reg(ipa3_ctx); /* default aggregation parameters */ ipa3_ctx->aggregation_type = IPA_MBIM_16; @@ -4568,6 +4661,8 @@ fail_init_mem_partition: fail_bind: kfree(ipa3_ctx->ctrl); fail_mem_ctrl: + kfree(ipa3_ctx->ipa_tz_unlock_reg); +fail_tz_unlock_reg: ipc_log_context_destroy(ipa3_ctx->logbuf); fail_logbuf: kfree(ipa3_ctx); @@ -4579,8 +4674,10 @@ fail_mem_ctx: static int get_ipa_dts_configuration(struct platform_device *pdev, struct ipa3_plat_drv_res *ipa_drv_res) { - int result; + int i, result, pos; struct resource *resource; + u32 *ipa_tz_unlock_reg; + int elem_num; /* initialize ipa3_res */ ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST; @@ -4595,6 +4692,8 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->lan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ; ipa_drv_res->apply_rg10_wa = false; ipa_drv_res->gsi_ch20_wa = false; + ipa_drv_res->ipa_tz_unlock_reg_num = 0; + ipa_drv_res->ipa_tz_unlock_reg = NULL; smmu_info.disable_htw = of_property_read_bool(pdev->dev.of_node, "qcom,smmu-disable-htw"); @@ -4808,6 +4907,46 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->apply_rg10_wa ? "Needed" : "Not needed"); + elem_num = of_property_count_elems_of_size(pdev->dev.of_node, + "qcom,ipa-tz-unlock-reg", sizeof(u32)); + + if (elem_num > 0 && elem_num % 2 == 0) { + ipa_drv_res->ipa_tz_unlock_reg_num = elem_num / 2; + + ipa_tz_unlock_reg = kcalloc(elem_num, sizeof(u32), GFP_KERNEL); + if (ipa_tz_unlock_reg == NULL) + return -ENOMEM; + + ipa_drv_res->ipa_tz_unlock_reg = kcalloc( + ipa_drv_res->ipa_tz_unlock_reg_num, + sizeof(*ipa_drv_res->ipa_tz_unlock_reg), + GFP_KERNEL); + if (ipa_drv_res->ipa_tz_unlock_reg == NULL) { + kfree(ipa_tz_unlock_reg); + return -ENOMEM; + } + + if (of_property_read_u32_array(pdev->dev.of_node, + "qcom,ipa-tz-unlock-reg", ipa_tz_unlock_reg, + elem_num)) { + IPAERR("failed to read register addresses\n"); + kfree(ipa_tz_unlock_reg); + kfree(ipa_drv_res->ipa_tz_unlock_reg); + return -EFAULT; + } + + pos = 0; + for (i = 0; i < ipa_drv_res->ipa_tz_unlock_reg_num; i++) { + ipa_drv_res->ipa_tz_unlock_reg[i].reg_addr = + ipa_tz_unlock_reg[pos++]; + ipa_drv_res->ipa_tz_unlock_reg[i].size = + ipa_tz_unlock_reg[pos++]; + IPADBG("tz unlock reg %d: addr 0x%pa size %d\n", i, + &ipa_drv_res->ipa_tz_unlock_reg[i].reg_addr, + ipa_drv_res->ipa_tz_unlock_reg[i].size); + } + kfree(ipa_tz_unlock_reg); + } return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 4309fbc3154f..cfbd291e09da 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1012,6 +1012,11 @@ struct ipa3_ready_cb_info { void *user_data; }; +struct ipa_tz_unlock_reg_info { + u64 reg_addr; + u32 size; +}; + /** * struct ipa3_context - IPA context * @class: pointer to the struct class @@ -1228,6 +1233,8 @@ struct ipa3_context { struct list_head ipa_ready_cb_list; struct completion init_completion_obj; struct ipa3_smp2p_info smp2p_info; + u32 ipa_tz_unlock_reg_num; + struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg; }; /** @@ -1266,6 +1273,8 @@ struct ipa3_plat_drv_res { bool apply_rg10_wa; bool gsi_ch20_wa; bool tethered_flow_control; + u32 ipa_tz_unlock_reg_num; + struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg; }; /**