lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 17 Feb 2021 12:18:25 +0530
From:   Souradeep Chowdhury <schowdhu@...eaurora.org>
To:     Andy Gross <agross@...nel.org>,
        Bjorn Andersson <bjorn.andersson@...aro.org>,
        Rob Herring <robh+dt@...nel.org>
Cc:     linux-arm-kernel@...ts.infradead.org, linux-kernel@...r.kernel.org,
        linux-arm-msm@...r.kernel.org, devicetree@...r.kernel.org,
        Rajendra Nayak <rnayak@...eaurora.org>,
        Sibi Sankar <sibis@...eaurora.org>,
        Sai Prakash Ranjan <saiprakash.ranjan@...eaurora.org>,
        Souradeep Chowdhury <schowdhu@...eaurora.org>
Subject: [PATCH V0 4/6] soc: qcom: dcc:Add the sysfs variables to the Data Capture and Compare driver(DCC)

Added the sysfs variables to expose the user space functionalities
like DCC enable,disable,configure addresses and software triggers.
Also added the necessary methods along with the same.

Signed-off-by: Souradeep Chowdhury <schowdhu@...eaurora.org>
---
 drivers/soc/qcom/dcc.c | 519 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 519 insertions(+)

diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c
index d67452b..02eee96 100644
--- a/drivers/soc/qcom/dcc.c
+++ b/drivers/soc/qcom/dcc.c
@@ -185,6 +185,82 @@ static int dcc_sram_writel(struct dcc_drvdata *drvdata,
 	return 0;
 }
 
