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

Commit 8fe045c3 authored by Camera Software Integration's avatar Camera Software Integration Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: cpas: Add more debug information in cpas dump" into camera-kernel.lnx.4.0

parents eedefac6 f4ec43b7
Loading
Loading
Loading
Loading
+257 −2
Original line number Diff line number Diff line
@@ -19,6 +19,11 @@
static uint cam_min_camnoc_ib_bw;
module_param(cam_min_camnoc_ib_bw, uint, 0644);

static void cam_cpas_update_monitor_array(struct cam_hw_info *cpas_hw,
	const char *identifier_string, int32_t identifier_value);
static void cam_cpas_dump_monitor_array(
	struct cam_cpas *cpas_core);

static void cam_cpas_process_bw_overrides(
	struct cam_cpas_bus_client *bus_client, uint64_t *ab, uint64_t *ib,
	const struct cam_cpas_debug_settings *cpas_settings)
@@ -1068,9 +1073,16 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw,
	cam_cpas_dump_axi_vote_info(cpas_core->cpas_client[client_indx],
		"Translated Vote", &axi_vote);

	/* Log an entry whenever there is an AXI update - before updating */
	cam_cpas_update_monitor_array(cpas_hw, "CPAS AXI pre-update",
		client_indx);

	rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
		cpas_core->cpas_client[client_indx], &axi_vote);

	/* Log an entry whenever there is an AXI update - after updating */
	cam_cpas_update_monitor_array(cpas_hw, "CPAS AXI post-update",
		client_indx);
unlock_client:
	mutex_unlock(&cpas_core->client_mutex[client_indx]);
	mutex_unlock(&cpas_hw->hw_mutex);
@@ -1785,8 +1797,52 @@ static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw)
	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
	struct cam_cpas_private_soc *soc_private =
		(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
	int rc = 0;
	uint32_t i;
	struct cam_cpas_tree_node *curr_node;
	struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;

	/*
	 * First print rpmh registers as early as possible to catch nearest
	 * state of rpmh after an issue (overflow) occurs.
	 */
	if ((cpas_core->streamon_clients > 0) &&
		(cpas_core->regbase_index[CAM_CPAS_REG_RPMH] != -1)) {
		int reg_base_index =
			cpas_core->regbase_index[CAM_CPAS_REG_RPMH];
		void __iomem *rpmh_base =
			soc_info->reg_map[reg_base_index].mem_base;
		uint32_t offset_fe, offset_be;
		uint32_t fe_val, be_val;
		uint32_t *rpmh_info = &soc_private->rpmh_info[0];
		uint32_t ddr_bcm_index =
			soc_private->rpmh_info[CAM_RPMH_BCM_DDR_INDEX];
		uint32_t mnoc_bcm_index =
			soc_private->rpmh_info[CAM_RPMH_BCM_MNOC_INDEX];

		/*
		 * print 12 registers from 0x4, 0x800 offsets -
		 * this will give ddr, mmnoc and other BCM info.
		 * i=0 for DDR, i=4 for mnoc, but double check for each chipset.
		 */
		for (i = 0; i < rpmh_info[CAM_RPMH_NUMBER_OF_BCMS]; i++) {
			if ((!cpas_core->full_state_dump) &&
				(i != ddr_bcm_index) &&
				(i != mnoc_bcm_index))
				continue;

			offset_fe = rpmh_info[CAM_RPMH_BCM_FE_OFFSET] +
				(i * 0x4);
			offset_be = rpmh_info[CAM_RPMH_BCM_BE_OFFSET] +
				(i * 0x4);

			fe_val = cam_io_r_mb(rpmh_base + offset_fe);
			be_val = cam_io_r_mb(rpmh_base + offset_be);

			CAM_INFO(CAM_CPAS,
				"i=%d, FE[offset=0x%x, value=0x%x] BE[offset=0x%x, value=0x%x]",
				i, offset_fe, fe_val, offset_be, be_val);
		}
	}

	for (i = 0; i < cpas_core->num_axi_ports; i++) {
		CAM_INFO(CAM_CPAS,
@@ -1818,7 +1874,182 @@ static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw)
	CAM_INFO(CAM_CPAS, "ahb client curr vote level[%d]",
		cpas_core->ahb_bus_client.curr_vote_level);

	return rc;
	if (!cpas_core->full_state_dump) {
		CAM_DBG(CAM_CPAS, "CPAS full state dump not enabled");
		return 0;
	}

	/* This will traverse through all nodes in the tree and print stats*/
	for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) {
		if (!soc_private->tree_node[i])
			continue;
		curr_node = soc_private->tree_node[i];

		CAM_INFO(CAM_CPAS,
			"[%s] Cell[%d] level[%d] PortIdx[%d][%d] camnoc_bw[%d %d %lld %lld] mnoc_bw[%lld %lld]",
			curr_node->node_name, curr_node->cell_idx,
			curr_node->level_idx, curr_node->axi_port_idx,
			curr_node->camnoc_axi_port_idx,
			curr_node->camnoc_max_needed,
			curr_node->bus_width_factor,
			curr_node->camnoc_bw,
			curr_node->camnoc_bw * curr_node->bus_width_factor,
			curr_node->mnoc_ab_bw, curr_node->mnoc_ib_bw);
	}

	if (cpas_core->streamon_clients > 0) {
		/*
		 * Means, cpas has clocks turned on, so we can query clk freq.
		 * Print clk frequencies that cpas enables - this will print
		 * camcc_ahb, camcc_axi, gcc_hf, gcc_sf as well.
		 */
		cam_soc_util_print_clk_freq(&cpas_hw->soc_info);
	}

	cam_cpas_dump_monitor_array(cpas_core);

	return 0;
}

