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

Commit f048dfe1 authored by Perry Randise's avatar Perry Randise
Browse files

msm: ipa3: Access Control aware IPA register dump



Embellished the IPA/GSI dump/collection feature, such that
it's now Access Control aware.

Change-Id: I0d75294c614419cbbc67164942fe9c42557ff421
CRs-Fixed: 2401867
Signed-off-by: default avatarPerry Randise <prandise@codeaurora.org>
parent 96ae0c26
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -16,4 +16,6 @@ obj-$(CONFIG_IPA3_MHI_PROXY) += ipa_mhi_proxy.o

ipat-$(CONFIG_IPA3_REGDUMP) += dump/ipa_reg_dump.o

ccflags-$(CONFIG_IPA3_REGDUMP) += -Idrivers/platform/msm/ipa/ipa_v3/dump

ccflags-$(CONFIG_IPA3_REGDUMP_IPA_4_5) += -Idrivers/platform/msm/ipa/ipa_v3/dump/ipa4.5
+42 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 */
#if !defined(_IPA_ACCESS_CONTROL_H_)
#define _IPA_ACCESS_CONTROL_H_

#include "ipa_reg_dump.h"

/*
 * The following is target specific.
 */
static struct reg_mem_access_map_t mem_access_map[] = {
	/*------------------------------------------------------------*/
	/*      Range               Use when              Use when    */
	/*  Begin    End           SD_ENABLED           SD_DISABLED   */
	/*------------------------------------------------------------*/
	{ 0x04000, 0x05000, { &io_matrix[AN_COMBO], &io_matrix[AN_COMBO] } },
	{ 0x1F000, 0x27000, { &io_matrix[AN_COMBO], &io_matrix[AN_COMBO] } },
	{ 0x05000, 0x0f000, { &io_matrix[AA_COMBO], &io_matrix[AN_COMBO] } },
	{ 0x0f000, 0x10000, { &io_matrix[NN_COMBO], &io_matrix[NN_COMBO] } },
	{ 0x13000, 0x17000, { &io_matrix[AA_COMBO], &io_matrix[AA_COMBO] } },
	{ 0x17000, 0x1b000, { &io_matrix[AN_COMBO], &io_matrix[AN_COMBO] } },
	{ 0x1b000, 0x1f000, { &io_matrix[AN_COMBO], &io_matrix[AN_COMBO] } },
	{ 0x10000, 0x11000, { &io_matrix[AA_COMBO], &io_matrix[AA_COMBO] } },
	{ 0x11000, 0x12000, { &io_matrix[AN_COMBO], &io_matrix[AN_COMBO] } },
	{ 0x12000, 0x13000, { &io_matrix[AA_COMBO], &io_matrix[AA_COMBO] } },
	{ 0x43000, 0x44000, { &io_matrix[AA_COMBO], &io_matrix[AA_COMBO] } },
	{ 0x44000, 0x45000, { &io_matrix[AA_COMBO], &io_matrix[AA_COMBO] } },
	{ 0x45000, 0x47000, { &io_matrix[AN_COMBO], &io_matrix[AN_COMBO] } },
	{ 0x40000, 0x42000, { &io_matrix[AA_COMBO], &io_matrix[AA_COMBO] } },
	{ 0x42000, 0x43000, { &io_matrix[AA_COMBO], &io_matrix[AN_COMBO] } },
	{ 0x50000, 0x60000, { &io_matrix[AA_COMBO], &io_matrix[AA_COMBO] } },
	{ 0x60000, 0x80000, { &io_matrix[AN_COMBO], &io_matrix[NN_COMBO] } },
	{ 0x80000, 0x81000, { &io_matrix[NN_COMBO], &io_matrix[NN_COMBO] } },
	{ 0x81000, 0x83000, { &io_matrix[AN_COMBO], &io_matrix[AN_COMBO] } },
	{ 0xa0000, 0xc0000, { &io_matrix[AN_COMBO], &io_matrix[AN_COMBO] } },
	{ 0xc0000, 0xc2000, { &io_matrix[AA_COMBO], &io_matrix[AA_COMBO] } },
	{ 0xc2000, 0xd0000, { &io_matrix[AA_COMBO], &io_matrix[AA_COMBO] } },
};