+static bool dcc_ready(struct dcc_drvdata *drvdata)
+{
+	u32 val;
+
+	/* poll until DCC ready */
+	if (!readl_poll_timeout((drvdata->base + DCC_STATUS), val,
+				(BMVAL(val, 0, 1) == 0), 1, TIMEOUT_US))
+		return true;
+
+	return false;
+}
+
+static int dcc_read_status(struct dcc_drvdata *drvdata)
+{
+	int curr_list;
+	u32 bus_status;
+	u32 ll_cfg = 0;
+	u32 tmp_ll_cfg = 0;
+
+	for (curr_list = 0; curr_list < drvdata->nr_link_list; curr_list++) {
+		if (!drvdata->enable[curr_list])
+			continue;
+
+		bus_status = dcc_readl(drvdata, DCC_LL_BUS_ACCESS_STATUS(curr_list));
+
+		if (bus_status) {
+			dev_err(drvdata->dev,
+				"Read access error for list %d err: 0x%x.\n",
+				curr_list, bus_status);
+
+			ll_cfg = dcc_readl(drvdata, DCC_LL_CFG(curr_list));
+			tmp_ll_cfg = ll_cfg & ~BIT(9);
+			dcc_writel(drvdata, tmp_ll_cfg, DCC_LL_CFG(curr_list));
+			dcc_writel(drvdata, 0x3,
+				DCC_LL_BUS_ACCESS_STATUS(curr_list));
+			dcc_writel(drvdata, ll_cfg, DCC_LL_CFG(curr_list));
+			return -ENODATA;
+		}
+	}
+
+	return 0;
+}
+
+static int dcc_sw_trigger(struct dcc_drvdata *drvdata)
+{
+	int ret = 0;
+	int curr_list;
+	u32 ll_cfg = 0;
+	u32 tmp_ll_cfg = 0;
+
+	mutex_lock(&drvdata->mutex);
+
+	for (curr_list = 0; curr_list < drvdata->nr_link_list; curr_list++) {
+		if (!drvdata->enable[curr_list])
+			continue;
+		ll_cfg = dcc_readl(drvdata, DCC_LL_CFG(curr_list));
+		tmp_ll_cfg = ll_cfg & ~BIT(9);
+		dcc_writel(drvdata, tmp_ll_cfg, DCC_LL_CFG(curr_list));
+		dcc_writel(drvdata, 1, DCC_LL_SW_TRIGGER(curr_list));
+		dcc_writel(drvdata, ll_cfg, DCC_LL_CFG(curr_list));
+	}
+
+	if (!dcc_ready(drvdata)) {
+		dev_err(drvdata->dev,
+			"DCC is busy after receiving sw tigger.\n");
+		ret = -EBUSY;
+		goto err;
+	}
+
+	ret = dcc_read_status(drvdata);
+
+err:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+
 static int _dcc_ll_cfg_read_write(struct dcc_drvdata *drvdata,
 struct dcc_config_entry *entry, struct dcc_cfg_attr *cfg)
 {
@@ -628,6 +704,211 @@ static int dcc_enable(struct dcc_drvdata *drvdata)
 	return ret;
 }
 
+static void dcc_disable(struct dcc_drvdata *drvdata)
+{
+	int curr_list;
+
+	mutex_lock(&drvdata->mutex);
+
+	if (!dcc_ready(drvdata))
+		dev_err(drvdata->dev, "DCC is not ready Disabling DCC...\n");
+
+	for (curr_list = 0; curr_list < drvdata->nr_link_list; curr_list++) {
+		if (!drvdata->enable[curr_list])
+			continue;
+		dcc_writel(drvdata, 0, DCC_LL_CFG(curr_list));
+		dcc_writel(drvdata, 0, DCC_LL_BASE(curr_list));
+		dcc_writel(drvdata, 0, DCC_FD_BASE(curr_list));
+		dcc_writel(drvdata, 0, DCC_LL_LOCK(curr_list));
+		drvdata->enable[curr_list] = false;
+	}
+	memset_io(drvdata->ram_base, 0, drvdata->ram_size);
+	drvdata->ram_cfg = 0;
+	drvdata->ram_start = 0;
+	mutex_unlock(&drvdata->mutex);
+}
+
+static ssize_t curr_list_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	int ret;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	mutex_lock(&drvdata->mutex);
+	if (drvdata->curr_list == DCC_INVALID_LINK_LIST) {
+		dev_err(dev, "curr_list is not set.\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = scnprintf(buf, PAGE_SIZE, "%d\n",	drvdata->curr_list);
+err:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+
+static ssize_t curr_list_store(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t size)
+{
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+	unsigned long val;
+	u32 lock_reg;
+	bool dcc_enable = false;
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	if (val >= drvdata->nr_link_list)
+		return -EINVAL;
+
+	mutex_lock(&drvdata->mutex);
+
+	dcc_enable = is_dcc_enabled(drvdata);
+	if (drvdata->curr_list != DCC_INVALID_LINK_LIST	&& dcc_enable) {
+		dev_err(drvdata->dev, "DCC is enabled, please disable it first.\n");
+		mutex_unlock(&drvdata->mutex);
+		return -EINVAL;
+	}
+
+	lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(val));
+	if (lock_reg & 0x1) {
+		dev_err(drvdata->dev, "DCC linked list is already configured\n");
+		mutex_unlock(&drvdata->mutex);
+		return -EINVAL;
+	}
+	drvdata->curr_list = val;
+	mutex_unlock(&drvdata->mutex);
+
+	return size;
+}
+
+static DEVICE_ATTR_RW(curr_list);
+
+
+static ssize_t trigger_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
+{
+	int ret = 0;
+	unsigned long val;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+	if (val != 1)
+		return -EINVAL;
+
+	ret = dcc_sw_trigger(drvdata);
+	if (!ret)
+		ret = size;
+
+	return ret;
+}
+static DEVICE_ATTR_WO(trigger);
+
+static ssize_t enable_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	int ret;
+	bool dcc_enable = false;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	mutex_lock(&drvdata->mutex);
+	if (drvdata->curr_list >= drvdata->nr_link_list) {
+		dev_err(dev, "Select link list to program using curr_list\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	dcc_enable = is_dcc_enabled(drvdata);
+
+	ret = scnprintf(buf, PAGE_SIZE, "%u\n",
+				(unsigned int)dcc_enable);
+err:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+
+static ssize_t enable_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	int ret = 0;
+	unsigned long val;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	if (val)
+		ret = dcc_enable(drvdata);
+	else
+		dcc_disable(drvdata);
+
+	if (!ret)
+		ret = size;
+
+	return ret;
+
+}
+
+static DEVICE_ATTR_RW(enable);
+
+static ssize_t config_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+	struct dcc_config_entry *entry;
+	char local_buf[64];
+	int len = 0, count = 0;
+
+	buf[0] = '\0';
+
+	mutex_lock(&drvdata->mutex);
+	if (drvdata->curr_list >= drvdata->nr_link_list) {
+		dev_err(dev, "Select link list to program using curr_list\n");
+		count = -EINVAL;
+		goto err;
+	}
+
+	list_for_each_entry(entry,
+	&drvdata->cfg_head[drvdata->curr_list], list) {
+		switch (entry->desc_type) {
+		case DCC_READ_WRITE_TYPE:
+			len = snprintf(local_buf, 64, "Index: 0x%x, mask: 0x%x, val: 0x%x\n",
+				entry->index, entry->mask, entry->write_val);
+			break;
+		case DCC_LOOP_TYPE:
+			len = snprintf(local_buf, 64, "Index: 0x%x, Loop: %d\n",
+				entry->index, entry->loop_cnt);
+			break;
+		case DCC_WRITE_TYPE:
+			len = snprintf(local_buf, 64,
+				"Write Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x APB: %d\n",
+				entry->index, entry->base, entry->offset, entry->len,
+				entry->apb_bus);
+			break;
+		default:
+			len = snprintf(local_buf, 64,
+				"Read Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x APB: %d\n",
+				entry->index, entry->base, entry->offset,
+				entry->len, entry->apb_bus);
+		}
+
+		if ((count + len) > PAGE_SIZE) {
+			dev_err(dev, "DCC: Couldn't write complete config\n");
+			break;
+		}
+		strlcat(buf, local_buf, PAGE_SIZE);
+		count += len;
+	}
+
+err:
+	mutex_unlock(&drvdata->mutex);
+	return count;
+}
+
 static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr,
 				unsigned int len, int apb_bus)
 {
@@ -709,6 +990,38 @@ static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr,
 	return ret;
 }
 
+static ssize_t config_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	int ret, len, apb_bus;
+	unsigned int base;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+	int nval;
+
+	nval = sscanf(buf, "%x %i %d", &base, &len, &apb_bus);
+	if (nval <= 0 || nval > 3)
+		return -EINVAL;
+
+	if (nval == 1) {
+		len = 1;
+		apb_bus = 0;
+	} else if (nval == 2) {
+		apb_bus = 0;
+	} else {
+		apb_bus = 1;
+	}
+
+	ret = dcc_config_add(drvdata, base, len, apb_bus);
+	if (ret)
+		return ret;
+
+	return size;
+
+}
+
+static DEVICE_ATTR_RW(config);
+
 static void dcc_config_reset(struct dcc_drvdata *drvdata)
 {
 	struct dcc_config_entry *entry, *temp;
@@ -730,6 +1043,80 @@ static void dcc_config_reset(struct dcc_drvdata *drvdata)
 	mutex_unlock(&drvdata->mutex);
 }
 
