Merge "msm: ipa: unlock WLAN doorbell register access"

This commit is contained in:
Linux Build Service Account 2016-09-30 18:23:45 -07:00 committed by Gerrit - the friendly Code Review server
commit e9ad6b6beb
3 changed files with 151 additions and 1 deletions

View file

@ -80,6 +80,8 @@ memory allocation over a PCIe bridge
- qcom,rx-polling-sleep-ms: Receive Polling Timeout in millisecond, - qcom,rx-polling-sleep-ms: Receive Polling Timeout in millisecond,
default is 1 millisecond. default is 1 millisecond.
- qcom,ipa-polling-iteration: IPA Polling Iteration Count,default is 40. - 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): IPA pipe sub nodes (A2 static pipes configurations):

View file

@ -38,6 +38,16 @@
#include <linux/hash.h> #include <linux/hash.h>
#include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/smem.h> #include <soc/qcom/smem.h>
#include <soc/qcom/scm.h>
#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" #define IPA_SUBSYSTEM_NAME "ipa_fws"
#include "ipa_i.h" #include "ipa_i.h"
#include "../ipa_rm_i.h" #include "../ipa_rm_i.h"
@ -199,6 +209,21 @@ struct ipa3_ioc_nat_alloc_mem32 {
}; };
#endif #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 void ipa3_start_tag_process(struct work_struct *work);
static DECLARE_WORK(ipa3_tag_work, ipa3_start_tag_process); 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; 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. * ipa3_pre_init() - Initialize the IPA Driver.
* This part contains all initialization which doesn't require IPA HW, such * 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->apply_rg10_wa = resource_p->apply_rg10_wa;
ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa; ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa;
ipa3_ctx->ipa3_active_clients_logging.log_rdy = false; 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 */ /* default aggregation parameters */
ipa3_ctx->aggregation_type = IPA_MBIM_16; ipa3_ctx->aggregation_type = IPA_MBIM_16;
@ -4568,6 +4661,8 @@ fail_init_mem_partition:
fail_bind: fail_bind:
kfree(ipa3_ctx->ctrl); kfree(ipa3_ctx->ctrl);
fail_mem_ctrl: fail_mem_ctrl:
kfree(ipa3_ctx->ipa_tz_unlock_reg);
fail_tz_unlock_reg:
ipc_log_context_destroy(ipa3_ctx->logbuf); ipc_log_context_destroy(ipa3_ctx->logbuf);
fail_logbuf: fail_logbuf:
kfree(ipa3_ctx); kfree(ipa3_ctx);
@ -4579,8 +4674,10 @@ fail_mem_ctx:
static int get_ipa_dts_configuration(struct platform_device *pdev, static int get_ipa_dts_configuration(struct platform_device *pdev,
struct ipa3_plat_drv_res *ipa_drv_res) struct ipa3_plat_drv_res *ipa_drv_res)
{ {
int result; int i, result, pos;
struct resource *resource; struct resource *resource;
u32 *ipa_tz_unlock_reg;
int elem_num;
/* initialize ipa3_res */ /* initialize ipa3_res */
ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST; 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->lan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
ipa_drv_res->apply_rg10_wa = false; ipa_drv_res->apply_rg10_wa = false;
ipa_drv_res->gsi_ch20_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, smmu_info.disable_htw = of_property_read_bool(pdev->dev.of_node,
"qcom,smmu-disable-htw"); "qcom,smmu-disable-htw");
@ -4808,6 +4907,46 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
ipa_drv_res->apply_rg10_wa ipa_drv_res->apply_rg10_wa
? "Needed" : "Not needed"); ? "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; return 0;
} }

View file

@ -1012,6 +1012,11 @@ struct ipa3_ready_cb_info {
void *user_data; void *user_data;
}; };
struct ipa_tz_unlock_reg_info {
u64 reg_addr;
u32 size;
};
/** /**
* struct ipa3_context - IPA context * struct ipa3_context - IPA context
* @class: pointer to the struct class * @class: pointer to the struct class
@ -1228,6 +1233,8 @@ struct ipa3_context {
struct list_head ipa_ready_cb_list; struct list_head ipa_ready_cb_list;
struct completion init_completion_obj; struct completion init_completion_obj;
struct ipa3_smp2p_info smp2p_info; 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 apply_rg10_wa;
bool gsi_ch20_wa; bool gsi_ch20_wa;
bool tethered_flow_control; bool tethered_flow_control;
u32 ipa_tz_unlock_reg_num;
struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg;
}; };
/** /**