static void cam_cpas_update_monitor_array(struct cam_hw_info *cpas_hw,
	const char *identifier_string, int32_t identifier_value)
{
	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
	struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
	struct cam_cpas_private_soc *soc_private =
		(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
	struct cam_cpas_monitor *entry;
	int iterator;
	int i;

	CAM_CPAS_INC_MONITOR_HEAD(&cpas_core->monitor_head, &iterator);

	entry = &cpas_core->monitor_entries[iterator];

	ktime_get_real_ts64(&entry->timestamp);
	strlcpy(entry->identifier_string, identifier_string,
		sizeof(entry->identifier_string));

	entry->identifier_value = identifier_value;

	for (i = 0; i < cpas_core->num_axi_ports; i++) {
		entry->axi_info[i].axi_port_name =
			cpas_core->axi_port[i].axi_port_name;
		entry->axi_info[i].ab_bw = cpas_core->axi_port[i].ab_bw;
		entry->axi_info[i].ib_bw = cpas_core->axi_port[i].ib_bw;
		entry->axi_info[i].camnoc_bw = cpas_core->axi_port[i].camnoc_bw;
		entry->axi_info[i].applied_ab_bw =
			cpas_core->axi_port[i].applied_ab_bw;
		entry->axi_info[i].applied_ib_bw =
			cpas_core->axi_port[i].applied_ib_bw;
	}

	entry->applied_camnoc_clk = cpas_core->applied_camnoc_axi_rate;
	entry->applied_ahb_level = cpas_core->ahb_bus_client.curr_vote_level;

	if ((cpas_core->streamon_clients > 0) &&
		(cpas_core->regbase_index[CAM_CPAS_REG_RPMH] != -1) &&
		soc_private->rpmh_info[CAM_RPMH_NUMBER_OF_BCMS]) {
		int reg_base_index =
			cpas_core->regbase_index[CAM_CPAS_REG_RPMH];
		void __iomem *rpmh_base =
			soc_info->reg_map[reg_base_index].mem_base;
		uint32_t fe_ddr_offset =
			soc_private->rpmh_info[CAM_RPMH_BCM_FE_OFFSET] +
			(0x4 * soc_private->rpmh_info[CAM_RPMH_BCM_DDR_INDEX]);
		uint32_t fe_mnoc_offset =
			soc_private->rpmh_info[CAM_RPMH_BCM_FE_OFFSET] +
			(0x4 * soc_private->rpmh_info[CAM_RPMH_BCM_MNOC_INDEX]);
		uint32_t be_ddr_offset =
			soc_private->rpmh_info[CAM_RPMH_BCM_BE_OFFSET] +
			(0x4 * soc_private->rpmh_info[CAM_RPMH_BCM_DDR_INDEX]);
		uint32_t be_mnoc_offset =
			soc_private->rpmh_info[CAM_RPMH_BCM_BE_OFFSET] +
			(0x4 * soc_private->rpmh_info[CAM_RPMH_BCM_MNOC_INDEX]);

		/*
		 * 0x4, 0x800 - DDR
		 * 0x800, 0x810 - mmnoc
		 */
		entry->fe_ddr = cam_io_r_mb(rpmh_base + fe_ddr_offset);
		entry->fe_mnoc = cam_io_r_mb(rpmh_base + fe_mnoc_offset);
		entry->be_ddr = cam_io_r_mb(rpmh_base + be_ddr_offset);
		entry->be_mnoc = cam_io_r_mb(rpmh_base + be_mnoc_offset);
	}
}

static void cam_cpas_dump_monitor_array(
	struct cam_cpas *cpas_core)
{
	int i = 0, j = 0;
	int64_t state_head = 0;
	uint32_t index, num_entries, oldest_entry;
	uint64_t ms, tmp, hrs, min, sec;
	struct cam_cpas_monitor *entry;

	if (!cpas_core->full_state_dump)
		return;

	state_head = atomic64_read(&cpas_core->monitor_head);

	if (state_head == -1) {
		CAM_WARN(CAM_CPAS, "No valid entries in cpas monitor array");
		return;
	} else if (state_head < CAM_CPAS_MONITOR_MAX_ENTRIES) {
		num_entries = state_head;
		oldest_entry = 0;
	} else {
		num_entries = CAM_CPAS_MONITOR_MAX_ENTRIES;
		div_u64_rem(state_head + 1,
			CAM_CPAS_MONITOR_MAX_ENTRIES, &oldest_entry);
	}

	CAM_INFO(CAM_CPAS, "======== Dumping monitor information ===========");

	index = oldest_entry;

	for (i = 0; i < num_entries; i++) {
		entry = &cpas_core->monitor_entries[index];
		tmp = entry->timestamp.tv_sec;
		ms = (entry->timestamp.tv_nsec) / 1000000;
		sec = do_div(tmp, 60);
		min = do_div(tmp, 60);
		hrs = do_div(tmp, 24);

		CAM_INFO(CAM_CPAS,
			"**** %llu:%llu:%llu.%llu : Index[%d] Identifier[%s][%d] camnoc=%lld, ahb=%d",
			hrs, min, sec, ms,
			index,
			entry->identifier_string, entry->identifier_value,
			entry->applied_camnoc_clk, entry->applied_ahb_level);

		for (j = 0; j < cpas_core->num_axi_ports; j++) {
			CAM_INFO(CAM_CPAS,
				"MNOC BW [%s] : ab=%lld, ib=%lld, camnoc=%lld",
				entry->axi_info[j].axi_port_name,
				entry->axi_info[j].applied_ab_bw,
				entry->axi_info[j].applied_ib_bw,
				entry->axi_info[j].camnoc_bw);
		}

		if (cpas_core->regbase_index[CAM_CPAS_REG_RPMH] != -1) {
			CAM_INFO(CAM_CPAS,
				"fe_ddr=0x%x, fe_mnoc=0x%x, be_ddr=0x%x, be_mnoc=0x%x",
				entry->fe_ddr, entry->fe_mnoc,
				entry->be_ddr, entry->be_mnoc);
		}

		index = (index + 1) % CAM_CPAS_MONITOR_MAX_ENTRIES;
	}
}

static int cam_cpas_log_event(struct cam_hw_info *cpas_hw,
	const char *identifier_string, int32_t identifier_value)
{
	cam_cpas_update_monitor_array(cpas_hw, identifier_string,
		identifier_value);

	return 0;
}

static int cam_cpas_select_qos(struct cam_hw_info *cpas_hw,
@@ -1957,6 +2188,22 @@ static int cam_cpas_hw_process_cmd(void *hw_priv,
		break;
	}

	case CAM_CPAS_HW_CMD_LOG_EVENT: {
		struct cam_cpas_hw_cmd_notify_event *event;

		if (sizeof(struct cam_cpas_hw_cmd_notify_event) != arg_size) {
			CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d",
				cmd_type, arg_size);
			break;
		}

		event = (struct cam_cpas_hw_cmd_notify_event *)cmd_args;

		rc = cam_cpas_log_event(hw_priv, event->identifier_string,
			event->identifier_value);
		break;
	}

	case CAM_CPAS_HW_CMD_SELECT_QOS: {
		uint32_t *selection_mask;

@@ -2052,6 +2299,10 @@ static int cam_cpas_util_create_debugfs(struct cam_cpas *cpas_core)

	dbgfileptr = debugfs_create_bool("ahb_bus_scaling_disable", 0644,
		cpas_core->dentry, &cpas_core->ahb_bus_scaling_disable);

	dbgfileptr = debugfs_create_bool("full_state_dump", 0644,
		cpas_core->dentry, &cpas_core->full_state_dump);

	if (IS_ERR(dbgfileptr)) {
		if (PTR_ERR(dbgfileptr) == -ENODEV)
			CAM_WARN(CAM_CPAS, "DebugFS not enabled in kernel!");
@@ -2102,6 +2353,10 @@ int cam_cpas_hw_probe(struct platform_device *pdev,
	cpas_hw->soc_info.dev_name = pdev->name;
	cpas_hw->open_count = 0;
	cpas_core->ahb_bus_scaling_disable = false;
	cpas_core->full_state_dump = false;

	atomic64_set(&cpas_core->monitor_head, -1);

	mutex_init(&cpas_hw->hw_mutex);
	spin_lock_init(&cpas_hw->hw_lock);
	init_completion(&cpas_hw->hw_complete);
+69 −0
Original line number Diff line number Diff line
@@ -37,6 +37,19 @@
	((CAM_CPAS_CLIENT_REGISTERED(cpas_core, indx)) && \
	(cpas_core->cpas_client[indx]->started))

/* Array indices to represent corresponding RPMH BCM info */
#define CAM_RPMH_NUMBER_OF_BCMS 0
#define CAM_RPMH_BCM_FE_OFFSET  1
#define CAM_RPMH_BCM_BE_OFFSET  2
#define CAM_RPMH_BCM_DDR_INDEX  3
#define CAM_RPMH_BCM_MNOC_INDEX 4
#define CAM_RPMH_BCM_INFO_MAX   5

#define CAM_CPAS_MONITOR_MAX_ENTRIES   20
#define CAM_CPAS_INC_MONITOR_HEAD(head, ret) \
	div_u64_rem(atomic64_add_return(1, head),\
	CAM_CPAS_MONITOR_MAX_ENTRIES, (ret))

/**
 * enum cam_cpas_access_type - Enum for Register access type
 */
@@ -163,6 +176,56 @@ struct cam_cpas_axi_port {
	uint64_t applied_ib_bw;
};

/**
 * struct cam_cpas_axi_port_debug_info : AXI port information
 *
 * @axi_port_name: Name of this AXI port
 * @ab_bw: AB bw value for this port
 * @ib_bw: IB bw value for this port
 * @camnoc_bw: CAMNOC bw value for this port
 * @applied_ab_bw: applied ab bw for this port
 * @applied_ib_bw: applied ib bw for this port
 */
struct cam_cpas_axi_port_debug_info {
	const char *axi_port_name;
	uint64_t ab_bw;
	uint64_t ib_bw;
	uint64_t camnoc_bw;
	uint64_t applied_ab_bw;
	uint64_t applied_ib_bw;
};

/**
 * struct cam_cpas_monitor : CPAS monitor array
 *
 * @timestamp: Timestamp at which this monitor entry is saved
 * @axi_info: AXI port information
 * @identifier_string: String passed by caller
 * @identifier_value: Identifier value passed by caller
 * @applied_camnoc_clk: Applied camnoc axi clock rate
 * @applied_ahb_level: Applied camcc ahb level
 * @fe_ddr: RPMH DDR BCM FE (front-end) status register value.
 *          This indicates requested clock plan
 * @be_ddr: RPMH DDR BCM BE (back-end) status register value.
 *          This indicates actual current clock plan
 * @fe_mnoc: RPMH MNOC BCM FE (front-end) status register value.
 *           This indicates requested clock plan
 * @be_mnoc: RPMH MNOC BCM BE (back-end) status register value.
 *           This indicates actual current clock plan
 */
struct cam_cpas_monitor {
	struct timespec64                   timestamp;
	char                                identifier_string[128];
	int32_t                             identifier_value;
	struct cam_cpas_axi_port_debug_info axi_info[CAM_CPAS_MAX_AXI_PORTS];
	uint64_t                            applied_camnoc_clk;
	unsigned int                        applied_ahb_level;
	uint32_t                            fe_ddr;
	uint32_t                            be_ddr;
	uint32_t                            fe_mnoc;
	uint32_t                            be_mnoc;
};

/**
 * struct cam_cpas : CPAS core data structure info
 *
@@ -186,6 +249,9 @@ struct cam_cpas_axi_port {
 * @dentry: debugfs file entry
 * @ahb_bus_scaling_disable: ahb scaling based on src clk corner for bus
 * @applied_camnoc_axi_rate: applied camnoc axi clock rate
 * @monitor_head: Monitor array head
 * @monitor_entries: cpas monitor array
 * @full_state_dump: Whether to enable full cpas state dump or not
 */
struct cam_cpas {
	struct cam_cpas_hw_caps hw_caps;
@@ -208,6 +274,9 @@ struct cam_cpas {
	struct dentry *dentry;
	bool ahb_bus_scaling_disable;
	uint64_t applied_camnoc_axi_rate;
	atomic64_t  monitor_head;
	struct cam_cpas_monitor monitor_entries[CAM_CPAS_MONITOR_MAX_ENTRIES];
	bool full_state_dump;
};

int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops);
+13 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ enum cam_cpas_hw_cmd_process {
	CAM_CPAS_HW_CMD_AXI_VOTE,
	CAM_CPAS_HW_CMD_LOG_VOTE,
	CAM_CPAS_HW_CMD_SELECT_QOS,
	CAM_CPAS_HW_CMD_LOG_EVENT,
	CAM_CPAS_HW_CMD_INVALID,
};

@@ -107,6 +108,18 @@ struct cam_cpas_hw_cmd_stop {
	uint32_t client_handle;
};

/**
 * struct cam_cpas_hw_cmd_notify_event : CPAS cmd struct for notify event
 *
 * @identifier_string: Identifier string passed by caller
 * @identifier_value: Identifier value passed by caller
 *
 */
struct cam_cpas_hw_cmd_notify_event {
	const char *identifier_string;
	int32_t identifier_value;
};

/**
 * struct cam_cpas_hw_caps : CPAS HW capabilities
 *
+31 −0
Original line number Diff line number Diff line
@@ -461,6 +461,37 @@ int cam_cpas_select_qos_settings(uint32_t selection_mask)
}
EXPORT_SYMBOL(cam_cpas_select_qos_settings);

int cam_cpas_notify_event(const char *identifier_string,
	int32_t identifier_value)
{
	int rc = 0;

	if (!CAM_CPAS_INTF_INITIALIZED()) {
		CAM_ERR(CAM_CPAS, "cpas intf not initialized");
		return -EBADR;
	}

	if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
		struct cam_cpas_hw_cmd_notify_event event = { 0 };

		event.identifier_string = identifier_string;
		event.identifier_value = identifier_value;

		rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
			g_cpas_intf->hw_intf->hw_priv,
			CAM_CPAS_HW_CMD_LOG_EVENT, &event,
			sizeof(event));
		if (rc)
			CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
	} else {
		CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
		rc = -EBADR;
	}

	return rc;
}
EXPORT_SYMBOL(cam_cpas_notify_event);

int cam_cpas_unregister_client(uint32_t client_handle)
{
	int rc;
+34 −0
Original line number Diff line number Diff line
@@ -834,6 +834,40 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
		goto cleanup_tree;
	}

	/* Optional rpmh bcm info */
	count = of_property_count_u32_elems(of_node, "rpmh-bcm-info");
	/*
	 * We expect count=5(CAM_RPMH_BCM_INFO_MAX) if valid rpmh bcm info
	 * is available.
	 * 0 - Total number of BCMs
	 * 1 - First BCM FE (front-end) register offset.
	 *     These represent requested clk plan by sw
	 * 2 - First BCM BE (back-end) register offset.
	 *     These represent actual clk plan at hw
	 * 3 - DDR BCM index
	 * 4 - MMNOC BCM index
	 */
	if (count == CAM_RPMH_BCM_INFO_MAX) {
		for (i = 0; i < count; i++) {
			rc = of_property_read_u32_index(of_node,
				"rpmh-bcm-info", i, &soc_private->rpmh_info[i]);
			if (rc) {
				CAM_ERR(CAM_CPAS,
					"Incorrect rpmh info at %d, count=%d",
					i, count);
				break;
			}
			CAM_DBG(CAM_CPAS, "RPMH BCM Info [%d]=0x%x",
				i, soc_private->rpmh_info[i]);
		}

		if (rc)
			soc_private->rpmh_info[CAM_RPMH_NUMBER_OF_BCMS] = 0;
	} else {
		CAM_DBG(CAM_CPAS, "RPMH BCM info not available in DT, count=%d",
			count);
	}

	return 0;

cleanup_tree:
Loading