+static ssize_t config_reset_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t size)
+{
+	unsigned long val;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	if (val)
+		dcc_config_reset(drvdata);
+
+	return size;
+}
+
+static DEVICE_ATTR_WO(config_reset);
+
+static ssize_t ready_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	int ret;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	mutex_lock(&drvdata->mutex);
+
+	if (drvdata->curr_list >= drvdata->nr_link_list) {
+		dev_err(dev, "Select link list to program using curr_list\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (!drvdata->enable[drvdata->curr_list]) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = scnprintf(buf, PAGE_SIZE, "%u\n",
+			(unsigned int)BVAL(dcc_readl(drvdata, DCC_STATUS), 1));
+err:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+
+static DEVICE_ATTR_RO(ready);
+
+static ssize_t interrupt_disable_show(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n",
+				(unsigned int)drvdata->interrupt_disable);
+}
+
+static ssize_t interrupt_disable_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t size)
+{
+	unsigned long val;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	mutex_lock(&drvdata->mutex);
+	drvdata->interrupt_disable = (val ? 1:0);
+	mutex_unlock(&drvdata->mutex);
+	return size;
+}
+
+static DEVICE_ATTR_RW(interrupt_disable);
+
 static int dcc_add_loop(struct dcc_drvdata *drvdata, unsigned long loop_cnt)
 {
 	struct dcc_config_entry *entry;
@@ -747,6 +1134,40 @@ static int dcc_add_loop(struct dcc_drvdata *drvdata, unsigned long loop_cnt)
 	return 0;
 }
 