#endif /* #if !defined(_IPA_ACCESS_CONTROL_H_) */
+89 −33
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 */
#include "ipa_reg_dump.h"
#include "ipa_access_control.h"

/* Total size required for test bus */
#define IPA_MEM_OVERLAY_SIZE     0x66000
@@ -16,8 +17,6 @@ static struct regs_save_hierarchy_s ipa_reg_save;

static unsigned int ipa_testbus_mem[IPA_MEM_OVERLAY_SIZE];

static u32 gsi_ver;

/*
 * The following data structure contains a list of the registers
 * (whose data are to be copied) and the locations (within
@@ -673,6 +672,55 @@ static void ipa_hal_save_regs_ipa_cmdq(void);
static void ipa_hal_save_regs_rsrc_db(void);
static void ipa_reg_save_anomaly_check(void);

static struct reg_access_funcs_s *get_access_funcs(u32 addr)
{
	u32 i, asub = ipa3_ctx->sd_state;

	for (i = 0; i < ARRAY_SIZE(mem_access_map); i++) {
		if (addr >= mem_access_map[i].addr_range_begin &&
			addr <= mem_access_map[i].addr_range_end) {
			return mem_access_map[i].access[asub];
		}
	}

	IPAERR("Unknown register offset(0x%08X). Using dflt access methods\n",
		   addr);

	return &io_matrix[AA_COMBO];
}

static u32 in_dword(
	u32 addr)
{
	struct reg_access_funcs_s *io = get_access_funcs(addr);

	return io->read(ipa3_ctx->reg_collection_base + addr);
}

static u32 in_dword_masked(
	u32 addr,
	u32 mask)
{
	struct reg_access_funcs_s *io = get_access_funcs(addr);
	u32 val;

	val = io->read(ipa3_ctx->reg_collection_base + addr);

	if (io->read == act_read)
		return val & mask;

	return val;
}

static void out_dword(
	u32 addr,
	u32 val)
{
	struct reg_access_funcs_s *io = get_access_funcs(addr);

	io->write(ipa3_ctx->reg_collection_base + addr, val);
}

/*
 * FUNCTION:  ipa_save_gsi_ver
 *
@@ -683,7 +731,7 @@ static void ipa_reg_save_anomaly_check(void);
 */
void ipa_save_gsi_ver(void)
{
	gsi_ver =
	ipa_reg_save.gsi.fw_ver =
		IPA_READ_1xVECTOR_REG(IPA_GSI_TOP_GSI_INST_RAM_n, 0) &
		0x0000FFFF;
}
@@ -702,9 +750,8 @@ void ipa_save_registers(void)
	/* Fetch the number of registers configured to be saved */
	u32 num_regs = ARRAY_SIZE(ipa_regs_to_save_array);
	u32 num_uc_per_regs = ARRAY_SIZE(ipa_uc_regs_to_save_array);
	union ipa_hwio_def_ipa_rsrc_mngr_db_cfg_u ipa_rsrc_mngr_db_cfg;
	union ipa_hwio_def_ipa_rsrc_mngr_db_rsrc_read_u
	    ipa_rsrc_mngr_db_rsrc_read;
	union ipa_hwio_def_ipa_rsrc_mngr_db_cfg_u for_cfg;
	union ipa_hwio_def_ipa_rsrc_mngr_db_rsrc_read_u for_read;

	if (!ipa3_ctx->do_register_collection_on_crash)
		return;
