Browse Source

msm: camera: common: Add sysfs support for bw override

To simulate bus overflow recovery in camera, cpas needs sysfs
to take input from shell and vote the final value as given,
instead of consolidated values from cpas clients. Add initial
support for sysfs to add nodes for all drivers. Add sysfs
based debug node to maintain and update all settings. Add cpas
settings to override final bw voted to camnoc and mnoc ports.

Usage:
adb shell "echo <driver_name>#<setting_name>=<value>
> /sys/devices/platform/soc/soc:qcom,cam-req-mgr/debug_node"

Example:i
adb shell "echo cpas#camnoc_bw=100
> /sys/devices/platform/soc/soc:qcom,cam-req-mgr/debug_node"

Input format for updating settings is strict.

CRs-Fixed: 2646825
Change-Id: I8d6063240f9685474bf4b2899e8dfb3f74cbdb75
Signed-off-by: Mukund Madhusudan Atre <[email protected]>
Mukund Madhusudan Atre 5 years ago
parent
commit
2e6a2419b4

+ 84 - 0
drivers/cam_cpas/cam_cpas_hw.c

@@ -13,10 +13,63 @@
 #include "cam_cpas_hw.h"
 #include "cam_cpas_hw_intf.h"
 #include "cam_cpas_soc.h"
+#include "cam_req_mgr_dev.h"
 
 static uint cam_min_camnoc_ib_bw;
 module_param(cam_min_camnoc_ib_bw, uint, 0644);
 
+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)
+{
+	uint64_t curr_ab = *ab;
+	uint64_t curr_ib = *ib;
+	size_t name_len = strlen(bus_client->common_data.name);
+
+	if (!cpas_settings) {
+		CAM_ERR(CAM_CPAS, "Invalid cpas debug settings");
+		return;
+	}
+
+	if (strnstr(bus_client->common_data.name, "cam_hf_0", name_len)) {
+		if (cpas_settings->mnoc_hf_0_ab_bw)
+			*ab = cpas_settings->mnoc_hf_0_ab_bw;
+		if (cpas_settings->mnoc_hf_0_ib_bw)
+			*ib = cpas_settings->mnoc_hf_0_ib_bw;
+	} else if (strnstr(bus_client->common_data.name, "cam_hf_1",
+		name_len)) {
+		if (cpas_settings->mnoc_hf_1_ab_bw)
+			*ab = cpas_settings->mnoc_hf_1_ab_bw;
+		if (cpas_settings->mnoc_hf_0_ib_bw)
+			*ib = cpas_settings->mnoc_hf_1_ib_bw;
+	} else if (strnstr(bus_client->common_data.name, "cam_sf_0",
+		name_len)) {
+		if (cpas_settings->mnoc_sf_0_ab_bw)
+			*ab = cpas_settings->mnoc_sf_0_ab_bw;
+		if (cpas_settings->mnoc_sf_0_ib_bw)
+			*ib = cpas_settings->mnoc_sf_0_ib_bw;
+	} else if (strnstr(bus_client->common_data.name, "cam_sf_1",
+		name_len)) {
+		if (cpas_settings->mnoc_sf_1_ab_bw)
+			*ab = cpas_settings->mnoc_sf_1_ab_bw;
+		if (cpas_settings->mnoc_sf_1_ib_bw)
+			*ib = cpas_settings->mnoc_sf_1_ib_bw;
+	} else if (strnstr(bus_client->common_data.name, "cam_sf_icp",
+		name_len)) {
+		if (cpas_settings->mnoc_sf_icp_ab_bw)
+			*ab = cpas_settings->mnoc_sf_icp_ab_bw;
+		if (cpas_settings->mnoc_sf_icp_ib_bw)
+			*ib = cpas_settings->mnoc_sf_icp_ib_bw;
+	} else {
+		CAM_ERR(CAM_CPAS, "unknown mnoc port: %s, bw override failed",
+			bus_client->common_data.name);
+		return;
+	}
+
+	CAM_INFO(CAM_CPAS,
+		"Overriding mnoc bw for: %s with ab: %llu, ib: %llu, curr_ab: %llu, curr_ib: %llu",
+		bus_client->common_data.name, *ab, *ib, curr_ab, curr_ib);
+}
 
 int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw,
 	enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info)