+static ssize_t loop_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t size)
+{
+	int ret;
+	unsigned long loop_cnt;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	mutex_lock(&drvdata->mutex);
+
+	if (kstrtoul(buf, 16, &loop_cnt)) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (drvdata->curr_list >= drvdata->nr_link_list) {
+		dev_err(dev, "Select link list to program using curr_list\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = dcc_add_loop(drvdata, loop_cnt);
+	if (ret)
+		goto err;
+
+	mutex_unlock(&drvdata->mutex);
+	return size;
+err:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+
+static DEVICE_ATTR_WO(loop);
+
 static int dcc_rd_mod_wr_add(struct dcc_drvdata *drvdata, unsigned int mask,
 				unsigned int val)
 {
@@ -784,6 +1205,30 @@ static int dcc_rd_mod_wr_add(struct dcc_drvdata *drvdata, unsigned int mask,
 	return ret;
 }
 
+static ssize_t rd_mod_wr_store(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t size)
+{
+	int ret;
+	int nval;
+	unsigned int mask, val;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	nval = sscanf(buf, "%x %x", &mask, &val);
+
+	if (nval <= 1 || nval > 2)
+		return -EINVAL;
+
+	ret = dcc_rd_mod_wr_add(drvdata, mask, val);
+	if (ret)
+		return ret;
+
+	return size;
+
+}
+
+static DEVICE_ATTR_WO(rd_mod_wr);
+
 static int dcc_add_write(struct dcc_drvdata *drvdata, unsigned int addr,
 				unsigned int write_val, int apb_bus)
 {
@@ -806,6 +1251,77 @@ static int dcc_add_write(struct dcc_drvdata *drvdata, unsigned int addr,
 	return 0;
 }
 
+static ssize_t config_write_store(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t size)
+{
+	int ret;
+	int nval;
+	unsigned int addr, write_val;
+	int apb_bus = 0;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+	mutex_lock(&drvdata->mutex);
+
+	nval = sscanf(buf, "%x %x %d", &addr, &write_val, &apb_bus);
+
+	if (nval <= 1 || nval > 3) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (drvdata->curr_list >= drvdata->nr_link_list) {
+		dev_err(dev, "Select link list to program using curr_list\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (nval == 3 && apb_bus != 0)
+		apb_bus = 1;
+
+	ret = dcc_add_write(drvdata, addr, write_val, apb_bus);
+	if (ret)
+		goto err;
+
+	mutex_unlock(&drvdata->mutex);
+	return size;
+err:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+
+static DEVICE_ATTR_WO(config_write);
+
+static const struct device_attribute *dcc_attrs[] = {
+	&dev_attr_trigger,
+	&dev_attr_enable,
+	&dev_attr_config,
+	&dev_attr_config_reset,
+	&dev_attr_ready,
+	&dev_attr_interrupt_disable,
+	&dev_attr_loop,
+	&dev_attr_rd_mod_wr,
+	&dev_attr_curr_list,
+	&dev_attr_config_write,
+	NULL,
+};
+
+static int dcc_create_files(struct device *dev,
+					const struct device_attribute **attrs)
+{
+	int ret = 0, i;
+
+	for (i = 0; attrs[i] != NULL; i++) {
+		ret = device_create_file(dev, attrs[i]);
+		if (ret) {
+			dev_err(dev, "DCC: Couldn't create sysfs attribute: %s\n",
+				attrs[i]->attr.name);
+			break;
+		}
+	}
+	return ret;
+}
+
 static int dcc_sram_open(struct inode *inode, struct file *file)
 {
 	struct dcc_drvdata *drvdata = container_of(inode->i_cdev,
@@ -1018,6 +1534,9 @@ static int dcc_probe(struct platform_device *pdev)
 	ret = dcc_sram_dev_init(drvdata);
 	if (ret)
 		goto err;
+	ret = dcc_create_files(dev, dcc_attrs);
+	if (ret)
+		goto err;
 
 	return ret;
 err:
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