@@ -718,9 +765,8 @@ void ipa_save_registers(void)
	num_regs -= (CONFIG_IPA3_REGDUMP_NUM_EXTRA_ENDP_REGS *
		     IPA_REG_SAVE_NUM_EXTRA_ENDP_REGS);

	memset(&ipa_rsrc_mngr_db_cfg, 0, sizeof(ipa_rsrc_mngr_db_cfg));
	memset(&ipa_rsrc_mngr_db_rsrc_read, 0,
	       sizeof(ipa_rsrc_mngr_db_rsrc_read));
	memset(&for_cfg, 0, sizeof(for_cfg));
	memset(&for_read, 0, sizeof(for_read));

	/* Now save all the configured registers */
	for (i = 0; i < num_regs; i++) {
@@ -867,38 +913,48 @@ void ipa_save_registers(void)
	 * true, via dtsi, and the collection will be done.
	 */
	if (ipa3_ctx->do_non_tn_collection_on_crash) {
		u32 ofst = GEN_2xVECTOR_REG_OFST(IPA_CTX_ID_m_CTX_NUM_n, 0, 0);
		struct reg_access_funcs_s *io = get_access_funcs(ofst);
		/*
		 * Copy Pkt context directly from IPA_CTX_ID register space
		 * If the memory is accessible, copy pkt context directly from
		 * IPA_CTX_ID register space
		 */
		if (io->read == act_read) {
			memcpy((void *)ipa_reg_save.pkt_ctntx,
		       (void *)((u8 *) ipa3_ctx->reg_collection_base +
				GEN_2xVECTOR_REG_OFST(
				    IPA_CTX_ID_m_CTX_NUM_n, 0, 0)),
				   (const void *)
				   (ipa3_ctx->reg_collection_base + ofst),
				   sizeof(ipa_reg_save.pkt_ctntx));

		ipa_rsrc_mngr_db_cfg.value =
			for_cfg.value =
				IPA_READ_SCALER_REG(IPA_RSRC_MNGR_DB_CFG);

		ipa_rsrc_mngr_db_cfg.def.rsrc_type_sel = 0;
		IPA_MASKED_WRITE_SCALER_REG(IPA_RSRC_MNGR_DB_CFG,
				     ipa_rsrc_mngr_db_cfg.value);
			for_cfg.def.rsrc_type_sel = 0;

			IPA_MASKED_WRITE_SCALER_REG(
				IPA_RSRC_MNGR_DB_CFG,
				for_cfg.value);

			for (i = 0; i < IPA_HW_PKT_CTNTX_MAX; i++) {
			ipa_rsrc_mngr_db_cfg.def.rsrc_id_sel = i;
			IPA_MASKED_WRITE_SCALER_REG(IPA_RSRC_MNGR_DB_CFG,
					     ipa_rsrc_mngr_db_cfg.value);
				for_cfg.def.rsrc_id_sel = i;

				IPA_MASKED_WRITE_SCALER_REG(
					IPA_RSRC_MNGR_DB_CFG,
					for_cfg.value);

			ipa_rsrc_mngr_db_rsrc_read.value =
				for_read.value =
					IPA_READ_SCALER_REG(
						IPA_RSRC_MNGR_DB_RSRC_READ);

			if (ipa_rsrc_mngr_db_rsrc_read.def.rsrc_occupied) {
				if (for_read.def.rsrc_occupied) {
					ipa_reg_save.pkt_ctntx_active[i] = true;
					ipa_reg_save.pkt_cntxt_state[i] =
						(enum ipa_hw_pkt_cntxt_state_e)
						ipa_reg_save.pkt_ctntx[i].state;
				}
			}
		} else {
			IPAERR("IPA_CTX_ID is not currently accessible\n");
		}
	}

	ipa_reg_save_anomaly_check();
@@ -1348,7 +1404,7 @@ static void ipa_hal_save_regs_save_ipa_testbus(void)
 *
 * @return
 */
int ipa_reg_save_init(u8 value)
int ipa_reg_save_init(u32 value)
{
	u32 i, num_regs = ARRAY_SIZE(ipa_regs_to_save_array);

+100 −12
Original line number Diff line number Diff line
@@ -19,21 +19,9 @@
 */
#define my_in_dword(addr) \
	({ u32 __v = readl_relaxed((addr)); __iormb(); __v; })
#define in_dword(addr) \
	my_in_dword((u8 *) ipa3_ctx->reg_collection_base + \
		    (u32)(addr))

#define my_in_dword_masked(addr, mask) \
	(my_in_dword(addr) & (mask))
#define in_dword_masked(addr, mask) \
	my_in_dword_masked((u8 *) ipa3_ctx->reg_collection_base + \
			   (u32)(addr), (mask))

#define my_out_dword(addr, val) \
	({ __iowmb(); writel_relaxed((val), (addr)); })
#define out_dword(addr, val) \
	my_out_dword((u8 *) ipa3_ctx->reg_collection_base + \
		     (u32)(addr), (val))

#define IPA_0_IPA_WRAPPER_BASE 0 /* required by following includes */

@@ -1263,6 +1251,7 @@ struct ipa_regs_save_hierarchy_s {

/* Top level GSI register save data struct */
struct gsi_regs_save_hierarchy_s {
	u32 fw_ver;
	struct ipa_reg_save_gsi_gen_s		gen;
	struct ipa_reg_save_gsi_gen_ee_s	gen_ee[IPA_REG_SAVE_GSI_NUM_EE];
	struct ipa_reg_save_gsi_ch_cntxt_s	ch_cntxt;
@@ -1325,4 +1314,103 @@ struct regs_save_hierarchy_s {
		gsi_fifo_status[IPA_HW_PIPE_ID_MAX];
};

/*
 * The following section deals with handling IPA registers' memory
 * access relative to pre-defined memory protection schemes
 * (ie. "access control").
 *
 * In a nut shell, the intent of the data stuctures below is to allow
 * higher level register accessors to be unaware of what really is
 * going on at the lowest level (ie. real vs non-real access).  This
 * methodology is also designed to allow for platform specific "access
 * maps."
 */

/*
 * Function for doing an actual read
 */
static inline u32
act_read(void __iomem *addr)
{
	u32 val = my_in_dword(addr);

	return val;
}

/*
 * Function for doing an actual write
 */
static inline void
act_write(void __iomem *addr, u32 val)
{
	my_out_dword(addr, val);
}

/*
 * Function that pretends to do a read
 */
static inline u32
nop_read(void __iomem *addr)
{
	return IPA_MEM_INIT_VAL;
}

/*
 * Function that pretends to do a write
 */
static inline void
nop_write(void __iomem *addr, u32 val)
{
}

/*
 * The following are used to define struct reg_access_funcs_s below...
 */
typedef u32 (*reg_read_func_t)(
	void __iomem *addr);
typedef void (*reg_write_func_t)(
	void __iomem *addr,
	u32 val);

/*
 * The following in used to define io_matrix[] below...
 */
struct reg_access_funcs_s {
	reg_read_func_t  read;
	reg_write_func_t write;
};

/*
 * The following will be used to appropriately index into the
 * read/write combos defined in io_matrix[] below...
 */
#define AA_COMBO 0 /* actual read, actual write */
#define AN_COMBO 1 /* actual read, no-op write  */
#define NA_COMBO 2 /* no-op read,  actual write */
#define NN_COMBO 3 /* no-op read,  no-op write  */

/*
 * The following will be used to dictate registers' access methods
 * relative to the state of secure debug...whether it's enabled or
 * disabled.
 *
 * NOTE: The table below defines all access combinations.
 */
static struct reg_access_funcs_s io_matrix[] = {
	{ act_read, act_write }, /* the AA_COMBO */
	{ act_read, nop_write }, /* the AN_COMBO */
	{ nop_read, act_write }, /* the NA_COMBO */
	{ nop_read, nop_write }, /* the NN_COMBO */
};

/*
 * The following will be used to define and drive IPA's register
 * access rules.
 */
struct reg_mem_access_map_t {
	u32 addr_range_begin;
	u32 addr_range_end;
	struct reg_access_funcs_s *access[2];
};

#endif /* #if !defined(_IPA_REG_DUMP_H_) */
+64 −1
Original line number Diff line number Diff line
@@ -5171,6 +5171,32 @@ static int ipa3_alloc_pkt_init(void)
	return 0;
}

/*
 * SCM call to check if secure dump is allowed.
 *
 * Returns true in secure dump allowed.
 * Return false when secure dump not allowed.
 */
#define TZ_UTIL_GET_SEC_DUMP_STATE  0x10
static bool ipa_is_mem_dump_allowed(void)
{
	struct scm_desc desc = {0};
	int ret = 0;

	desc.args[0] = 0;
	desc.arginfo = 0;

	ret = scm_call2(
		SCM_SIP_FNID(SCM_SVC_UTIL, TZ_UTIL_GET_SEC_DUMP_STATE),
		&desc);
	if (ret) {
		IPAERR("SCM DUMP_STATE call failed\n");
		return false;
	}

	return (desc.ret[0] == 1);
}

/**
 * ipa3_pre_init() - Initialize the IPA Driver.
 * This part contains all initialization which doesn't require IPA HW, such
@@ -5260,6 +5286,30 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
	    resource_p->do_testbus_collection_on_crash;
	ipa3_ctx->do_non_tn_collection_on_crash =
	    resource_p->do_non_tn_collection_on_crash;
	ipa3_ctx->secure_debug_check_action =
		resource_p->secure_debug_check_action;

	if (ipa3_ctx->secure_debug_check_action == USE_SCM) {
		if (ipa_is_mem_dump_allowed())
			ipa3_ctx->sd_state = SD_ENABLED;
		else
			ipa3_ctx->sd_state = SD_DISABLED;
	} else {
		if (ipa3_ctx->secure_debug_check_action == OVERRIDE_SCM_TRUE)
			ipa3_ctx->sd_state = SD_ENABLED;
		else
			/* secure_debug_check_action == OVERRIDE_SCM_FALSE */
			ipa3_ctx->sd_state = SD_DISABLED;
	}

	if (ipa3_ctx->sd_state == SD_ENABLED) {
		/* secure debug is enabled. */
		IPADBG("secure debug enabled\n");
	} else {
		/* secure debug is disabled. */
		IPADBG("secure debug disabled\n");
		ipa3_ctx->do_testbus_collection_on_crash = false;
	}

	WARN(ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL,
		"Non NORMAL IPA HW mode, is this emulation platform ?");
@@ -5380,7 +5430,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
	/*
	 * Setup access for register collection/dump on crash
	 */
	if (ipa_reg_save_init(0xFF) != 0) {
	if (ipa_reg_save_init(IPA_MEM_INIT_VAL) != 0) {
		result = -EFAULT;
		goto fail_gsi_map;
	}
@@ -6213,6 +6263,19 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
	IPADBG(": doing register collection on crash = %u\n",
	       ipa_drv_res->do_register_collection_on_crash);

	result = of_property_read_u32(
		pdev->dev.of_node,
		"qcom,secure-debug-check-action",
		&ipa_drv_res->secure_debug_check_action);
	if (result ||
		(ipa_drv_res->secure_debug_check_action != 0 &&
		 ipa_drv_res->secure_debug_check_action != 1 &&
		 ipa_drv_res->secure_debug_check_action != 2))
		ipa_drv_res->secure_debug_check_action = USE_SCM;

	IPADBG(": secure-debug-check-action = %d\n",
		   ipa_drv_res->secure_debug_check_action);

	return 0;
}

Loading