@@ -85,6 +138,7 @@ static int cam_cpas_util_vote_bus_client_bw(
 {
 	int rc = 0;
 	uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW;
+	const struct camera_debug_settings *cam_debug = NULL;
 
 	if (!bus_client->valid) {
 		CAM_ERR(CAM_CPAS, "bus client: %s not valid",
@@ -116,6 +170,21 @@ static int cam_cpas_util_vote_bus_client_bw(
 			ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW;
 	}
 
+	cam_debug = cam_debug_get_settings();
+
+	if (cam_debug && (cam_debug->cpas_settings.mnoc_hf_0_ab_bw ||
+		cam_debug->cpas_settings.mnoc_hf_0_ib_bw ||
+		cam_debug->cpas_settings.mnoc_hf_1_ab_bw ||
+		cam_debug->cpas_settings.mnoc_hf_1_ib_bw ||
+		cam_debug->cpas_settings.mnoc_sf_0_ab_bw ||
+		cam_debug->cpas_settings.mnoc_sf_0_ib_bw ||
+		cam_debug->cpas_settings.mnoc_sf_1_ab_bw ||
+		cam_debug->cpas_settings.mnoc_sf_1_ib_bw ||
+		cam_debug->cpas_settings.mnoc_sf_icp_ab_bw ||
+		cam_debug->cpas_settings.mnoc_sf_icp_ib_bw))
+		cam_cpas_process_bw_overrides(bus_client, &ab, &ib,
+			&cam_debug->cpas_settings);
+
 	rc = cam_soc_bus_client_update_bw(bus_client->soc_bus_client, ab, ib);
 	if (rc) {
 		CAM_ERR(CAM_CPAS,
@@ -376,6 +445,8 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate(
 	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
 	struct cam_cpas_tree_node *tree_node = NULL;
 	int rc = 0, i = 0;
+	const struct camera_debug_settings *cam_debug = NULL;
+
 
 	CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d",
 		soc_private->control_camnoc_axi_clk);
@@ -415,6 +486,19 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate(
 			soc_private->camnoc_axi_min_ib_bw))
 			required_camnoc_bw = soc_private->camnoc_axi_min_ib_bw;
 
+		cam_debug = cam_debug_get_settings();
+		if (cam_debug && cam_debug->cpas_settings.camnoc_bw) {
+			if (cam_debug->cpas_settings.camnoc_bw <
+				soc_private->camnoc_bus_width)
+				required_camnoc_bw =
+					soc_private->camnoc_bus_width;
+			else
+				required_camnoc_bw =
+					cam_debug->cpas_settings.camnoc_bw;
+			CAM_INFO(CAM_CPAS, "Overriding camnoc bw: %llu",
+				required_camnoc_bw);
+		}
+
 		intermediate_result = required_camnoc_bw;
 		do_div(intermediate_result, soc_private->camnoc_bus_width);
 		clk_rate = intermediate_result;

+ 13 - 0
drivers/cam_req_mgr/cam_req_mgr_dev.c

@@ -25,12 +25,16 @@
 #include "cam_debug_util.h"
 #include "cam_common_util.h"
 #include "cam_compat.h"
+#include "cam_cpas_hw.h"
 
 #define CAM_REQ_MGR_EVENT_MAX 30
 
 static struct cam_req_mgr_device g_dev;
 struct kmem_cache *g_cam_req_mgr_timer_cachep;
 
+static struct device_attribute camera_debug_sysfs_attr =
+	__ATTR(debug_node, 0600, NULL, cam_debug_sysfs_node_store);
+
 static int cam_media_device_setup(struct device *dev)
 {
 	int rc;
@@ -810,9 +814,17 @@ static int cam_req_mgr_component_master_bind(struct device *dev)
 	}
 
 	CAM_INFO(CAM_CRM, "All camera components bound successfully");
+	rc = sysfs_create_file(&dev->kobj, &camera_debug_sysfs_attr.attr);
+	if (rc < 0) {
+		CAM_ERR(CAM_CPAS,
+			"Failed to create debug attribute, rc=%d\n", rc);
+		goto sysfs_fail;
+	}
 
 	return rc;
 
+sysfs_fail:
+	sysfs_remove_file(&dev->kobj, &camera_debug_sysfs_attr.attr);
 req_mgr_device_deinit:
 	cam_req_mgr_core_device_deinit();
 req_mgr_core_fail:
@@ -835,6 +847,7 @@ static void cam_req_mgr_component_master_unbind(struct device *dev)
 	component_unbind_all(dev, NULL);
 
 	/* Now proceed with unbinding master */
+	sysfs_remove_file(&dev->kobj, &camera_debug_sysfs_attr.attr);
 	cam_req_mgr_core_device_deinit();
 	cam_req_mgr_util_deinit();
 	cam_media_device_cleanup();

+ 103 - 0
drivers/cam_utils/cam_debug_util.c

@@ -4,12 +4,115 @@
  */
 
 #include <linux/io.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 
 #include "cam_debug_util.h"
 
 static uint debug_mdl;
 module_param(debug_mdl, uint, 0644);
+struct camera_debug_settings cam_debug;
+
+const struct camera_debug_settings *cam_debug_get_settings()
+{
+	return &cam_debug;
+}
+
+static int cam_debug_parse_cpas_settings(const char *setting, u64 value)
+{
+	if (!strcmp(setting, "camnoc_bw")) {
+		cam_debug.cpas_settings.camnoc_bw = value;
+	} else if (!strcmp(setting, "mnoc_hf_0_ab_bw")) {
+		cam_debug.cpas_settings.mnoc_hf_0_ab_bw = value;
+	} else if (!strcmp(setting, "mnoc_hf_0_ib_bw")) {
+		cam_debug.cpas_settings.mnoc_hf_0_ib_bw = value;
+	} else if (!strcmp(setting, "mnoc_hf_1_ab_bw")) {
+		cam_debug.cpas_settings.mnoc_hf_1_ab_bw = value;
+	} else if (!strcmp(setting, "mnoc_hf_1_ib_bw")) {
+		cam_debug.cpas_settings.mnoc_hf_1_ib_bw = value;
+	} else if (!strcmp(setting, "mnoc_sf_0_ab_bw")) {
+		cam_debug.cpas_settings.mnoc_sf_0_ab_bw = value;
+	} else if (!strcmp(setting, "mnoc_sf_0_ib_bw")) {
+		cam_debug.cpas_settings.mnoc_sf_0_ib_bw = value;
+	} else if (!strcmp(setting, "mnoc_sf_1_ab_bw")) {
+		cam_debug.cpas_settings.mnoc_sf_1_ab_bw = value;
+	} else if (!strcmp(setting, "mnoc_sf_1_ib_bw")) {
+		cam_debug.cpas_settings.mnoc_sf_1_ib_bw = value;
+	} else if (!strcmp(setting, "mnoc_sf_icp_ab_bw")) {
+		cam_debug.cpas_settings.mnoc_sf_icp_ab_bw = value;
+	} else if (!strcmp(setting, "mnoc_sf_icp_ib_bw")) {
+		cam_debug.cpas_settings.mnoc_sf_icp_ib_bw = value;
+	} else {
+		CAM_ERR(CAM_UTIL, "Unsupported cpas sysfs entry");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+ssize_t cam_debug_sysfs_node_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int rc = 0;
+	char *local_buf = NULL, *local_buf_temp = NULL;
+	char *driver;
+	char *setting = NULL;
+	char *value_str = NULL;
+	u64 value;
+
+	CAM_INFO(CAM_UTIL, "Sysfs debug attr name:[%s] buf:[%s] bytes:[%d]",
+		attr->attr.name, buf, count);
+	local_buf = kmemdup(buf, (count + sizeof(char)), GFP_KERNEL);
+	local_buf_temp = local_buf;
+	driver = strsep(&local_buf, "#");
+	if (!driver) {
+		CAM_ERR(CAM_UTIL,
+			"Invalid input driver name buf:[%s], count:%d",
+			buf, count);
+		goto error;
+	}
+
+	setting = strsep(&local_buf, "=");
+	if (!setting) {
+		CAM_ERR(CAM_UTIL, "Invalid input setting buf:[%s], count:%d",
+			buf, count);
+		goto error;
+	}
+
+	value_str = strsep(&local_buf, "=");
+	if (!value_str) {
+		CAM_ERR(CAM_UTIL, "Invalid input value buf:[%s], count:%d",
+			buf, count);
+		goto error;
+	}
+
+	rc = kstrtou64(value_str, 0, &value);
+	if (rc < 0) {
+		CAM_ERR(CAM_UTIL, "Error converting value:[%s], buf:[%s]",
+			value_str, buf);
+		goto error;
+	}
+
+	CAM_INFO(CAM_UTIL,
+		"Processing sysfs store for driver:[%s], setting:[%s], value:[%llu]",
+		driver, setting, value);
+
+	if (!strcmp(driver, "cpas")) {
+		rc = cam_debug_parse_cpas_settings(setting, value);
+		if (rc)
+			goto error;
+	} else {
+		CAM_ERR(CAM_UTIL, "Unsupported driver in camera debug node");
+		goto error;
+	}
+
+	kfree(local_buf_temp);
+	return count;
+
+error:
+	kfree(local_buf_temp);
+	return -EPERM;
+}
 
 const char *cam_get_module_name(unsigned int module_id)
 {

+ 41 - 0
drivers/cam_utils/cam_debug_util.h

@@ -6,6 +6,8 @@
 #ifndef _CAM_DEBUG_UTIL_H_
 #define _CAM_DEBUG_UTIL_H_
 
+#include <linux/platform_device.h>
+
 #define CAM_CDM        (1 << 0)
 #define CAM_CORE       (1 << 1)
 #define CAM_CPAS       (1 << 2)
@@ -44,6 +46,32 @@
 
 #define STR_BUFFER_MAX_LENGTH  1024
 
+/**
+ * struct cam_cpas_debug_settings - Sysfs debug settings for cpas driver
+ */
+struct cam_cpas_debug_settings {
+	uint64_t mnoc_hf_0_ab_bw;
+	uint64_t mnoc_hf_0_ib_bw;
+	uint64_t mnoc_hf_1_ab_bw;
+	uint64_t mnoc_hf_1_ib_bw;
+	uint64_t mnoc_sf_0_ab_bw;
+	uint64_t mnoc_sf_0_ib_bw;
+	uint64_t mnoc_sf_1_ab_bw;
+	uint64_t mnoc_sf_1_ib_bw;
+	uint64_t mnoc_sf_icp_ab_bw;
+	uint64_t mnoc_sf_icp_ib_bw;
+	uint64_t camnoc_bw;
+};
+
+/**
+ * struct camera_debug_settings - Sysfs debug settings for camera
+ *
+ * @cpas_settings: Debug settings for cpas driver.
+ */
+struct camera_debug_settings {
+	struct cam_cpas_debug_settings cpas_settings;
+};
+
 /*
  *  cam_debug_log()
  *
@@ -211,4 +239,17 @@ const char *cam_get_module_name(unsigned int module_id);
 				__LINE__, ##args);                         \
 	})
 
+/**
+ * @brief : API to get camera debug settings
+ * @return const struct camera_debug_settings pointer.
+ */
+const struct camera_debug_settings *cam_debug_get_settings(void);
+
+/**
+ * @brief : API to parse and store input from sysfs debug node
+ * @return Number of bytes read from buffer on success, or -EPERM on error.
+ */
+ssize_t cam_debug_sysfs_node_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count);
+
 #endif /* _CAM_DEBUG_UTIL_H_ */