Linux userland API discussions
 help / color / mirror / Atom feed
* [PATCH v2 06/11] coresight-etm4x: Controls pertaining to the address comparator functions
From: Mathieu Poirier @ 2015-04-29 17:16 UTC (permalink / raw)
  To: gregkh
  Cc: linux-arm-kernel, linux-api, linux-kernel, kaixu.xia,
	zhang.chunyan, mathieu.poirier
In-Reply-To: <1430327795-10710-1-git-send-email-mathieu.poirier@linaro.org>

From: Pratik Patel <pratikp@codeaurora.org>

Adding sysfs entries to control the various mode the address comparator
registers can enact, i.e, start/top, single, and range.  Also supplementing
with address comparator types configuration registers access, mandatory
to complete the configuration of the comparator functions.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 .../ABI/testing/sysfs-bus-coresight-devices-etm4x  |  25 ++
 drivers/hwtracing/coresight/coresight-etm4x.c      | 423 +++++++++++++++++++++
 2 files changed, 448 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
index d7409c3d58e6..8cdc4ad10bd6 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
@@ -166,3 +166,28 @@ KernelVersion:	4.01
 Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
 Description: 	(RW) In non-secure state, each bit controls whether instruction
 		tracing is enabled for the corresponding exception level.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/addr_idx
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Select which address comparator or pair (of comparators) to
+		work with.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/addr_instdatatype
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Controls what type of comparison the trace unit performs.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/addr_single
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Used to setup single address comparator values.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/addr_range
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Used to setup address range comparator values.
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 9f2a13dd1280..47cc68b8cc43 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -1027,6 +1027,421 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(ns_exlevel_vinst);
 
+static ssize_t addr_idx_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->addr_idx;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t addr_idx_store(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+	if (val >= drvdata->nr_addr_cmp * 2)
+		return -EINVAL;
+
+	/*
+	 * Use spinlock to ensure index doesn't change while it gets
+	 * dereferenced multiple times within a spinlock block elsewhere.
+	 */
+	spin_lock(&drvdata->spinlock);
+	drvdata->addr_idx = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(addr_idx);
+
+static ssize_t addr_instdatatype_show(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	ssize_t len;
+	u8 val, idx;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	val = BMVAL(drvdata->addr_acc[idx], 0, 1);
+	len = scnprintf(buf, PAGE_SIZE, "%s\n",
+			val == ETM_INSTR_ADDR ? "instr" :
+			(val == ETM_DATA_LOAD_ADDR ? "data_load" :
+			(val == ETM_DATA_STORE_ADDR ? "data_store" :
+			"data_load_store")));
+	spin_unlock(&drvdata->spinlock);
+	return len;
+}
+
+static ssize_t addr_instdatatype_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t size)
+{
+	u8 idx;
+	char str[20] = "";
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (strlen(buf) >= 20)
+		return -EINVAL;
+	if (sscanf(buf, "%s", str) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!strcmp(str, "instr"))
+		/* TYPE, bits[1:0] */
+		drvdata->addr_acc[idx] &= ~(BIT(0) | BIT(1));
+
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(addr_instdatatype);
+
+static ssize_t addr_single_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	u8 idx;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	idx = drvdata->addr_idx;
+	spin_lock(&drvdata->spinlock);
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+	val = (unsigned long)drvdata->addr_val[idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t addr_single_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t size)
+{
+	u8 idx;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	drvdata->addr_val[idx] = (u64)val;
+	drvdata->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(addr_single);
+
+static ssize_t addr_range_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	u8 idx;
+	unsigned long val1, val2;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (idx % 2 != 0) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+	if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+	      (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	val1 = (unsigned long)drvdata->addr_val[idx];
+	val2 = (unsigned long)drvdata->addr_val[idx + 1];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
+}
+
+static ssize_t addr_range_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	u8 idx;
+	unsigned long val1, val2;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+		return -EINVAL;
+	/* lower address comparator cannot have a higher address value */
+	if (val1 > val2)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (idx % 2 != 0) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+	      (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	drvdata->addr_val[idx] = (u64)val1;
+	drvdata->addr_type[idx] = ETM_ADDR_TYPE_RANGE;
+	drvdata->addr_val[idx + 1] = (u64)val2;
+	drvdata->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
+	/*
+	 * Program include or exclude control bits for vinst or vdata
+	 * whenever we change addr comparators to ETM_ADDR_TYPE_RANGE
+	 */
+	if (drvdata->mode & ETM_MODE_EXCLUDE)
+		etm4_set_mode_exclude(drvdata, true);
+	else
+		etm4_set_mode_exclude(drvdata, false);
+
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(addr_range);
+
+static ssize_t addr_start_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	u8 idx;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	val = (unsigned long)drvdata->addr_val[idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t addr_start_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	u8 idx;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!drvdata->nr_addr_cmp) {
+		spin_unlock(&drvdata->spinlock);
+		return -EINVAL;
+	}
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	drvdata->addr_val[idx] = (u64)val;
+	drvdata->addr_type[idx] = ETM_ADDR_TYPE_START;
+	drvdata->vissctlr |= BIT(idx);
+	/* SSSTATUS, bit[9] - turn on start/stop logic */
+	drvdata->vinst_ctrl |= BIT(9);
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(addr_start);
+
+static ssize_t addr_stop_show(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	u8 idx;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	val = (unsigned long)drvdata->addr_val[idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t addr_stop_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t size)
+{
+	u8 idx;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!drvdata->nr_addr_cmp) {
+		spin_unlock(&drvdata->spinlock);
+		return -EINVAL;
+	}
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	       drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	drvdata->addr_val[idx] = (u64)val;
+	drvdata->addr_type[idx] = ETM_ADDR_TYPE_STOP;
+	drvdata->vissctlr |= BIT(idx + 16);
+	/* SSSTATUS, bit[9] - turn on start/stop logic */
+	drvdata->vinst_ctrl |= BIT(9);
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(addr_stop);
+
+static ssize_t addr_ctxtype_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	ssize_t len;
+	u8 idx, val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	/* CONTEXTTYPE, bits[3:2] */
+	val = BMVAL(drvdata->addr_acc[idx], 2, 3);
+	len = scnprintf(buf, PAGE_SIZE, "%s\n", val == ETM_CTX_NONE ? "none" :
+			(val == ETM_CTX_CTXID ? "ctxid" :
+			(val == ETM_CTX_VMID ? "vmid" : "all")));
+	spin_unlock(&drvdata->spinlock);
+	return len;
+}
+
+static ssize_t addr_ctxtype_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t size)
+{
+	u8 idx;
+	char str[10] = "";
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (strlen(buf) >= 10)
+		return -EINVAL;
+	if (sscanf(buf, "%s", str) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!strcmp(str, "none"))
+		/* start by clearing context type bits */
+		drvdata->addr_acc[idx] &= ~(BIT(2) | BIT(3));
+	else if (!strcmp(str, "ctxid")) {
+		/* 0b01 The trace unit performs a Context ID */
+		if (drvdata->numcidc) {
+			drvdata->addr_acc[idx] |= BIT(2);
+			drvdata->addr_acc[idx] &= ~BIT(3);
+		}
+	} else if (!strcmp(str, "vmid")) {
+		/* 0b10 The trace unit performs a VMID */
+		if (drvdata->numvmidc) {
+			drvdata->addr_acc[idx] &= ~BIT(2);
+			drvdata->addr_acc[idx] |= BIT(3);
+		}
+	} else if (!strcmp(str, "all")) {
+		/*
+		 * 0b11 The trace unit performs a Context ID
+		 * comparison and a VMID
+		 */
+		if (drvdata->numcidc)
+			drvdata->addr_acc[idx] |= BIT(2);
+		if (drvdata->numvmidc)
+			drvdata->addr_acc[idx] |= BIT(3);
+	}
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(addr_ctxtype);
+
+static ssize_t addr_context_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	u8 idx;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	/* context ID comparator bits[6:4] */
+	val = BMVAL(drvdata->addr_acc[idx], 4, 6);
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t addr_context_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t size)
+{
+	u8 idx;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+	if ((drvdata->numcidc <= 1) && (drvdata->numvmidc <= 1))
+		return -EINVAL;
+	if (val >=  (drvdata->numcidc >= drvdata->numvmidc ?
+		     drvdata->numcidc : drvdata->numvmidc))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	/* clear context ID comparator bits[6:4] */
+	drvdata->addr_acc[idx] &= ~(BIT(4) | BIT(5) | BIT(6));
+	drvdata->addr_acc[idx] |= (val << 4);
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(addr_context);
+
 static ssize_t status_show(struct device *dev,
 			   struct device_attribute *attr, char *buf)
 {
@@ -1191,6 +1606,14 @@ static struct attribute *coresight_etmv4_attrs[] = {
 	&dev_attr_event_vinst.attr,
 	&dev_attr_s_exlevel_vinst.attr,
 	&dev_attr_ns_exlevel_vinst.attr,
+	&dev_attr_addr_idx.attr,
+	&dev_attr_addr_instdatatype.attr,
+	&dev_attr_addr_single.attr,
+	&dev_attr_addr_range.attr,
+	&dev_attr_addr_start.attr,
+	&dev_attr_addr_stop.attr,
+	&dev_attr_addr_ctxtype.attr,
+	&dev_attr_addr_context.attr,
 	&dev_attr_status.attr,
 	&dev_attr_mgmt.attr,
 	&dev_attr_trcidr.attr,
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 05/11] coresight-etm4x: Controls pertaining to the ViewInst register
From: Mathieu Poirier @ 2015-04-29 17:16 UTC (permalink / raw)
  To: gregkh
  Cc: mathieu.poirier, linux-api, linux-kernel, zhang.chunyan,
	linux-arm-kernel, kaixu.xia
In-Reply-To: <1430327795-10710-1-git-send-email-mathieu.poirier@linaro.org>

From: Pratik Patel <pratikp@codeaurora.org>

Adding sysfs entries to control the ViewInst register's event
selector along with secure and non-secure exception level
instruction tracing.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 .../ABI/testing/sysfs-bus-coresight-devices-etm4x  | 20 +++++
 drivers/hwtracing/coresight/coresight-etm4x.c      | 98 ++++++++++++++++++++++
 2 files changed, 118 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
index 2aeae2976c10..d7409c3d58e6 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
@@ -146,3 +146,23 @@ KernelVersion:	4.01
 Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
 Description: 	(RW) Controls which regions in the memory map are enabled to
 		use branch broadcasting.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/event_vinst
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Controls instruction trace filtering.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/s_exlevel_vinst
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) In Secure state, each bit controls whether instruction
+		tracing is enabled for the corresponding exception level.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/ns_exlevel_vinst
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) In non-secure state, each bit controls whether instruction
+		tracing is enabled for the corresponding exception level.
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index f69e4652a357..9f2a13dd1280 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -932,6 +932,101 @@ static ssize_t bb_ctrl_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(bb_ctrl);
 
+static ssize_t event_vinst_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->vinst_ctrl & ETMv4_EVENT_MASK;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t event_vinst_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	val &= ETMv4_EVENT_MASK;
+	drvdata->vinst_ctrl &= ~ETMv4_EVENT_MASK;
+	drvdata->vinst_ctrl |= val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(event_vinst);
+
+static ssize_t s_exlevel_vinst_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = BMVAL(drvdata->vinst_ctrl, 16, 19);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t s_exlevel_vinst_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	/* clear all EXLEVEL_S bits (bit[18] is never implemented) */
+	drvdata->vinst_ctrl &= ~(BIT(16) | BIT(17) | BIT(19));
+	/* enable instruction tracing for corresponding exception level */
+	val &= drvdata->s_ex_level;
+	drvdata->vinst_ctrl |= (val << 16);
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(s_exlevel_vinst);
+
+static ssize_t ns_exlevel_vinst_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	/* EXLEVEL_NS, bits[23:20] */
+	val = BMVAL(drvdata->vinst_ctrl, 20, 23);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t ns_exlevel_vinst_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	/* clear EXLEVEL_NS bits (bit[23] is never implemented */
+	drvdata->vinst_ctrl &= ~(BIT(20) | BIT(21) | BIT(22));
+	/* enable instruction tracing for corresponding exception level */
+	val &= drvdata->ns_ex_level;
+	drvdata->vinst_ctrl |= (val << 20);
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(ns_exlevel_vinst);
+
 static ssize_t status_show(struct device *dev,
 			   struct device_attribute *attr, char *buf)
 {
@@ -1093,6 +1188,9 @@ static struct attribute *coresight_etmv4_attrs[] = {
 	&dev_attr_syncfreq.attr,
 	&dev_attr_cyc_threshold.attr,
 	&dev_attr_bb_ctrl.attr,
+	&dev_attr_event_vinst.attr,
+	&dev_attr_s_exlevel_vinst.attr,
+	&dev_attr_ns_exlevel_vinst.attr,
 	&dev_attr_status.attr,
 	&dev_attr_mgmt.attr,
 	&dev_attr_trcidr.attr,
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 04/11] coresight-etm4x: Controls pertaining to various configuration options
From: Mathieu Poirier @ 2015-04-29 17:16 UTC (permalink / raw)
  To: gregkh
  Cc: mathieu.poirier, linux-api, linux-kernel, zhang.chunyan,
	linux-arm-kernel, kaixu.xia
In-Reply-To: <1430327795-10710-1-git-send-email-mathieu.poirier@linaro.org>

From: Pratik Patel <pratikp@codeaurora.org>

Adding sysfs entries to configure:
. global timestamp.
. how often trace synchronisation occur.
. the threashold value for cycle counting.
. branch and broadcasting regions.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 .../ABI/testing/sysfs-bus-coresight-devices-etm4x  |  28 ++++-
 drivers/hwtracing/coresight/coresight-etm4x.c      | 124 +++++++++++++++++++++
 2 files changed, 151 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
index 9caf70382088..2aeae2976c10 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
@@ -119,4 +119,30 @@ What:		/sys/bus/coresight/devices/<memory_map>.etm/event_instren
 Date:		April 2015
 KernelVersion:	4.01
 Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
-Description: 	(RW) Controls the behavior of the events in bank 0 to 3.
+Description: 	(RW) Controls the behavior of the events in bank 0 to 3
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/event_ts
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Controls the insertion of global timestamps in the trace
+		streams.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/syncfreq
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Controls how often trace synchronization requests occur.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/cyc_threshold
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Sets the threshold value for cycle counting.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/bb_ctrl
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Controls which regions in the memory map are enabled to
+		use branch broadcasting.
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 4d58b41bb27c..f69e4652a357 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -812,6 +812,126 @@ static ssize_t event_instren_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(event_instren);
 
+static ssize_t event_ts_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->ts_ctrl;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t event_ts_store(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+	if (!drvdata->ts_size)
+		return -EINVAL;
+
+	drvdata->ts_ctrl = val & ETMv4_EVENT_MASK;
+	return size;
+}
+static DEVICE_ATTR_RW(event_ts);
+
+static ssize_t syncfreq_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->syncfreq;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t syncfreq_store(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+	if (drvdata->syncpr == true)
+		return -EINVAL;
+
+	drvdata->syncfreq = val & ETMv4_SYNC_MASK;
+	return size;
+}
+static DEVICE_ATTR_RW(syncfreq);
+
+static ssize_t cyc_threshold_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->ccctlr;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t cyc_threshold_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+	if (val < drvdata->ccitmin)
+		return -EINVAL;
+
+	drvdata->ccctlr = val & ETM_CYC_THRESHOLD_MASK;
+	return size;
+}
+static DEVICE_ATTR_RW(cyc_threshold);
+
+static ssize_t bb_ctrl_show(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->bb_ctrl;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t bb_ctrl_store(struct device *dev,
+			     struct device_attribute *attr,
+			     const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+	if (drvdata->trcbb == false)
+		return -EINVAL;
+	if (!drvdata->nr_addr_cmp)
+		return -EINVAL;
+	/*
+	 * Bit[7:0] selects which address range comparator is used for
+	 * branch broadcast control.
+	 */
+	if (BMVAL(val, 0, 7) > drvdata->nr_addr_cmp)
+		return -EINVAL;
+
+	drvdata->bb_ctrl = val;
+	return size;
+}
+static DEVICE_ATTR_RW(bb_ctrl);
+
 static ssize_t status_show(struct device *dev,
 			   struct device_attribute *attr, char *buf)
 {
@@ -969,6 +1089,10 @@ static struct attribute *coresight_etmv4_attrs[] = {
 	&dev_attr_pe.attr,
 	&dev_attr_event.attr,
 	&dev_attr_event_instren.attr,
+	&dev_attr_event_ts.attr,
+	&dev_attr_syncfreq.attr,
+	&dev_attr_cyc_threshold.attr,
+	&dev_attr_bb_ctrl.attr,
 	&dev_attr_status.attr,
 	&dev_attr_mgmt.attr,
 	&dev_attr_trcidr.attr,
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 03/11] coresight-etm4x: Controls pertaining to the reset, mode, pe and events
From: Mathieu Poirier @ 2015-04-29 17:16 UTC (permalink / raw)
  To: gregkh
  Cc: linux-arm-kernel, linux-api, linux-kernel, kaixu.xia,
	zhang.chunyan, mathieu.poirier
In-Reply-To: <1430327795-10710-1-git-send-email-mathieu.poirier@linaro.org>

From: Pratik Patel <pratikp@codeaurora.org>

Adding sysfs entries to:
. set the tracing entity with default values.
. set various mode associated to the tracing entity.
. select the processing entity the tracing entity relates to.
. select various events of interest.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 .../ABI/testing/sysfs-bus-coresight-devices-etm4x  |  33 ++
 drivers/hwtracing/coresight/coresight-etm4x.c      | 442 ++++++++++++++++++++-
 2 files changed, 474 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
index 0f579eb24631..9caf70382088 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
@@ -87,3 +87,36 @@ KernelVersion:	4.01
 Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:	(R) Indicates the number of single-shot comparator controls that
 		are available for tracing.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/reset
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(W) Cancels all configuration on a trace unit and set it back
+		to its boot configuration.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/mode
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Controls various modes supported by this ETM, for example
+		P0 instruction tracing, branch broadcast, cycle counting and
+		context ID tracing.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/pe
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Controls which PE to trace.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/event
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Controls the tracing of arbitrary events from bank 0 to 3.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/event_instren
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: 	(RW) Controls the behavior of the events in bank 0 to 3.
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index babf9bb27d25..4d58b41bb27c 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -268,6 +268,46 @@ static const struct coresight_ops etm4_cs_ops = {
 	.source_ops	= &etm4_source_ops,
 };
 
+static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
+{
+	u8 idx = drvdata->addr_idx;
+
+	/*
+	 * TRCACATRn.TYPE bit[1:0]: type of comparison
+	 * the trace unit performs
+	 */
+	if (BMVAL(drvdata->addr_acc[idx], 0, 1) == ETM_INSTR_ADDR) {
+		if (idx % 2 != 0)
+			return -EINVAL;
+
+		/*
+		 * We are performing instruction address comparison. Set the
+		 * relevant bit of ViewInst Include/Exclude Control register
+		 * for corresponding address comparator pair.
+		 */
+		if (drvdata->addr_type[idx] != ETM_ADDR_TYPE_RANGE ||
+		    drvdata->addr_type[idx + 1] != ETM_ADDR_TYPE_RANGE)
+			return -EINVAL;
+
+		if (exclude == true) {
+			/*
+			 * Set exclude bit and unset the include bit
+			 * corresponding to comparator pair
+			 */
+			drvdata->viiectlr |= BIT(idx / 2 + 16);
+			drvdata->viiectlr &= ~BIT(idx / 2);
+		} else {
+			/*
+			 * Set include bit and unset exclude bit
+			 * corresponding to comparator pair
+			 */
+			drvdata->viiectlr |= BIT(idx / 2);
+			drvdata->viiectlr &= ~BIT(idx / 2 + 16);
+		}
+	}
+	return 0;
+}
+
 static ssize_t nr_pe_cmp_show(struct device *dev,
 			      struct device_attribute *attr,
 			      char *buf)
@@ -376,6 +416,402 @@ static ssize_t nr_ss_cmp_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(nr_ss_cmp);
 
+static ssize_t reset_store(struct device *dev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t size)
+{
+	int i;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	if (val)
+		drvdata->mode = 0x0;
+
+	/* Disable data tracing: do not trace load and store data transfers */
+	drvdata->mode &= ~(ETM_MODE_LOAD | ETM_MODE_STORE);
+	drvdata->cfg &= ~(BIT(1) | BIT(2));
+
+	/* Disable data value and data address tracing */
+	drvdata->mode &= ~(ETM_MODE_DATA_TRACE_ADDR |
+			   ETM_MODE_DATA_TRACE_VAL);
+	drvdata->cfg &= ~(BIT(16) | BIT(17));
+
+	/* Disable all events tracing */
+	drvdata->eventctrl0 = 0x0;
+	drvdata->eventctrl1 = 0x0;
+
+	/* Disable timestamp event */
+	drvdata->ts_ctrl = 0x0;
+
+	/* Disable stalling */
+	drvdata->stall_ctrl = 0x0;
+
+	/* Reset trace synchronization period  to 2^8 = 256 bytes*/
+	if (drvdata->syncpr == false)
+		drvdata->syncfreq = 0x8;
+
+	/*
+	 * Enable ViewInst to trace everything with start-stop logic in
+	 * started state. ARM recommends start-stop logic is set before
+	 * each trace run.
+	 */
+	drvdata->vinst_ctrl |= BIT(0);
+	if (drvdata->nr_addr_cmp == true) {
+		drvdata->mode |= ETM_MODE_VIEWINST_STARTSTOP;
+		/* SSSTATUS, bit[9] */
+		drvdata->vinst_ctrl |= BIT(9);
+	}
+
+	/* No address range filtering for ViewInst */
+	drvdata->viiectlr = 0x0;
+
+	/* No start-stop filtering for ViewInst */
+	drvdata->vissctlr = 0x0;
+
+	/* Disable seq events */
+	for (i = 0; i < drvdata->nrseqstate-1; i++)
+		drvdata->seq_ctrl[i] = 0x0;
+	drvdata->seq_rst = 0x0;
+	drvdata->seq_state = 0x0;
+
+	/* Disable external input events */
+	drvdata->ext_inp = 0x0;
+
+	drvdata->cntr_idx = 0x0;
+	for (i = 0; i < drvdata->nr_cntr; i++) {
+		drvdata->cntrldvr[i] = 0x0;
+		drvdata->cntr_ctrl[i] = 0x0;
+		drvdata->cntr_val[i] = 0x0;
+	}
+
+	drvdata->res_idx = 0x0;
+	for (i = 0; i < drvdata->nr_resource; i++)
+		drvdata->res_ctrl[i] = 0x0;
+
+	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+		drvdata->ss_ctrl[i] = 0x0;
+		drvdata->ss_pe_cmp[i] = 0x0;
+	}
+
+	drvdata->addr_idx = 0x0;
+	for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+		drvdata->addr_val[i] = 0x0;
+		drvdata->addr_acc[i] = 0x0;
+		drvdata->addr_type[i] = ETM_ADDR_TYPE_NONE;
+	}
+
+	drvdata->ctxid_idx = 0x0;
+	for (i = 0; i < drvdata->numcidc; i++)
+		drvdata->ctxid_val[i] = 0x0;
+	drvdata->ctxid_mask0 = 0x0;
+	drvdata->ctxid_mask1 = 0x0;
+
+	drvdata->vmid_idx = 0x0;
+	for (i = 0; i < drvdata->numvmidc; i++)
+		drvdata->vmid_val[i] = 0x0;
+	drvdata->vmid_mask0 = 0x0;
+	drvdata->vmid_mask1 = 0x0;
+
+	drvdata->trcid = drvdata->cpu + 1;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_WO(reset);
+
+static ssize_t mode_show(struct device *dev,
+			 struct device_attribute *attr,
+			 char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->mode;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t mode_store(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf, size_t size)
+{
+	unsigned long val, mode;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->mode = val & ETMv4_MODE_ALL;
+
+	if (drvdata->mode & ETM_MODE_EXCLUDE)
+		etm4_set_mode_exclude(drvdata, true);
+	else
+		etm4_set_mode_exclude(drvdata, false);
+
+	if (drvdata->instrp0 == true) {
+		/* start by clearing instruction P0 field */
+		drvdata->cfg  &= ~(BIT(1) | BIT(2));
+		if (drvdata->mode & ETM_MODE_LOAD)
+			/* 0b01 Trace load instructions as P0 instructions */
+			drvdata->cfg  |= BIT(1);
+		if (drvdata->mode & ETM_MODE_STORE)
+			/* 0b10 Trace store instructions as P0 instructions */
+			drvdata->cfg  |= BIT(2);
+		if (drvdata->mode & ETM_MODE_LOAD_STORE)
+			/*
+			 * 0b11 Trace load and store instructions
+			 * as P0 instructions
+			 */
+			drvdata->cfg  |= BIT(1) | BIT(2);
+	}
+
+	/* bit[3], Branch broadcast mode */
+	if ((drvdata->mode & ETM_MODE_BB) && (drvdata->trcbb == true))
+		drvdata->cfg |= BIT(3);
+	else
+		drvdata->cfg &= ~BIT(3);
+
+	/* bit[4], Cycle counting instruction trace bit */
+	if ((drvdata->mode & ETMv4_MODE_CYCACC) &&
+		(drvdata->trccci == true))
+		drvdata->cfg |= BIT(4);
+	else
+		drvdata->cfg &= ~BIT(4);
+
+	/* bit[6], Context ID tracing bit */
+	if ((drvdata->mode & ETMv4_MODE_CTXID) && (drvdata->ctxid_size))
+		drvdata->cfg |= BIT(6);
+	else
+		drvdata->cfg &= ~BIT(6);
+
+	if ((drvdata->mode & ETM_MODE_VMID) && (drvdata->vmid_size))
+		drvdata->cfg |= BIT(7);
+	else
+		drvdata->cfg &= ~BIT(7);
+
+	/* bits[10:8], Conditional instruction tracing bit */
+	mode = ETM_MODE_COND(drvdata->mode);
+	if (drvdata->trccond == true) {
+		drvdata->cfg &= ~(BIT(8) | BIT(9) | BIT(10));
+		drvdata->cfg |= mode << 8;
+	}
+
+	/* bit[11], Global timestamp tracing bit */
+	if ((drvdata->mode & ETMv4_MODE_TIMESTAMP) && (drvdata->ts_size))
+		drvdata->cfg |= BIT(11);
+	else
+		drvdata->cfg &= ~BIT(11);
+
+	/* bit[12], Return stack enable bit */
+	if ((drvdata->mode & ETM_MODE_RETURNSTACK) &&
+		(drvdata->retstack == true))
+		drvdata->cfg |= BIT(12);
+	else
+		drvdata->cfg &= ~BIT(12);
+
+	/* bits[14:13], Q element enable field */
+	mode = ETM_MODE_QELEM(drvdata->mode);
+	/* start by clearing QE bits */
+	drvdata->cfg &= ~(BIT(13) | BIT(14));
+	/* if supported, Q elements with instruction counts are enabled */
+	if ((mode & BIT(0)) && (drvdata->q_support & BIT(0)))
+		drvdata->cfg |= BIT(13);
+	/*
+	 * if supported, Q elements with and without instruction
+	 * counts are enabled
+	 */
+	if ((mode & BIT(1)) && (drvdata->q_support & BIT(1)))
+		drvdata->cfg |= BIT(14);
+
+	/* bit[11], AMBA Trace Bus (ATB) trigger enable bit */
+	if ((drvdata->mode & ETM_MODE_ATB_TRIGGER) &&
+	    (drvdata->atbtrig == true))
+		drvdata->eventctrl1 |= BIT(11);
+	else
+		drvdata->eventctrl1 &= ~BIT(11);
+
+	/* bit[12], Low-power state behavior override bit */
+	if ((drvdata->mode & ETM_MODE_LPOVERRIDE) &&
+	    (drvdata->lpoverride == true))
+		drvdata->eventctrl1 |= BIT(12);
+	else
+		drvdata->eventctrl1 &= ~BIT(12);
+
+	/* bit[8], Instruction stall bit */
+	if (drvdata->mode & ETM_MODE_ISTALL_EN)
+		drvdata->stall_ctrl |= BIT(8);
+	else
+		drvdata->stall_ctrl &= ~BIT(8);
+
+	/* bit[10], Prioritize instruction trace bit */
+	if (drvdata->mode & ETM_MODE_INSTPRIO)
+		drvdata->stall_ctrl |= BIT(10);
+	else
+		drvdata->stall_ctrl &= ~BIT(10);
+
+	/* bit[13], Trace overflow prevention bit */
+	if ((drvdata->mode & ETM_MODE_NOOVERFLOW) &&
+		(drvdata->nooverflow == true))
+		drvdata->stall_ctrl |= BIT(13);
+	else
+		drvdata->stall_ctrl &= ~BIT(13);
+
+	/* bit[9] Start/stop logic control bit */
+	if (drvdata->mode & ETM_MODE_VIEWINST_STARTSTOP)
+		drvdata->vinst_ctrl |= BIT(9);
+	else
+		drvdata->vinst_ctrl &= ~BIT(9);
+
+	/* bit[10], Whether a trace unit must trace a Reset exception */
+	if (drvdata->mode & ETM_MODE_TRACE_RESET)
+		drvdata->vinst_ctrl |= BIT(10);
+	else
+		drvdata->vinst_ctrl &= ~BIT(10);
+
+	/* bit[11], Whether a trace unit must trace a system error exception */
+	if ((drvdata->mode & ETM_MODE_TRACE_ERR) &&
+		(drvdata->trc_error == true))
+		drvdata->vinst_ctrl |= BIT(11);
+	else
+		drvdata->vinst_ctrl &= ~BIT(11);
+
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(mode);
+
+static ssize_t pe_show(struct device *dev,
+		       struct device_attribute *attr,
+		       char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->pe_sel;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t pe_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	if (val > drvdata->nr_pe) {
+		spin_unlock(&drvdata->spinlock);
+		return -EINVAL;
+	}
+
+	drvdata->pe_sel = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(pe);
+
+static ssize_t event_show(struct device *dev,
+			  struct device_attribute *attr,
+			  char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->eventctrl0;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t event_store(struct device *dev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	switch (drvdata->nr_event) {
+	case 0x0:
+		/* EVENT0, bits[7:0] */
+		drvdata->eventctrl0 = val & 0xFF;
+		break;
+	case 0x1:
+		 /* EVENT1, bits[15:8] */
+		drvdata->eventctrl0 = val & 0xFFFF;
+		break;
+	case 0x2:
+		/* EVENT2, bits[23:16] */
+		drvdata->eventctrl0 = val & 0xFFFFFF;
+		break;
+	case 0x3:
+		/* EVENT3, bits[31:24] */
+		drvdata->eventctrl0 = val;
+		break;
+	default:
+		break;
+	}
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(event);
+
+static ssize_t event_instren_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = BMVAL(drvdata->eventctrl1, 0, 3);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t event_instren_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	/* start by clearing all instruction event enable bits */
+	drvdata->eventctrl1 &= ~(BIT(0) | BIT(1) | BIT(2) | BIT(3));
+	switch (drvdata->nr_event) {
+	case 0x0:
+		/* generate Event element for event 1 */
+		drvdata->eventctrl1 |= val & BIT(1);
+		break;
+	case 0x1:
+		/* generate Event element for event 1 and 2 */
+		drvdata->eventctrl1 |= val & (BIT(0) | BIT(1));
+		break;
+	case 0x2:
+		/* generate Event element for event 1, 2 and 3 */
+		drvdata->eventctrl1 |= val & (BIT(0) | BIT(1) | BIT(2));
+		break;
+	case 0x3:
+		/* generate Event element for all 4 events */
+		drvdata->eventctrl1 |= val & 0xF;
+		break;
+	default:
+		break;
+	}
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(event_instren);
+
 static ssize_t status_show(struct device *dev,
 			   struct device_attribute *attr, char *buf)
 {
@@ -518,7 +954,6 @@ static ssize_t trcidr_show(struct device *dev,
 	return ret;
 }
 static DEVICE_ATTR_RO(trcidr);
-
 static struct attribute *coresight_etmv4_attrs[] = {
 	&dev_attr_nr_pe_cmp.attr,
 	&dev_attr_nr_addr_cmp.attr,
@@ -529,6 +964,11 @@ static struct attribute *coresight_etmv4_attrs[] = {
 	&dev_attr_nrseqstate.attr,
 	&dev_attr_nr_resource.attr,
 	&dev_attr_nr_ss_cmp.attr,
+	&dev_attr_reset.attr,
+	&dev_attr_mode.attr,
+	&dev_attr_pe.attr,
+	&dev_attr_event.attr,
+	&dev_attr_event_instren.attr,
 	&dev_attr_status.attr,
 	&dev_attr_mgmt.attr,
 	&dev_attr_trcidr.attr,
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 02/11] coresight-etm4x: Controls pertaining to tracer configuration
From: Mathieu Poirier @ 2015-04-29 17:16 UTC (permalink / raw)
  To: gregkh
  Cc: linux-arm-kernel, linux-api, linux-kernel, kaixu.xia,
	zhang.chunyan, mathieu.poirier
In-Reply-To: <1430327795-10710-1-git-send-email-mathieu.poirier@linaro.org>

From: Pratik Patel <pratikp@codeaurora.org>

Tracers can be configured with various options at synthesis
time and knowing what resources are available is important for
SW configuration purposes.

As such adding RO sysfs entries for characteristics related to the
tracer implementation.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 .../ABI/testing/sysfs-bus-coresight-devices-etm4x  |  61 +++++++++++
 drivers/hwtracing/coresight/coresight-etm4x.c      | 117 +++++++++++++++++++++
 2 files changed, 178 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
index a4b623871ca0..0f579eb24631 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
@@ -26,3 +26,64 @@ Date:		April 2015
 KernelVersion:	4.01
 Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
 Description:	(R) Provides value of all the ID registers (TRCIDRx).
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/nr_pe_cmp
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Indicates the number of PE comparator inputs that are
+		available for tracing.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/nr_addr_cmp
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Indicates the number of address comparator pairs that are
+		available for tracing.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/nr_cntr
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Indicates the number of counters that are available for
+		tracing.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/nr_ext_inp
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Indicates how many external inputs are implemented.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/numcidc
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Indicates the number of Context ID comparators that are
+		available for tracing.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/numvmidc
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Indicates the number of VMID comparators that are available
+		for tracing.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/nrseqstate
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Indicates the number of sequencer states that are implemented.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/nr_resource
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Indicates the number of resource selection pairs that are
+		available for tracing.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/nr_ss_cmp
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Indicates the number of single-shot comparator controls that
+		are available for tracing.
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index c53274264898..babf9bb27d25 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -268,6 +268,114 @@ static const struct coresight_ops etm4_cs_ops = {
 	.source_ops	= &etm4_source_ops,
 };
 
+static ssize_t nr_pe_cmp_show(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->nr_pe_cmp;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(nr_pe_cmp);
+
+static ssize_t nr_addr_cmp_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->nr_addr_cmp;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(nr_addr_cmp);
+
+static ssize_t nr_cntr_show(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->nr_cntr;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(nr_cntr);
+
+static ssize_t nr_ext_inp_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->nr_ext_inp;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(nr_ext_inp);
+
+static ssize_t numcidc_show(struct device *dev,
+			    struct device_attribute *attr,
+			    char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->numcidc;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(numcidc);
+
+static ssize_t numvmidc_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->numvmidc;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(numvmidc);
+
+static ssize_t nrseqstate_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->nrseqstate;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(nrseqstate);
+
+static ssize_t nr_resource_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->nr_resource;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(nr_resource);
+
+static ssize_t nr_ss_cmp_show(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	val = drvdata->nr_ss_cmp;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(nr_ss_cmp);
+
 static ssize_t status_show(struct device *dev,
 			   struct device_attribute *attr, char *buf)
 {
@@ -412,6 +520,15 @@ static ssize_t trcidr_show(struct device *dev,
 static DEVICE_ATTR_RO(trcidr);
 
 static struct attribute *coresight_etmv4_attrs[] = {
+	&dev_attr_nr_pe_cmp.attr,
+	&dev_attr_nr_addr_cmp.attr,
+	&dev_attr_nr_cntr.attr,
+	&dev_attr_nr_ext_inp.attr,
+	&dev_attr_numcidc.attr,
+	&dev_attr_numvmidc.attr,
+	&dev_attr_nrseqstate.attr,
+	&dev_attr_nr_resource.attr,
+	&dev_attr_nr_ss_cmp.attr,
 	&dev_attr_status.attr,
 	&dev_attr_mgmt.attr,
 	&dev_attr_trcidr.attr,
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 01/11] coresight-etm4x: Adding CoreSight ETM4x driver
From: Mathieu Poirier @ 2015-04-29 17:16 UTC (permalink / raw)
  To: gregkh
  Cc: mathieu.poirier, linux-api, linux-kernel, zhang.chunyan,
	linux-arm-kernel, kaixu.xia
In-Reply-To: <1430327795-10710-1-git-send-email-mathieu.poirier@linaro.org>

From: Pratik Patel <pratikp@codeaurora.org>

This driver manages the CoreSight ETMv4 (Embedded Trace Macrocell) IP block
to support HW assisted tracing on ARMv7 and ARMv8 architectures.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
Signed-off-by: Kaixu Xia <xiakaixu@huawei.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 .../ABI/testing/sysfs-bus-coresight-devices-etm4x  |  28 +
 drivers/hwtracing/coresight/Kconfig                |  10 +
 drivers/hwtracing/coresight/Makefile               |   1 +
 drivers/hwtracing/coresight/coresight-etm4x.c      | 829 +++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-etm4x.h      | 391 ++++++++++
 5 files changed, 1259 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
 create mode 100644 drivers/hwtracing/coresight/coresight-etm4x.c
 create mode 100644 drivers/hwtracing/coresight/coresight-etm4x.h

diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
new file mode 100644
index 000000000000..a4b623871ca0
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
@@ -0,0 +1,28 @@
+What:		/sys/bus/coresight/devices/<memory_map>.etm/enable_source
+Date:		April 2015
+KernelVersion:  4.01
+Contact:        Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(RW) Enable/disable tracing on this specific trace entiry.
+		Enabling a source implies the source has been configured
+		properly and a sink has been identidifed for it.  The path
+		of coresight components linking the source to the sink is
+		configured and managed automatically by the coresight framework.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/status
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) List various control and status registers.  The specific
+		layout and content is driver specific.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/mgmt
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Provides the current value of all the management registers.
+
+What:		/sys/bus/coresight/devices/<memory_map>.etm/trcidr
+Date:		April 2015
+KernelVersion:	4.01
+Contact:	Mathieu Poirier <mathieu.poirier@linaro.org>
+Description:	(R) Provides value of all the ID registers (TRCIDRx).
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index fc1f1ae7a49d..6b331d44d424 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -58,4 +58,14 @@ config CORESIGHT_SOURCE_ETM3X
 	  which allows tracing the instructions that a processor is executing
 	  This is primarily useful for instruction level tracing.  Depending
 	  the ETM version data tracing may also be available.
+
+config CORESIGHT_SOURCE_ETM4X
+	bool "CoreSight Embedded Trace Macrocell 4.x driver"
+	depends on ARM64
+	select CORESIGHT_LINKS_AND_SINKS
+	help
+	  This driver provides support for the ETM4.x tracer module, tracing the
+	  instructions that a processor is executing. This is primarily useful
+	  for instruction level tracing. Depending on the implemented version
+	  data tracing may also be available.
 endif
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 4b4bec890ef5..0af28d43465c 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
 obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
 					   coresight-replicator.o
 obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o
+obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
new file mode 100644
index 000000000000..c53274264898
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -0,0 +1,829 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/sysfs.h>
+#include <linux/stat.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/coresight.h>
+#include <linux/pm_wakeup.h>
+#include <linux/amba/bus.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/pm_runtime.h>
+#include <asm/sections.h>
+
+#include "coresight-etm4x.h"
+
+static int boot_enable;
+module_param_named(boot_enable, boot_enable, int, S_IRUGO);
+
+/* The number of ETMv4 currently registered */
+static int etm4_count;
+static struct etmv4_drvdata *etmdrvdata[NR_CPUS];
+
+static void etm4_os_unlock(void *info)
+{
+	struct etmv4_drvdata *drvdata = (struct etmv4_drvdata *)info;
+
+	/* Writing any value to ETMOSLAR unlocks the trace registers */
+	writel_relaxed(0x0, drvdata->base + TRCOSLAR);
+	isb();
+}
+
+static bool etm4_arch_supported(u8 arch)
+{
+	switch (arch) {
+	case ETM_ARCH_V4:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+static int etm4_trace_id(struct coresight_device *csdev)
+{
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+	int trace_id = -1;
+
+	if (!drvdata->enable)
+		return drvdata->trcid;
+
+	pm_runtime_get_sync(drvdata->dev);
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	CS_UNLOCK(drvdata->base);
+	trace_id = readl_relaxed(drvdata->base + TRCTRACEIDR);
+	trace_id &= ETM_TRACEID_MASK;
+	CS_LOCK(drvdata->base);
+
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	pm_runtime_put(drvdata->dev);
+
+	return trace_id;
+}
+
+static void etm4_enable_hw(void *info)
+{
+	int i;
+	struct etmv4_drvdata *drvdata = info;
+
+	CS_UNLOCK(drvdata->base);
+
+	etm4_os_unlock(drvdata);
+
+	/* Disable the trace unit before programming trace registers */
+	writel_relaxed(0, drvdata->base + TRCPRGCTLR);
+
+	/* wait for TRCSTATR.IDLE to go up */
+	if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 1))
+		dev_err(drvdata->dev,
+			"timeout observed when probing at offset %#x\n",
+			TRCSTATR);
+
+	writel_relaxed(drvdata->pe_sel, drvdata->base + TRCPROCSELR);
+	writel_relaxed(drvdata->cfg, drvdata->base + TRCCONFIGR);
+	/* nothing specific implemented */
+	writel_relaxed(0x0, drvdata->base + TRCAUXCTLR);
+	writel_relaxed(drvdata->eventctrl0, drvdata->base + TRCEVENTCTL0R);
+	writel_relaxed(drvdata->eventctrl1, drvdata->base + TRCEVENTCTL1R);
+	writel_relaxed(drvdata->stall_ctrl, drvdata->base + TRCSTALLCTLR);
+	writel_relaxed(drvdata->ts_ctrl, drvdata->base + TRCTSCTLR);
+	writel_relaxed(drvdata->syncfreq, drvdata->base + TRCSYNCPR);
+	writel_relaxed(drvdata->ccctlr, drvdata->base + TRCCCCTLR);
+	writel_relaxed(drvdata->bb_ctrl, drvdata->base + TRCBBCTLR);
+	writel_relaxed(drvdata->trcid, drvdata->base + TRCTRACEIDR);
+	writel_relaxed(drvdata->vinst_ctrl, drvdata->base + TRCVICTLR);
+	writel_relaxed(drvdata->viiectlr, drvdata->base + TRCVIIECTLR);
+	writel_relaxed(drvdata->vissctlr,
+		       drvdata->base + TRCVISSCTLR);
+	writel_relaxed(drvdata->vipcssctlr,
+		       drvdata->base + TRCVIPCSSCTLR);
+	for (i = 0; i < drvdata->nrseqstate - 1; i++)
+		writel_relaxed(drvdata->seq_ctrl[i],
+			       drvdata->base + TRCSEQEVRn(i));
+	writel_relaxed(drvdata->seq_rst, drvdata->base + TRCSEQRSTEVR);
+	writel_relaxed(drvdata->seq_state, drvdata->base + TRCSEQSTR);
+	writel_relaxed(drvdata->ext_inp, drvdata->base + TRCEXTINSELR);
+	for (i = 0; i < drvdata->nr_cntr; i++) {
+		writel_relaxed(drvdata->cntrldvr[i],
+			       drvdata->base + TRCCNTRLDVRn(i));
+		writel_relaxed(drvdata->cntr_ctrl[i],
+			       drvdata->base + TRCCNTCTLRn(i));
+		writel_relaxed(drvdata->cntr_val[i],
+			       drvdata->base + TRCCNTVRn(i));
+	}
+	for (i = 0; i < drvdata->nr_resource; i++)
+		writel_relaxed(drvdata->res_ctrl[i],
+			       drvdata->base + TRCRSCTLRn(i));
+
+	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+		writel_relaxed(drvdata->ss_ctrl[i],
+			       drvdata->base + TRCSSCCRn(i));
+		writel_relaxed(drvdata->ss_status[i],
+			       drvdata->base + TRCSSCSRn(i));
+		writel_relaxed(drvdata->ss_pe_cmp[i],
+			       drvdata->base + TRCSSPCICRn(i));
+	}
+	for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+		writeq_relaxed(drvdata->addr_val[i],
+			       drvdata->base + TRCACVRn(i));
+		writeq_relaxed(drvdata->addr_acc[i],
+			       drvdata->base + TRCACATRn(i));
+	}
+	for (i = 0; i < drvdata->numcidc; i++)
+		writeq_relaxed(drvdata->ctxid_val[i],
+			       drvdata->base + TRCCIDCVRn(i));
+	writel_relaxed(drvdata->ctxid_mask0, drvdata->base + TRCCIDCCTLR0);
+	writel_relaxed(drvdata->ctxid_mask1, drvdata->base + TRCCIDCCTLR1);
+
+	for (i = 0; i < drvdata->numvmidc; i++)
+		writeq_relaxed(drvdata->vmid_val[i],
+			       drvdata->base + TRCVMIDCVRn(i));
+	writel_relaxed(drvdata->vmid_mask0, drvdata->base + TRCVMIDCCTLR0);
+	writel_relaxed(drvdata->vmid_mask1, drvdata->base + TRCVMIDCCTLR1);
+
+	/* Enable the trace unit */
+	writel_relaxed(1, drvdata->base + TRCPRGCTLR);
+
+	/* wait for TRCSTATR.IDLE to go back down to '0' */
+	if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 0))
+		dev_err(drvdata->dev,
+			"timeout observed when probing at offset %#x\n",
+			TRCSTATR);
+
+	CS_LOCK(drvdata->base);
+
+	dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
+}
+
+static int etm4_enable(struct coresight_device *csdev)
+{
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
+
+	pm_runtime_get_sync(drvdata->dev);
+	spin_lock(&drvdata->spinlock);
+
+	/*
+	 * Executing etm4_enable_hw on the cpu whose ETM is being enabled
+	 * ensures that register writes occur when cpu is powered.
+	 */
+	ret = smp_call_function_single(drvdata->cpu,
+				       etm4_enable_hw, drvdata, 1);
+	if (ret)
+		goto err;
+	drvdata->enable = true;
+	drvdata->sticky_enable = true;
+
+	spin_unlock(&drvdata->spinlock);
+
+	dev_info(drvdata->dev, "ETM tracing enabled\n");
+	return 0;
+err:
+	spin_unlock(&drvdata->spinlock);
+	pm_runtime_put(drvdata->dev);
+	return ret;
+}
+
+static void etm4_disable_hw(void *info)
+{
+	u32 control;
+	struct etmv4_drvdata *drvdata = info;
+
+	CS_UNLOCK(drvdata->base);
+
+	control = readl_relaxed(drvdata->base + TRCPRGCTLR);
+
+	/* EN, bit[0] Trace unit enable bit */
+	control &= ~0x1;
+
+	/* make sure everything completes before disabling */
+	mb();
+	isb();
+	writel_relaxed(control, drvdata->base + TRCPRGCTLR);
+
+	CS_LOCK(drvdata->base);
+
+	dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
+}
+
+static void etm4_disable(struct coresight_device *csdev)
+{
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	/*
+	 * Taking hotplug lock here protects from clocks getting disabled
+	 * with tracing being left on (crash scenario) if user disable occurs
+	 * after cpu online mask indicates the cpu is offline but before the
+	 * DYING hotplug callback is serviced by the ETM driver.
+	 */
+	get_online_cpus();
+	spin_lock(&drvdata->spinlock);
+
+	/*
+	 * Executing etm4_disable_hw on the cpu whose ETM is being disabled
+	 * ensures that register writes occur when cpu is powered.
+	 */
+	smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
+	drvdata->enable = false;
+
+	spin_unlock(&drvdata->spinlock);
+	put_online_cpus();
+
+	pm_runtime_put(drvdata->dev);
+
+	dev_info(drvdata->dev, "ETM tracing disabled\n");
+}
+
+static const struct coresight_ops_source etm4_source_ops = {
+	.trace_id	= etm4_trace_id,
+	.enable		= etm4_enable,
+	.disable	= etm4_disable,
+};
+
+static const struct coresight_ops etm4_cs_ops = {
+	.source_ops	= &etm4_source_ops,
+};
+
+static ssize_t status_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	int ret;
+	unsigned long flags;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	pm_runtime_get_sync(drvdata->dev);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	CS_UNLOCK(drvdata->base);
+	ret = sprintf(buf,
+		      "TRCCONFIGR:\t0x%08x\n"
+		      "TRCEVENTCTL0R:\t0x%08x\n"
+		      "TRCEVENTCTL1R:\t0x%08x\n"
+		      "TRCSTALLCTLR:\t0x%08x\n"
+		      "TRCSYNCPR:\t0x%08x\n"
+		      "TRCTRACEIDR:\t0x%08x\n"
+		      "TRCTSCTLR:\t0x%08x\n"
+		      "TRCVDARCCTLR:\t0x%08x\n"
+		      "TRCVDCTLR:\t0x%08x\n"
+		      "TRCVDSACCTLR:\t0x%08x\n"
+		      "TRCVICTLR:\t0x%08x\n"
+		      "TRCVIIECTLR:\t0x%08x\n"
+		      "TRCVISSCTLR:\t0x%08x\n"
+		      "TRCPRGCTLR:\t0x%08x\n"
+		      "CPU affinity:\t%d\n",
+		      readl_relaxed(drvdata->base + TRCCONFIGR),
+		      readl_relaxed(drvdata->base + TRCEVENTCTL0R),
+		      readl_relaxed(drvdata->base + TRCEVENTCTL1R),
+		      readl_relaxed(drvdata->base + TRCSTALLCTLR),
+		      readl_relaxed(drvdata->base + TRCSYNCPR),
+		      readl_relaxed(drvdata->base + TRCTRACEIDR),
+		      readl_relaxed(drvdata->base + TRCTSCTLR),
+		      readl_relaxed(drvdata->base + TRCVDARCCTLR),
+		      readl_relaxed(drvdata->base + TRCVDCTLR),
+		      readl_relaxed(drvdata->base + TRCVDSACCTLR),
+		      readl_relaxed(drvdata->base + TRCVICTLR),
+		      readl_relaxed(drvdata->base + TRCVIIECTLR),
+		      readl_relaxed(drvdata->base + TRCVISSCTLR),
+		      readl_relaxed(drvdata->base + TRCPRGCTLR),
+		      drvdata->cpu);
+	CS_LOCK(drvdata->base);
+
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	pm_runtime_put(drvdata->dev);
+
+	return ret;
+}
+static DEVICE_ATTR_RO(status);
+
+static ssize_t mgmt_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	int ret;
+	unsigned long flags;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	pm_runtime_get_sync(drvdata->dev);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	CS_UNLOCK(drvdata->base);
+	ret = sprintf(buf,
+		      "TRCOSLSR:\t0x%08x\n"
+		      "TRCPDCR:\t0x%08x\n"
+		      "TRCPDSR:\t0x%08x\n"
+		      "TRCLSR:\t\t0x%08x\n"
+		      "TRCAUTHSTATUS:\t0x%08x\n"
+		      "TRCDEVID:\t0x%08x\n"
+		      "TRCDEVTYPE:\t0x%08x\n"
+		      "TRCPIDR0:\t0x%08x\n"
+		      "TRCPIDR1:\t0x%08x\n"
+		      "TRCPIDR2:\t0x%08x\n"
+		      "TRCPIDR3:\t0x%08x\n",
+		      readl_relaxed(drvdata->base + TRCOSLSR),
+		      readl_relaxed(drvdata->base + TRCPDCR),
+		      readl_relaxed(drvdata->base + TRCPDSR),
+		      readl_relaxed(drvdata->base + TRCLSR),
+		      readl_relaxed(drvdata->base + TRCAUTHSTATUS),
+		      readl_relaxed(drvdata->base + TRCDEVID),
+		      readl_relaxed(drvdata->base + TRCDEVTYPE),
+		      readl_relaxed(drvdata->base + TRCPIDR0),
+		      readl_relaxed(drvdata->base + TRCPIDR1),
+		      readl_relaxed(drvdata->base + TRCPIDR2),
+		      readl_relaxed(drvdata->base + TRCPIDR3));
+	CS_LOCK(drvdata->base);
+
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	pm_runtime_put(drvdata->dev);
+
+	return ret;
+}
+static DEVICE_ATTR_RO(mgmt);
+
+static ssize_t trcidr_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	int ret;
+	unsigned long flags;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	pm_runtime_get_sync(drvdata->dev);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	CS_UNLOCK(drvdata->base);
+	ret = sprintf(buf,
+		      "TRCIDR0:\t0x%08x\n"
+		      "TRCIDR1:\t0x%08x\n"
+		      "TRCIDR2:\t0x%08x\n"
+		      "TRCIDR3:\t0x%08x\n"
+		      "TRCIDR4:\t0x%08x\n"
+		      "TRCIDR5:\t0x%08x\n"
+		      "TRCIDR6:\t0x%08x\n"
+		      "TRCIDR7:\t0x%08x\n"
+		      "TRCIDR8:\t0x%08x\n"
+		      "TRCIDR9:\t0x%08x\n"
+		      "TRCIDR10:\t0x%08x\n"
+		      "TRCIDR11:\t0x%08x\n"
+		      "TRCIDR12:\t0x%08x\n"
+		      "TRCIDR13:\t0x%08x\n",
+		      readl_relaxed(drvdata->base + TRCIDR0),
+		      readl_relaxed(drvdata->base + TRCIDR1),
+		      readl_relaxed(drvdata->base + TRCIDR2),
+		      readl_relaxed(drvdata->base + TRCIDR3),
+		      readl_relaxed(drvdata->base + TRCIDR4),
+		      readl_relaxed(drvdata->base + TRCIDR5),
+		      readl_relaxed(drvdata->base + TRCIDR6),
+		      readl_relaxed(drvdata->base + TRCIDR7),
+		      readl_relaxed(drvdata->base + TRCIDR8),
+		      readl_relaxed(drvdata->base + TRCIDR9),
+		      readl_relaxed(drvdata->base + TRCIDR10),
+		      readl_relaxed(drvdata->base + TRCIDR11),
+		      readl_relaxed(drvdata->base + TRCIDR12),
+		      readl_relaxed(drvdata->base + TRCIDR13));
+	CS_LOCK(drvdata->base);
+
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	pm_runtime_put(drvdata->dev);
+
+	return ret;
+}
+static DEVICE_ATTR_RO(trcidr);
+
+static struct attribute *coresight_etmv4_attrs[] = {
+	&dev_attr_status.attr,
+	&dev_attr_mgmt.attr,
+	&dev_attr_trcidr.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(coresight_etmv4);
+
+static void etm4_init_arch_data(void *info)
+{
+	u32 etmidr0;
+	u32 etmidr1;
+	u32 etmidr2;
+	u32 etmidr3;
+	u32 etmidr4;
+	u32 etmidr5;
+	struct etmv4_drvdata *drvdata = info;
+
+	CS_UNLOCK(drvdata->base);
+
+	/* find all capabilities of the tracing unit */
+	etmidr0 = readl_relaxed(drvdata->base + TRCIDR0);
+
+	/* INSTP0, bits[2:1] P0 tracing support field */
+	if (BMVAL(etmidr0, 1, 1) && BMVAL(etmidr0, 2, 2))
+		drvdata->instrp0 = true;
+	else
+		drvdata->instrp0 = false;
+
+	/* TRCBB, bit[5] Branch broadcast tracing support bit */
+	if (BMVAL(etmidr0, 5, 5))
+		drvdata->trcbb = true;
+	else
+		drvdata->trcbb = false;
+
+	/* TRCCOND, bit[6] Conditional instruction tracing support bit */
+	if (BMVAL(etmidr0, 6, 6))
+		drvdata->trccond = true;
+	else
+		drvdata->trccond = false;
+
+	/* TRCCCI, bit[7] Cycle counting instruction bit */
+	if (BMVAL(etmidr0, 7, 7))
+		drvdata->trccci = true;
+	else
+		drvdata->trccci = false;
+
+	/* RETSTACK, bit[9] Return stack bit */
+	if (BMVAL(etmidr0, 9, 9))
+		drvdata->retstack = true;
+	else
+		drvdata->retstack = false;
+
+	/* NUMEVENT, bits[11:10] Number of events field */
+	drvdata->nr_event = BMVAL(etmidr0, 10, 11);
+	/* QSUPP, bits[16:15] Q element support field */
+	drvdata->q_support = BMVAL(etmidr0, 15, 16);
+	/* TSSIZE, bits[28:24] Global timestamp size field */
+	drvdata->ts_size = BMVAL(etmidr0, 24, 28);
+
+	/* base architecture of trace unit */
+	etmidr1 = readl_relaxed(drvdata->base + TRCIDR1);
+	/*
+	 * TRCARCHMIN, bits[7:4] architecture the minor version number
+	 * TRCARCHMAJ, bits[11:8] architecture major versin number
+	 */
+	drvdata->arch = BMVAL(etmidr1, 4, 11);
+
+	/* maximum size of resources */
+	etmidr2 = readl_relaxed(drvdata->base + TRCIDR2);
+	/* CIDSIZE, bits[9:5] Indicates the Context ID size */
+	drvdata->ctxid_size = BMVAL(etmidr2, 5, 9);
+	/* VMIDSIZE, bits[14:10] Indicates the VMID size */
+	drvdata->vmid_size = BMVAL(etmidr2, 10, 14);
+	/* CCSIZE, bits[28:25] size of the cycle counter in bits minus 12 */
+	drvdata->ccsize = BMVAL(etmidr2, 25, 28);
+
+	etmidr3 = readl_relaxed(drvdata->base + TRCIDR3);
+	/* CCITMIN, bits[11:0] minimum threshold value that can be programmed */
+	drvdata->ccitmin = BMVAL(etmidr3, 0, 11);
+	/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
+	drvdata->s_ex_level = BMVAL(etmidr3, 16, 19);
+	/* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
+	drvdata->ns_ex_level = BMVAL(etmidr3, 20, 23);
+
+	/*
+	 * TRCERR, bit[24] whether a trace unit can trace a
+	 * system error exception.
+	 */
+	if (BMVAL(etmidr3, 24, 24))
+		drvdata->trc_error = true;
+	else
+		drvdata->trc_error = false;
+
+	/* SYNCPR, bit[25] implementation has a fixed synchronization period? */
+	if (BMVAL(etmidr3, 25, 25))
+		drvdata->syncpr = true;
+	else
+		drvdata->syncpr = false;
+
+	/* STALLCTL, bit[26] is stall control implemented? */
+	if (BMVAL(etmidr3, 26, 26))
+		drvdata->stallctl = true;
+	else
+		drvdata->stallctl = false;
+
+	/* SYSSTALL, bit[27] implementation can support stall control? */
+	if (BMVAL(etmidr3, 27, 27))
+		drvdata->sysstall = true;
+	else
+		drvdata->sysstall = false;
+
+	/* NUMPROC, bits[30:28] the number of PEs available for tracing */
+	drvdata->nr_pe = BMVAL(etmidr3, 28, 30);
+
+	/* NOOVERFLOW, bit[31] is trace overflow prevention supported */
+	if (BMVAL(etmidr3, 31, 31))
+		drvdata->nooverflow = true;
+	else
+		drvdata->nooverflow = false;
+
+	/* number of resources trace unit supports */
+	etmidr4 = readl_relaxed(drvdata->base + TRCIDR4);
+	/* NUMACPAIRS, bits[0:3] number of addr comparator pairs for tracing */
+	drvdata->nr_addr_cmp = BMVAL(etmidr4, 0, 3);
+	/* NUMPC, bits[15:12] number of PE comparator inputs for tracing */
+	drvdata->nr_pe_cmp = BMVAL(etmidr4, 12, 15);
+	/* NUMRSPAIR, bits[19:16] the number of resource pairs for tracing */
+	drvdata->nr_resource = BMVAL(etmidr4, 16, 19);
+	/*
+	 * NUMSSCC, bits[23:20] the number of single-shot
+	 * comparator control for tracing
+	 */
+	drvdata->nr_ss_cmp = BMVAL(etmidr4, 20, 23);
+	/* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
+	drvdata->numcidc = BMVAL(etmidr4, 24, 27);
+	/* NUMVMIDC, bits[31:28] number of VMID comparators for tracing */
+	drvdata->numvmidc = BMVAL(etmidr4, 28, 31);
+
+	etmidr5 = readl_relaxed(drvdata->base + TRCIDR5);
+	/* NUMEXTIN, bits[8:0] number of external inputs implemented */
+	drvdata->nr_ext_inp = BMVAL(etmidr5, 0, 8);
+	/* TRACEIDSIZE, bits[21:16] indicates the trace ID width */
+	drvdata->trcid_size = BMVAL(etmidr5, 16, 21);
+	/* ATBTRIG, bit[22] implementation can support ATB triggers? */
+	if (BMVAL(etmidr5, 22, 22))
+		drvdata->atbtrig = true;
+	else
+		drvdata->atbtrig = false;
+	/*
+	 * LPOVERRIDE, bit[23] implementation supports
+	 * low-power state override
+	 */
+	if (BMVAL(etmidr5, 23, 23))
+		drvdata->lpoverride = true;
+	else
+		drvdata->lpoverride = false;
+	/* NUMSEQSTATE, bits[27:25] number of sequencer states implemented */
+	drvdata->nrseqstate = BMVAL(etmidr5, 25, 27);
+	/* NUMCNTR, bits[30:28] number of counters available for tracing */
+	drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
+	CS_LOCK(drvdata->base);
+}
+
+static void etm4_init_default_data(struct etmv4_drvdata *drvdata)
+{
+	int i;
+
+	drvdata->pe_sel = 0x0;
+	drvdata->cfg = (ETMv4_MODE_CTXID | ETM_MODE_VMID |
+			ETMv4_MODE_TIMESTAMP | ETM_MODE_RETURNSTACK);
+
+	/* disable all events tracing */
+	drvdata->eventctrl0 = 0x0;
+	drvdata->eventctrl1 = 0x0;
+
+	/* disable stalling */
+	drvdata->stall_ctrl = 0x0;
+
+	/* disable timestamp event */
+	drvdata->ts_ctrl = 0x0;
+
+	/* enable trace synchronization every 4096 bytes for trace */
+	if (drvdata->syncpr == false)
+		drvdata->syncfreq = 0xC;
+
+	/*
+	 *  enable viewInst to trace everything with start-stop logic in
+	 *  started state
+	 */
+	drvdata->vinst_ctrl |= BIT(0);
+	/* set initial state of start-stop logic */
+	if (drvdata->nr_addr_cmp)
+		drvdata->vinst_ctrl |= BIT(9);
+
+	/* no address range filtering for ViewInst */
+	drvdata->viiectlr = 0x0;
+	/* no start-stop filtering for ViewInst */
+	drvdata->vissctlr = 0x0;
+
+	/* disable seq events */
+	for (i = 0; i < drvdata->nrseqstate-1; i++)
+		drvdata->seq_ctrl[i] = 0x0;
+	drvdata->seq_rst = 0x0;
+	drvdata->seq_state = 0x0;
+
+	/* disable external input events */
+	drvdata->ext_inp = 0x0;
+
+	for (i = 0; i < drvdata->nr_cntr; i++) {
+		drvdata->cntrldvr[i] = 0x0;
+		drvdata->cntr_ctrl[i] = 0x0;
+		drvdata->cntr_val[i] = 0x0;
+	}
+
+	for (i = 2; i < drvdata->nr_resource * 2; i++)
+		drvdata->res_ctrl[i] = 0x0;
+
+	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+		drvdata->ss_ctrl[i] = 0x0;
+		drvdata->ss_pe_cmp[i] = 0x0;
+	}
+
+	if (drvdata->nr_addr_cmp >= 1) {
+		drvdata->addr_val[0] = (unsigned long)_stext;
+		drvdata->addr_val[1] = (unsigned long)_etext;
+		drvdata->addr_type[0] = ETM_ADDR_TYPE_RANGE;
+		drvdata->addr_type[1] = ETM_ADDR_TYPE_RANGE;
+	}
+
+	for (i = 0; i < drvdata->numcidc; i++)
+		drvdata->ctxid_val[i] = 0x0;
+	drvdata->ctxid_mask0 = 0x0;
+	drvdata->ctxid_mask1 = 0x0;
+
+	for (i = 0; i < drvdata->numvmidc; i++)
+		drvdata->vmid_val[i] = 0x0;
+	drvdata->vmid_mask0 = 0x0;
+	drvdata->vmid_mask1 = 0x0;
+
+	/*
+	 * A trace ID value of 0 is invalid, so let's start at some
+	 * random value that fits in 7 bits.  ETMv3.x has 0x10 so let's
+	 * start at 0x20.
+	 */
+	drvdata->trcid = 0x20 + drvdata->cpu;
+}
+
+static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
+			    void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+
+	if (!etmdrvdata[cpu])
+		goto out;
+
+	switch (action & (~CPU_TASKS_FROZEN)) {
+	case CPU_STARTING:
+		spin_lock(&etmdrvdata[cpu]->spinlock);
+		if (!etmdrvdata[cpu]->os_unlock) {
+			etm4_os_unlock(etmdrvdata[cpu]);
+			etmdrvdata[cpu]->os_unlock = true;
+		}
+
+		if (etmdrvdata[cpu]->enable)
+			etm4_enable_hw(etmdrvdata[cpu]);
+		spin_unlock(&etmdrvdata[cpu]->spinlock);
+		break;
+
+	case CPU_ONLINE:
+		if (etmdrvdata[cpu]->boot_enable &&
+			!etmdrvdata[cpu]->sticky_enable)
+			coresight_enable(etmdrvdata[cpu]->csdev);
+		break;
+
+	case CPU_DYING:
+		spin_lock(&etmdrvdata[cpu]->spinlock);
+		if (etmdrvdata[cpu]->enable)
+			etm4_disable_hw(etmdrvdata[cpu]);
+		spin_unlock(&etmdrvdata[cpu]->spinlock);
+		break;
+	}
+out:
+	return NOTIFY_OK;
+}
+
+static struct notifier_block etm4_cpu_notifier = {
+	.notifier_call = etm4_cpu_callback,
+};
+
+static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
+{
+	int ret;
+	void __iomem *base;
+	struct device *dev = &adev->dev;
+	struct coresight_platform_data *pdata = NULL;
+	struct etmv4_drvdata *drvdata;
+	struct resource *res = &adev->res;
+	struct coresight_desc *desc;
+	struct device_node *np = adev->dev.of_node;
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	if (np) {
+		pdata = of_get_coresight_platform_data(dev, np);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		adev->dev.platform_data = pdata;
+	}
+
+	drvdata->dev = &adev->dev;
+	dev_set_drvdata(dev, drvdata);
+
+	/* Validity for the resource is already checked by the AMBA core */
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	drvdata->base = base;
+
+	spin_lock_init(&drvdata->spinlock);
+
+	drvdata->cpu = pdata ? pdata->cpu : 0;
+
+	get_online_cpus();
+	etmdrvdata[drvdata->cpu] = drvdata;
+
+	if (!smp_call_function_single(drvdata->cpu, etm4_os_unlock, drvdata, 1))
+		drvdata->os_unlock = true;
+
+	if (smp_call_function_single(drvdata->cpu,
+				etm4_init_arch_data,  drvdata, 1))
+		dev_err(dev, "ETM arch init failed\n");
+
+	if (!etm4_count++)
+		register_hotcpu_notifier(&etm4_cpu_notifier);
+
+	put_online_cpus();
+
+	if (etm4_arch_supported(drvdata->arch) == false) {
+		ret = -EINVAL;
+		goto err_arch_supported;
+	}
+	etm4_init_default_data(drvdata);
+
+	pm_runtime_put(&adev->dev);
+
+	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+	desc->ops = &etm4_cs_ops;
+	desc->pdata = pdata;
+	desc->dev = dev;
+	desc->groups = coresight_etmv4_groups;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev)) {
+		ret = PTR_ERR(drvdata->csdev);
+		goto err_coresight_register;
+	}
+
+	dev_info(dev, "%s initialized\n", (char *)id->data);
+
+	if (boot_enable) {
+		coresight_enable(drvdata->csdev);
+		drvdata->boot_enable = true;
+	}
+
+	return 0;
+
+err_arch_supported:
+	pm_runtime_put(&adev->dev);
+err_coresight_register:
+	if (--etm4_count == 0)
+		unregister_hotcpu_notifier(&etm4_cpu_notifier);
+	return ret;
+}
+
+static int etm4_remove(struct amba_device *adev)
+{
+	struct etmv4_drvdata *drvdata = amba_get_drvdata(adev);
+
+	coresight_unregister(drvdata->csdev);
+	if (--etm4_count == 0)
+		unregister_hotcpu_notifier(&etm4_cpu_notifier);
+
+	return 0;
+}
+
+static struct amba_id etm4_ids[] = {
+	{       /* ETM 4.0 - Juno board */
+		.id	= 0x000bb95e,
+		.mask	= 0x000fffff,
+		.data	= "ETM 4.0",
+	},
+	{ 0, 0},
+};
+
+static struct amba_driver etm4x_driver = {
+	.drv = {
+		.name   = "coresight-etm4x",
+		.owner  = THIS_MODULE,
+	},
+	.probe		= etm4_probe,
+	.remove		= etm4_remove,
+	.id_table	= etm4_ids,
+};
+
+module_amba_driver(etm4x_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Embedded Trace Macrocell v4 driver");
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
new file mode 100644
index 000000000000..e08e983dd2d9
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -0,0 +1,391 @@
+/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CORESIGHT_CORESIGHT_ETM_H
+#define _CORESIGHT_CORESIGHT_ETM_H
+
+#include <linux/spinlock.h>
+#include "coresight-priv.h"
+
+/*
+ * Device registers:
+ * 0x000 - 0x2FC: Trace		registers
+ * 0x300 - 0x314: Management	registers
+ * 0x318 - 0xEFC: Trace		registers
+ * 0xF00: Management		registers
+ * 0xFA0 - 0xFA4: Trace		registers
+ * 0xFA8 - 0xFFC: Management	registers
+ */
+/* Trace registers (0x000-0x2FC) */
+/* Main control and configuration registers */
+#define TRCPRGCTLR			0x004
+#define TRCPROCSELR			0x008
+#define TRCSTATR			0x00C
+#define TRCCONFIGR			0x010
+#define TRCAUXCTLR			0x018
+#define TRCEVENTCTL0R			0x020
+#define TRCEVENTCTL1R			0x024
+#define TRCSTALLCTLR			0x02C
+#define TRCTSCTLR			0x030
+#define TRCSYNCPR			0x034
+#define TRCCCCTLR			0x038
+#define TRCBBCTLR			0x03C
+#define TRCTRACEIDR			0x040
+#define TRCQCTLR			0x044
+/* Filtering control registers */
+#define TRCVICTLR			0x080
+#define TRCVIIECTLR			0x084
+#define TRCVISSCTLR			0x088
+#define TRCVIPCSSCTLR			0x08C
+#define TRCVDCTLR			0x0A0
+#define TRCVDSACCTLR			0x0A4
+#define TRCVDARCCTLR			0x0A8
+/* Derived resources registers */
+#define TRCSEQEVRn(n)			(0x100 + (n * 4))
+#define TRCSEQRSTEVR			0x118
+#define TRCSEQSTR			0x11C
+#define TRCEXTINSELR			0x120
+#define TRCCNTRLDVRn(n)			(0x140 + (n * 4))
+#define TRCCNTCTLRn(n)			(0x150 + (n * 4))
+#define TRCCNTVRn(n)			(0x160 + (n * 4))
+/* ID registers */
+#define TRCIDR8				0x180
+#define TRCIDR9				0x184
+#define TRCIDR10			0x188
+#define TRCIDR11			0x18C
+#define TRCIDR12			0x190
+#define TRCIDR13			0x194
+#define TRCIMSPEC0			0x1C0
+#define TRCIMSPECn(n)			(0x1C0 + (n * 4))
+#define TRCIDR0				0x1E0
+#define TRCIDR1				0x1E4
+#define TRCIDR2				0x1E8
+#define TRCIDR3				0x1EC
+#define TRCIDR4				0x1F0
+#define TRCIDR5				0x1F4
+#define TRCIDR6				0x1F8
+#define TRCIDR7				0x1FC
+/* Resource selection registers */
+#define TRCRSCTLRn(n)			(0x200 + (n * 4))
+/* Single-shot comparator registers */
+#define TRCSSCCRn(n)			(0x280 + (n * 4))
+#define TRCSSCSRn(n)			(0x2A0 + (n * 4))
+#define TRCSSPCICRn(n)			(0x2C0 + (n * 4))
+/* Management registers (0x300-0x314) */
+#define TRCOSLAR			0x300
+#define TRCOSLSR			0x304
+#define TRCPDCR				0x310
+#define TRCPDSR				0x314
+/* Trace registers (0x318-0xEFC) */
+/* Comparator registers */
+#define TRCACVRn(n)			(0x400 + (n * 8))
+#define TRCACATRn(n)			(0x480 + (n * 8))
+#define TRCDVCVRn(n)			(0x500 + (n * 16))
+#define TRCDVCMRn(n)			(0x580 + (n * 16))
+#define TRCCIDCVRn(n)			(0x600 + (n * 8))
+#define TRCVMIDCVRn(n)			(0x640 + (n * 8))
+#define TRCCIDCCTLR0			0x680
+#define TRCCIDCCTLR1			0x684
+#define TRCVMIDCCTLR0			0x688
+#define TRCVMIDCCTLR1			0x68C
+/* Management register (0xF00) */
+/* Integration control registers */
+#define TRCITCTRL			0xF00
+/* Trace registers (0xFA0-0xFA4) */
+/* Claim tag registers */
+#define TRCCLAIMSET			0xFA0
+#define TRCCLAIMCLR			0xFA4
+/* Management registers (0xFA8-0xFFC) */
+#define TRCDEVAFF0			0xFA8
+#define TRCDEVAFF1			0xFAC
+#define TRCLAR				0xFB0
+#define TRCLSR				0xFB4
+#define TRCAUTHSTATUS			0xFB8
+#define TRCDEVARCH			0xFBC
+#define TRCDEVID			0xFC8
+#define TRCDEVTYPE			0xFCC
+#define TRCPIDR4			0xFD0
+#define TRCPIDR5			0xFD4
+#define TRCPIDR6			0xFD8
+#define TRCPIDR7			0xFDC
+#define TRCPIDR0			0xFE0
+#define TRCPIDR1			0xFE4
+#define TRCPIDR2			0xFE8
+#define TRCPIDR3			0xFEC
+#define TRCCIDR0			0xFF0
+#define TRCCIDR1			0xFF4
+#define TRCCIDR2			0xFF8
+#define TRCCIDR3			0xFFC
+
+/* ETMv4 resources */
+#define ETM_MAX_NR_PE			8
+#define ETMv4_MAX_CNTR			4
+#define ETM_MAX_SEQ_STATES		4
+#define ETM_MAX_EXT_INP_SEL		4
+#define ETM_MAX_EXT_INP			256
+#define ETM_MAX_EXT_OUT			4
+#define ETM_MAX_SINGLE_ADDR_CMP		16
+#define ETM_MAX_ADDR_RANGE_CMP		(ETM_MAX_SINGLE_ADDR_CMP / 2)
+#define ETM_MAX_DATA_VAL_CMP		8
+#define ETMv4_MAX_CTXID_CMP		8
+#define ETM_MAX_VMID_CMP		8
+#define ETM_MAX_PE_CMP			8
+#define ETM_MAX_RES_SEL			16
+#define ETM_MAX_SS_CMP			8
+
+#define ETM_ARCH_V4			0x40
+#define ETMv4_SYNC_MASK			0x1F
+#define ETM_CYC_THRESHOLD_MASK		0xFFF
+#define ETMv4_EVENT_MASK		0xFF
+#define ETM_CNTR_MAX_VAL		0xFFFF
+#define ETM_TRACEID_MASK		0x3f
+
+/* ETMv4 programming modes */
+#define ETM_MODE_EXCLUDE		BIT(0)
+#define ETM_MODE_LOAD			BIT(1)
+#define ETM_MODE_STORE			BIT(2)
+#define ETM_MODE_LOAD_STORE		BIT(3)
+#define ETM_MODE_BB			BIT(4)
+#define ETMv4_MODE_CYCACC		BIT(5)
+#define ETMv4_MODE_CTXID		BIT(6)
+#define ETM_MODE_VMID			BIT(7)
+#define ETM_MODE_COND(val)		BMVAL(val, 8, 10)
+#define ETMv4_MODE_TIMESTAMP		BIT(11)
+#define ETM_MODE_RETURNSTACK		BIT(12)
+#define ETM_MODE_QELEM(val)		BMVAL(val, 13, 14)
+#define ETM_MODE_DATA_TRACE_ADDR	BIT(15)
+#define ETM_MODE_DATA_TRACE_VAL		BIT(16)
+#define ETM_MODE_ISTALL			BIT(17)
+#define ETM_MODE_DSTALL			BIT(18)
+#define ETM_MODE_ATB_TRIGGER		BIT(19)
+#define ETM_MODE_LPOVERRIDE		BIT(20)
+#define ETM_MODE_ISTALL_EN		BIT(21)
+#define ETM_MODE_DSTALL_EN		BIT(22)
+#define ETM_MODE_INSTPRIO		BIT(23)
+#define ETM_MODE_NOOVERFLOW		BIT(24)
+#define ETM_MODE_TRACE_RESET		BIT(25)
+#define ETM_MODE_TRACE_ERR		BIT(26)
+#define ETM_MODE_VIEWINST_STARTSTOP	BIT(27)
+#define ETMv4_MODE_ALL			0xFFFFFFF
+
+#define TRCSTATR_IDLE_BIT		0
+
+/**
+ * struct etm4_drvdata - specifics associated to an ETM component
+ * @base:       Memory mapped base address for this component.
+ * @dev:        The device entity associated to this component.
+ * @csdev:      Component vitals needed by the framework.
+ * @spinlock:   Only one at a time pls.
+ * @cpu:        The cpu this component is affined to.
+ * @arch:       ETM version number.
+ * @enable:	Is this ETM currently tracing.
+ * @sticky_enable: true if ETM base configuration has been done.
+ * @boot_enable:True if we should start tracing at boot time.
+ * @os_unlock:  True if access to management registers is allowed.
+ * @nr_pe:	The number of processing entity available for tracing.
+ * @nr_pe_cmp:	The number of processing entity comparator inputs that are
+ *		available for tracing.
+ * @nr_addr_cmp:Number of pairs of address comparators available
+ *		as found in ETMIDR4 0-3.
+ * @nr_cntr:    Number of counters as found in ETMIDR5 bit 28-30.
+ * @nr_ext_inp: Number of external input.
+ * @numcidc:	Number of contextID comparators.
+ * @numvmidc:	Number of VMID comparators.
+ * @nrseqstate: The number of sequencer states that are implemented.
+ * @nr_event:	Indicates how many events the trace unit support.
+ * @nr_resource:The number of resource selection pairs available for tracing.
+ * @nr_ss_cmp:	Number of single-shot comparator controls that are available.
+ * @mode:	Controls various modes supported by this ETM.
+ * @trcid:	value of the current ID for this component.
+ * @trcid_size: Indicates the trace ID width.
+ * @instrp0:	Tracing of load and store instructions
+ *		as P0 elements is supported.
+ * @trccond:	If the trace unit supports conditional
+ *		instruction tracing.
+ * @retstack:	Indicates if the implementation supports a return stack.
+ * @trc_error:	Whether a trace unit can trace a system
+ *		error exception.
+ * @atbtrig:	If the implementation can support ATB triggers
+ * @lpoverride:	If the implementation can support low-power state over.
+ * @pe_sel:	Controls which PE to trace.
+ * @cfg:	Controls the tracing options.
+ * @eventctrl0: Controls the tracing of arbitrary events.
+ * @eventctrl1: Controls the behavior of the events that @event_ctrl0 selects.
+ * @stallctl:	If functionality that prevents trace unit buffer overflows
+ *		is available.
+ * @sysstall:	Does the system support stall control of the PE?
+ * @nooverflow:	Indicate if overflow prevention is supported.
+ * @stall_ctrl:	Enables trace unit functionality that prevents trace
+ *		unit buffer overflows.
+ * @ts_size:	Global timestamp size field.
+ * @ts_ctrl:	Controls the insertion of global timestamps in the
+ *		trace streams.
+ * @syncpr:	Indicates if an implementation has a fixed
+ *		synchronization period.
+ * @syncfreq:	Controls how often trace synchronization requests occur.
+ * @trccci:	Indicates if the trace unit supports cycle counting
+ *		for instruction.
+ * @ccsize:	Indicates the size of the cycle counter in bits.
+ * @ccitmin:	minimum value that can be programmed in
+ *		the TRCCCCTLR register.
+ * @ccctlr:	Sets the threshold value for cycle counting.
+ * @trcbb:	Indicates if the trace unit supports branch broadcast tracing.
+ * @q_support:	Q element support characteristics.
+ * @vinst_ctrl:	Controls instruction trace filtering.
+ * @viiectlr:	Set or read, the address range comparators.
+ * @vissctlr:	Set, or read, the single address comparators that control the
+ *		ViewInst start-stop logic.
+ * @vipcssctlr:	Set, or read, which PE comparator inputs can control the
+ *		ViewInst start-stop logic.
+ * @seq_idx:	Sequencor index selector.
+ * @seq_ctrl:	Control for the sequencer state transition control register.
+ * @seq_rst:	Moves the sequencer to state 0 when a programmed event occurs.
+ * @seq_state:	Set, or read the sequencer state.
+ * @cntr_idx:	Counter index seletor.
+ * @cntrldvr:	Sets or returns the reload count value for a counter.
+ * @cntr_ctrl:	Controls the operation of a counter.
+ * @cntr_val:	Sets or returns the value for a counter.
+ * @res_idx:	Resource index selector.
+ * @res_ctrl:	Controls the selection of the resources in the trace unit.
+ * @ss_ctrl:	Controls the corresponding single-shot comparator resource.
+ * @ss_status:	The status of the corresponding single-shot comparator.
+ * @ss_pe_cmp:	Selects the PE comparator inputs for Single-shot control.
+ * @addr_idx:	Address comparator index selector.
+ * @addr_val:	Value for address comparator.
+ * @addr_acc:	Address comparator access type.
+ * @addr_type:	Current status of the comparator register.
+ * @ctxid_idx:	Context ID index selector.
+ * @ctxid_size:	Size of the context ID field to consider.
+ * @ctxid_val:	Value of the context ID comparator.
+ * @ctxid_mask0:Context ID comparator mask for comparator 0-3.
+ * @ctxid_mask1:Context ID comparator mask for comparator 4-7.
+ * @vmid_idx:	VM ID index selector.
+ * @vmid_size:	Size of the VM ID comparator to consider.
+ * @vmid_val:	Value of the VM ID comparator.
+ * @vmid_mask0:	VM ID comparator mask for comparator 0-3.
+ * @vmid_mask1:	VM ID comparator mask for comparator 4-7.
+ * @s_ex_level:	In secure state, indicates whether instruction tracing is
+ *		supported for the corresponding Exception level.
+ * @ns_ex_level:In non-secure state, indicates whether instruction tracing is
+ *		supported for the corresponding Exception level.
+ * @ext_inp:	External input selection.
+ */
+struct etmv4_drvdata {
+	void __iomem			*base;
+	struct device			*dev;
+	struct coresight_device		*csdev;
+	spinlock_t			spinlock;
+	int				cpu;
+	u8				arch;
+	bool				enable;
+	bool				sticky_enable;
+	bool				boot_enable;
+	bool				os_unlock;
+	u8				nr_pe;
+	u8				nr_pe_cmp;
+	u8				nr_addr_cmp;
+	u8				nr_cntr;
+	u8				nr_ext_inp;
+	u8				numcidc;
+	u8				numvmidc;
+	u8				nrseqstate;
+	u8				nr_event;
+	u8				nr_resource;
+	u8				nr_ss_cmp;
+	u32				mode;
+	u8				trcid;
+	u8				trcid_size;
+	bool				instrp0;
+	bool				trccond;
+	bool				retstack;
+	bool				trc_error;
+	bool				atbtrig;
+	bool				lpoverride;
+	u32				pe_sel;
+	u32				cfg;
+	u32				eventctrl0;
+	u32				eventctrl1;
+	bool				stallctl;
+	bool				sysstall;
+	bool				nooverflow;
+	u32				stall_ctrl;
+	u8				ts_size;
+	u32				ts_ctrl;
+	bool				syncpr;
+	u32				syncfreq;
+	bool				trccci;
+	u8				ccsize;
+	u8				ccitmin;
+	u32				ccctlr;
+	bool				trcbb;
+	u32				bb_ctrl;
+	bool				q_support;
+	u32				vinst_ctrl;
+	u32				viiectlr;
+	u32				vissctlr;
+	u32				vipcssctlr;
+	u8				seq_idx;
+	u32				seq_ctrl[ETM_MAX_SEQ_STATES];
+	u32				seq_rst;
+	u32				seq_state;
+	u8				cntr_idx;
+	u32				cntrldvr[ETMv4_MAX_CNTR];
+	u32				cntr_ctrl[ETMv4_MAX_CNTR];
+	u32				cntr_val[ETMv4_MAX_CNTR];
+	u8				res_idx;
+	u32				res_ctrl[ETM_MAX_RES_SEL];
+	u32				ss_ctrl[ETM_MAX_SS_CMP];
+	u32				ss_status[ETM_MAX_SS_CMP];
+	u32				ss_pe_cmp[ETM_MAX_SS_CMP];
+	u8				addr_idx;
+	u64				addr_val[ETM_MAX_SINGLE_ADDR_CMP];
+	u64				addr_acc[ETM_MAX_SINGLE_ADDR_CMP];
+	u8				addr_type[ETM_MAX_SINGLE_ADDR_CMP];
+	u8				ctxid_idx;
+	u8				ctxid_size;
+	u64				ctxid_val[ETMv4_MAX_CTXID_CMP];
+	u32				ctxid_mask0;
+	u32				ctxid_mask1;
+	u8				vmid_idx;
+	u8				vmid_size;
+	u64				vmid_val[ETM_MAX_VMID_CMP];
+	u32				vmid_mask0;
+	u32				vmid_mask1;
+	u8				s_ex_level;
+	u8				ns_ex_level;
+	u32				ext_inp;
+};
+
+/* Address comparator access types */
+enum etm_addr_acctype {
+	ETM_INSTR_ADDR,
+	ETM_DATA_LOAD_ADDR,
+	ETM_DATA_STORE_ADDR,
+	ETM_DATA_LOAD_STORE_ADDR,
+};
+
+/* Address comparator context types */
+enum etm_addr_ctxtype {
+	ETM_CTX_NONE,
+	ETM_CTX_CTXID,
+	ETM_CTX_VMID,
+	ETM_CTX_CTXID_VMID,
+};
+
+enum etm_addr_type {
+	ETM_ADDR_TYPE_NONE,
+	ETM_ADDR_TYPE_SINGLE,
+	ETM_ADDR_TYPE_RANGE,
+	ETM_ADDR_TYPE_START,
+	ETM_ADDR_TYPE_STOP,
+};
+#endif
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 00/11] Support for coresight ETMv4 tracer
From: Mathieu Poirier @ 2015-04-29 17:16 UTC (permalink / raw)
  To: gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	kaixu.xia-QSEj5FYQhm4dnm+yROfE0A,
	zhang.chunyan-QSEj5FYQhm4dnm+yROfE0A,
	mathieu.poirier-QSEj5FYQhm4dnm+yROfE0A

Please find in this patchset a driver implementation that conforms
to the coresight framework and provide support for the Embedded
Trace Macrocell version 4.

Regards,
Mathieu

---
Changes for v2:
- Rebased on v4.1-rc1. 
- Fixed mask in the amba_id cells.
- Fixed double pm_runtime_put() in error path. 
---

Pratik Patel (11):
  coresight-etm4x: Adding CoreSight ETM4x driver
  coresight-etm4x: Controls pertaining to tracer configuration
  coresight-etm4x: Controls pertaining to the reset, mode, pe and events
  coresight-etm4x: Controls pertaining to various configuration options
  coresight-etm4x: Controls pertaining to the ViewInst register
  coresight-etm4x: Controls pertaining to the address comparator
    functions
  coresight-etm4x: Controls pertaining to the sequencer functions
  coresight-etm4x: Controls pertaining to the counter functions
  coresight-etm4x: Controls pertaining to the selection of resources
  coresight-etm4x: Controls pertaining to the context ID functions
  coresight-etm4x: Controls pertaining to the VM ID functions

 .../ABI/testing/sysfs-bus-coresight-devices-etm4x  |  295 +++
 drivers/hwtracing/coresight/Kconfig                |   10 +
 drivers/hwtracing/coresight/Makefile               |    1 +
 drivers/hwtracing/coresight/coresight-etm4x.c      | 2744 ++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-etm4x.h      |  391 +++
 5 files changed, 3441 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
 create mode 100644 drivers/hwtracing/coresight/coresight-etm4x.c
 create mode 100644 drivers/hwtracing/coresight/coresight-etm4x.h

-- 
1.9.1

^ permalink raw reply

* Re: [PATCH] usb: core: add usb3 lpm sysfs
From: Zhuang Jin Can @ 2015-04-29 16:21 UTC (permalink / raw)
  To: Greg KH
  Cc: rafael.j.wysocki-ral2JQCrhuEAvxtiuMwx3w,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w, pmladek-AlSwsSmVLrQ,
	peter.chen-KZfg59tc24xl57MIdRCFDg, jwerner-F7+t8E8rja9g9hUCZPvPmw,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150429110622.GA26820-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>

On Wed, Apr 29, 2015 at 01:06:22PM +0200, Greg KH wrote:
> On Wed, Apr 29, 2015 at 06:57:30PM +0800, Zhuang Jin Can wrote:
> > On Wed, Apr 29, 2015 at 11:01:48AM +0200, Greg KH wrote:
> > > On Wed, Apr 29, 2015 at 03:20:04PM +0800, Zhuang Jin Can wrote:
> > > > On Tue, Apr 28, 2015 at 11:11:10PM +0200, Greg KH wrote:
> > > > > On Wed, Apr 29, 2015 at 12:51:27AM +0800, Zhuang Jin Can wrote:
> > > > > > Hi Greg KH,
> > > > > > 
> > > > > > On Tue, Apr 28, 2015 at 12:42:24PM +0200, Greg KH wrote:
> > > > > > > On Sun, Apr 19, 2015 at 11:46:12AM +0800, Zhuang Jin Can wrote:
> > > > > > > > Some usb3 devices may not support usb3 lpm well.
> > > > > > > > The patch adds a sysfs to enable/disable u1 or u2 of the port.The
> > > > > > > > settings apply to both before and after device enumeration.
> > > > > > > > Supported values are "0" - u1 and u2 are disabled, "u1" - only u1 is
> > > > > > > > enabled, "u2" - only u2 is enabled, "u1_u2" - u1 and u2 are enabled.
> > > > > > > > 
> > > > > > > > The interface is useful for testing some USB3 devices during
> > > > > > > > development, and provides a way to disable usb3 lpm if the issues can
> > > > > > > > not be fixed in final products.
> > > > > > > 
> > > > > > > How is a user supposed to "know" to make this setting for a device?  Why
> > > > > > > can't the kernel automatically set this value properly?  Why does it
> > > > > > > need to be a kernel issue at all?
> > > > > > > 
> > > > > > By default kernel enables u1 u2 of all USB3 devices. This interface
> > > > > > provides the user to change this policy. User may set the policy
> > > > > > according to PID/VID of uevent or according to the platform information
> > > > > > known by userspace.
> > > > > 
> > > > > And why would they ever want to do that?
> > > > > 
> > > > > > It's not a kernel issue, as u1 u2 is mandatory by USB3 compliance. But
> > > > > > for some internal hardwired USB3 connection, e.g. SSIC, passing USB3
> > > > > > compliance is not mandatory. So the interface provides a way for vendor
> > > > > > to ship with u1 or u2 broken products. Of course, this is not encouraged :).
> > > > > 
> > > > > If the state is broken for those devices, we can't require the user to
> > > > > fix it for us, the kernel should do it automatically.
> > > > > 
> > > > > > > And when you are doing development of broken devices, the kernel doesn't
> > > > > > > have to support you, you can run with debugging patches of your own
> > > > > > > until you fix your firmware :)
> > > > > > > 
> > > > > > Understood. But I think other vendor or developer may face the same
> > > > > > issue in final product shipment or during development. Moreover, the
> > > > > > interface provide the flexibility for developer to separately
> > > > > > disable/enable u1 or u2, e.g. If they're debugging an u2 issue, they
> > > > > > can disable u1 to simplify the situtation.
> > > > > 
> > > > > For debugging only, perhaps, but for a "normal" user, please let's
> > > > > handle this automatically and don't create a switch that never gets used
> > > > > by anyone or anything.
> > > > > 
> > > > Thanks Greg. Since so far the patch has no interesting value to the
> > > > community, I'll drop the patch.
> > > 
> > > I didn't say that, I said it needed some more work to be accepted.
> > Sorry for misunderstanding. Let me explain more why we need this interface.
> > 
> > We have a modem USB3 device (in stepping C) hardwired to one specific port of xHCI.
> > The device was expected to work with u1 u2, however, due to a HW issue, it doesn't
> > work stably. To workaround the issue, we let the init.rc script disable u1 u2 for
> > this specific port.
> 
> Modern Linux systems don't have init.rc scripts anymore :)
> 
In Android, the init process still reads an init.rc where vendor can
define their own policies. Vendors normally provides a whole reference
design (including HW, FW, Kernel, BSP, AOSP) to OEMs. BSP contains
vendor specific configurations including its own init.rc.

> > Then maybe we want to start debug u1 issue first, to avoid hitting u2 issue,
> > we can disable u2. After u1 issue is resolved, we can enable back u2 to continue to
> > debug u2 issue. This provides the flexibility to isolate u1 u2 debugging.
> > This is valuable I think :)
> 
> I agree.
> 
> > The HW issue will be fixed in stepping D, however C and D will have the same PID/VID.
> > There's no way for kernel to know the difference between C and D.
> > Even after fixing in D, C will still be used for development (to save money..)
> 
> That sounds like a big design flaw, what about looking at the version of
> the device?  That's what that field in the USB descriptors is for.
> 
You're right. bcdDevice should be used for this purpose.
However, since we need to live with what we have, we just used the init.rc to disable
u1/u2. Definitely, it's a ugly hack in userspace to make it "automatically" work.

A better solution is to use monitor uevent, reading bcdDevice + PID/VID, and define
a rule in to disable u1/u2 of this device. Android provides an uevent machanism to do this.

However, how to do it automatically, it's out of the scope of the patch.
Without the patch, the only choice is to add a quirk in usb core to do it automatically. And
this should be in another separate patch.
With the patch:
	1. Userspace can also do the quirk with the help of uevent and rules
	2. Developer can isolate u1 u2 debugging.

And I don't think it's necessary for kernel to support this broken modem. Because, the modem
is integrated with the SoC, and SoC goes with init.rc to OEMs. Thus, it doesn't make sense we
add a quirk in kernel to long term support it. The SoC/Modem is going to be replaced by its next
generation, especially in mobile area.

> > If somehow finally we decide to ship stepping C (suppose HW issue can't be fixed in D in time),
> > we'll have to disable both u1 and u2.
> > 
> > If we fix only u1 issue, we can just disable u2, etc..
> > 
> > To summarize, it provide users an opptunity to change the u1 u2 policy to
> > debug and ship broken products.
> 
> That's good, but you need to do it somehow "automatically", as again,
> systems don't have a init.rc file anymore :)
> 

Thanks
Jincan
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] of: unittest: overlay: Keep track of created overlays
From: Rob Herring @ 2015-04-29 15:55 UTC (permalink / raw)
  To: Pantelis Antoniou
  Cc: Grant Likely, Andrew Morton, Matt Porter, Koen Kooi,
	Guenter Roeck, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-api@vger.kernel.org,
	Pantelis Antoniou
In-Reply-To: <1429868546-19613-1-git-send-email-pantelis.antoniou@konsulko.com>

On Fri, Apr 24, 2015 at 4:42 AM, Pantelis Antoniou
<pantelis.antoniou@konsulko.com> wrote:
> During the course of the overlay selftests some of them remain
> applied. While this does not pose a real problem, make sure you track
> them and destroy them at the end of the test.
>
> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>

This is already in for 4.1. Is this the same as the prior version.

Rob

> ---
>  drivers/of/unittest.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 62 insertions(+)
>
> diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
> index e844907..1801634 100644
> --- a/drivers/of/unittest.c
> +++ b/drivers/of/unittest.c
> @@ -23,6 +23,8 @@
>  #include <linux/i2c.h>
>  #include <linux/i2c-mux.h>
>
> +#include <linux/bitops.h>
> +
>  #include "of_private.h"
>
>  static struct unittest_results {
> @@ -1109,6 +1111,59 @@ static const char *overlay_path(int nr)
>
>  static const char *bus_path = "/testcase-data/overlay-node/test-bus";
>
> +/* it is guaranteed that overlay ids are assigned in sequence */
> +#define MAX_UNITTEST_OVERLAYS  256
> +static unsigned long overlay_id_bits[BITS_TO_LONGS(MAX_UNITTEST_OVERLAYS)];
> +static int overlay_first_id = -1;
> +
> +static void of_unittest_track_overlay(int id)
> +{
> +       if (overlay_first_id < 0)
> +               overlay_first_id = id;
> +       id -= overlay_first_id;
> +
> +       /* we shouldn't need that many */
> +       BUG_ON(id >= MAX_UNITTEST_OVERLAYS);
> +       overlay_id_bits[BIT_WORD(id)] |= BIT_MASK(id);
> +}
> +
> +static void of_unittest_untrack_overlay(int id)
> +{
> +       if (overlay_first_id < 0)
> +               return;
> +       id -= overlay_first_id;
> +       BUG_ON(id >= MAX_UNITTEST_OVERLAYS);
> +       overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
> +}
> +
> +static void of_unittest_destroy_tracked_overlays(void)
> +{
> +       int id, ret, defers;
> +
> +       if (overlay_first_id < 0)
> +               return;
> +
> +       /* try until no defers */
> +       do {
> +               defers = 0;
> +               /* remove in reverse order */
> +               for (id = MAX_UNITTEST_OVERLAYS - 1; id >= 0; id--) {
> +                       if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id)))
> +                               continue;
> +
> +                       ret = of_overlay_destroy(id + overlay_first_id);
> +                       if (ret != 0) {
> +                               defers++;
> +                               pr_warn("%s: overlay destroy failed for #%d\n",
> +                                       __func__, id + overlay_first_id);
> +                               continue;
> +                       }
> +
> +                       overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
> +               }
> +       } while (defers > 0);
> +}
> +
>  static int of_unittest_apply_overlay(int unittest_nr, int overlay_nr,
>                 int *overlay_id)
>  {
> @@ -1130,6 +1185,7 @@ static int of_unittest_apply_overlay(int unittest_nr, int overlay_nr,
>                 goto out;
>         }
>         id = ret;
> +       of_unittest_track_overlay(id);
>
>         ret = 0;
>
> @@ -1343,6 +1399,7 @@ static void of_unittest_overlay_6(void)
>                         return;
>                 }
>                 ov_id[i] = ret;
> +               of_unittest_track_overlay(ov_id[i]);
>         }
>
>         for (i = 0; i < 2; i++) {
> @@ -1367,6 +1424,7 @@ static void of_unittest_overlay_6(void)
>                                                 PDEV_OVERLAY));
>                         return;
>                 }
> +               of_unittest_untrack_overlay(ov_id[i]);
>         }
>
>         for (i = 0; i < 2; i++) {
> @@ -1411,6 +1469,7 @@ static void of_unittest_overlay_8(void)
>                         return;
>                 }
>                 ov_id[i] = ret;
> +               of_unittest_track_overlay(ov_id[i]);
>         }
>
>         /* now try to remove first overlay (it should fail) */
> @@ -1433,6 +1492,7 @@ static void of_unittest_overlay_8(void)
>                                                 PDEV_OVERLAY));
>                         return;
>                 }
> +               of_unittest_untrack_overlay(ov_id[i]);
>         }
>
>         unittest(1, "overlay test %d passed\n", 8);
> @@ -1855,6 +1915,8 @@ static void __init of_unittest_overlay(void)
>         of_unittest_overlay_i2c_cleanup();
>  #endif
>
> +       of_unittest_destroy_tracked_overlays();
> +
>  out:
>         of_node_put(bus_np);
>  }
> --
> 1.7.12
>

^ permalink raw reply

* Re: [RFC v2 1/4] fs: Add generic file system event notifications
From: Greg KH @ 2015-04-29 15:55 UTC (permalink / raw)
  To: Beata Michalska
  Cc: Jan Kara, linux-kernel, linux-fsdevel, linux-api, tytso,
	adilger.kernel, hughd, lczerner, hch, linux-ext4, linux-mm,
	kyungmin.park, kmpark
In-Reply-To: <5540FD3E.9050801@samsung.com>

On Wed, Apr 29, 2015 at 05:48:14PM +0200, Beata Michalska wrote:
> On 04/29/2015 03:45 PM, Greg KH wrote:
> > On Wed, Apr 29, 2015 at 01:10:34PM +0200, Beata Michalska wrote:
> >>>>> It needs to be done internally by the app but is doable.
> >>>>> The app knows what it is watching, so it can maintain the mappings.
> >>>>> So prior to activating the notifications it can call 'stat' on the mount point.
> >>>>> Stat struct gives the 'st_dev' which is the device id. Same will be reported
> >>>>> within the message payload (through major:minor numbers). So having this,
> >>>>> the app is able to get any other information it needs. 
> >>>>> Note that the events refer to the file system as a whole and they may not
> >>>>> necessarily have anything to do with the actual block device. 
> >>>
> >>> How are you going to show an event for a filesystem that is made up of
> >>> multiple block devices?
> >>
> >> AFAIK, for such filesystems there will be similar case with the anonymous
> >> major:minor numbers - at least the btrfs is doing so. Not sure we can
> >> differentiate here the actual block device. So in this case such events
> >> serves merely as a hint for the userspace.
> > 
> > "hint" seems like this isn't really going to work well.
> > 
> > Do you have userspace code that can properly map this back to the "real"
> > device that is causing problems?  Without that, this doesn't seem all
> > that useful as no one would be able to use those events.
> 
> I'm not sure we are on the same page here.
> This is about watching the file system rather than the 'real' device.
> Like the threshold notifications: you would like to know when you
> will be approaching certain level of available space for the tmpfs
> mounted on /tmp.  You do know you are watching the /tmp
> and you know that the dev numbers for this are 0:20 (or so). 
> (either through calling stat on /tmp or through reading the /proc/$$/mountinfo)
> With this interface you can setup threshold levels
> for /tmp. Then, once the limit is reached the event will be
> sent with those anonymous major:minor numbers.
> 
> I can provide a sample code which will demonstrate how this
> can be achieved.

Yes, example code would be helpful to understand this, thanks.

greg k-h

^ permalink raw reply

* Re: [RFC v2 1/4] fs: Add generic file system event notifications
From: Beata Michalska @ 2015-04-29 15:48 UTC (permalink / raw)
  To: Greg KH
  Cc: Jan Kara, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
	adilger.kernel-m1MBpc4rdrD3fQ9qLvQP4Q,
	hughd-hpIqsD4AKlfQT0dZR+AlfA, lczerner-H+wXaHxf7aLQT0dZR+AlfA,
	hch-wEGCiKHe2LqWVfeAwA7xHQ, linux-ext4-u79uwXL29TY76Z2rM5mHXA,
	linux-mm-Bw31MaZKKs3YtjvyW6yDsg,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	kmpark-wEGCiKHe2LqWVfeAwA7xHQ
In-Reply-To: <20150429134505.GB15398-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>

On 04/29/2015 03:45 PM, Greg KH wrote:
> On Wed, Apr 29, 2015 at 01:10:34PM +0200, Beata Michalska wrote:
>>>>> It needs to be done internally by the app but is doable.
>>>>> The app knows what it is watching, so it can maintain the mappings.
>>>>> So prior to activating the notifications it can call 'stat' on the mount point.
>>>>> Stat struct gives the 'st_dev' which is the device id. Same will be reported
>>>>> within the message payload (through major:minor numbers). So having this,
>>>>> the app is able to get any other information it needs. 
>>>>> Note that the events refer to the file system as a whole and they may not
>>>>> necessarily have anything to do with the actual block device. 
>>>
>>> How are you going to show an event for a filesystem that is made up of
>>> multiple block devices?
>>
>> AFAIK, for such filesystems there will be similar case with the anonymous
>> major:minor numbers - at least the btrfs is doing so. Not sure we can
>> differentiate here the actual block device. So in this case such events
>> serves merely as a hint for the userspace.
> 
> "hint" seems like this isn't really going to work well.
> 
> Do you have userspace code that can properly map this back to the "real"
> device that is causing problems?  Without that, this doesn't seem all
> that useful as no one would be able to use those events.

I'm not sure we are on the same page here.
This is about watching the file system rather than the 'real' device.
Like the threshold notifications: you would like to know when you
will be approaching certain level of available space for the tmpfs
mounted on /tmp.  You do know you are watching the /tmp
and you know that the dev numbers for this are 0:20 (or so). 
(either through calling stat on /tmp or through reading the /proc/$$/mountinfo)
With this interface you can setup threshold levels
for /tmp. Then, once the limit is reached the event will be
sent with those anonymous major:minor numbers.

I can provide a sample code which will demonstrate how this
can be achieved.

> 
>> At this point a user might decide to run some scanning tools.
> 
> You can't run a scanning tool on a tmpfs :)

I was referring to btrfs here as a filesystem with multiple devices
and its btrfs device scan :)
> 
> So what can a user do with information about one of these "virtual"
> filesystems that it can't directly see or access?
> 
>> We might extend the scope of the
>> info being sent, though I would consider this as a nice-to-have but not
>> required for this initial version of notifications. The filesystems
>> might also want to decide to send their own custom messages so it is
>> possible for filesystems like btrfs to send more detailed information
>> using the new genetlink multicast group.
>>>>   Or you can use /proc/self/mountinfo for the mapping. There you can see
>>>> device numbers, real device names if applicable and mountpoints. This has
>>>> the advantage that it works even if filesystem mountpoints change.
>>>
>>> Ok, then that brings up my next question, how does this handle
>>> namespaces?  What namespace is the event being sent in?  block devices
>>> aren't namespaced, but the mount points are, is that going to cause
>>> problems?
>>>
>>
>> The path should get resolved properly (as from root level). though I must
>> admit I'm not sure if there will be no issues when it comes to the network
>> namespaces. I'll double check it. Any hints though are more than welcomed :)
> 
> What is "root level" here?  You can mount things in different namespaces
> all over the place.

I was referring here to the mounts visibility and the mount propagation
which on some distros is set by default with the make-shared option,
so the mounts created in new namespace are visible outside of it (running
cat /proc/$$/moutinfo showed the new mounts). Which got me really
confused, obviously.

> 
> This is going to get really complex very quickly :(

It will/is indeed - still I believe it's worth giving it a try.
I'll try to work out the namespace issue here and get back to you.

BR
Beata
> 
> I still think you should tie this to an existing sysfs device, which
> handles the namespace issues for you, and it also handles the fact that
> userspace can properly identify the device, if at all possible.
> 

> thanks,
> 
> greg k-h
> 

^ permalink raw reply

* Re: Regression: Requiring CAP_SYS_ADMIN for /proc/<pid>/pagemap causes application-level breakage
From: Mark Williamson @ 2015-04-29 14:38 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Linus Torvalds, Linux Kernel Mailing List, Kirill A. Shutemov,
	Pavel Emelyanov, Konstantin Khlebnikov, Andrew Morton,
	Mark Seaborn, Linux API, Finn Grimwood, Daniel James
In-Reply-To: <CALCETrUkkbZaNGkcZMenciC7o9BO7U52LPXQwT+Q5TT8W2=uKQ@mail.gmail.com>

Hi Andy,

On Fri, Apr 24, 2015 at 5:10 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> Even though I've been accused (correctly?) of suggesting that, I'm not
> sure I like it anymore.  Suppose I map some anonymous memory, learn
> its (scrambled) pfn, then unmap it and remap a setuid file.  Now I can
> tell whether I've mapped the setuid file at the same pfn that was
> mapped as my anonymous memory.  IIRC that's sufficient for one of the
> variants of Mark's attack.

In fairness, you may have mentioned it but it's entirely possible you
didn't originate the suggestion and I quoted out of context.  Sorry
for implicating you ;-)

That's an attack that I hadn't considered when thinking about this
stuff.  Zeroing the page frame numbers is an easier patch, so
arguments in favour of that are a happy answer as far as I'm
concerned!

Thanks,
Mark

^ permalink raw reply

* Re: [RFC v2 1/4] fs: Add generic file system event notifications
From: Greg KH @ 2015-04-29 13:45 UTC (permalink / raw)
  To: Beata Michalska
  Cc: Jan Kara, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
	adilger.kernel-m1MBpc4rdrD3fQ9qLvQP4Q,
	hughd-hpIqsD4AKlfQT0dZR+AlfA, lczerner-H+wXaHxf7aLQT0dZR+AlfA,
	hch-wEGCiKHe2LqWVfeAwA7xHQ, linux-ext4-u79uwXL29TY76Z2rM5mHXA,
	linux-mm-Bw31MaZKKs3YtjvyW6yDsg,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	kmpark-wEGCiKHe2LqWVfeAwA7xHQ
In-Reply-To: <5540BC2A.8010504-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

On Wed, Apr 29, 2015 at 01:10:34PM +0200, Beata Michalska wrote:
> >>> It needs to be done internally by the app but is doable.
> >>> The app knows what it is watching, so it can maintain the mappings.
> >>> So prior to activating the notifications it can call 'stat' on the mount point.
> >>> Stat struct gives the 'st_dev' which is the device id. Same will be reported
> >>> within the message payload (through major:minor numbers). So having this,
> >>> the app is able to get any other information it needs. 
> >>> Note that the events refer to the file system as a whole and they may not
> >>> necessarily have anything to do with the actual block device. 
> > 
> > How are you going to show an event for a filesystem that is made up of
> > multiple block devices?
> 
> AFAIK, for such filesystems there will be similar case with the anonymous
> major:minor numbers - at least the btrfs is doing so. Not sure we can
> differentiate here the actual block device. So in this case such events
> serves merely as a hint for the userspace.

"hint" seems like this isn't really going to work well.

Do you have userspace code that can properly map this back to the "real"
device that is causing problems?  Without that, this doesn't seem all
that useful as no one would be able to use those events.

> At this point a user might decide to run some scanning tools.

You can't run a scanning tool on a tmpfs :)

So what can a user do with information about one of these "virtual"
filesystems that it can't directly see or access?

> We might extend the scope of the
> info being sent, though I would consider this as a nice-to-have but not
> required for this initial version of notifications. The filesystems
> might also want to decide to send their own custom messages so it is
> possible for filesystems like btrfs to send more detailed information
> using the new genetlink multicast group.
> >>   Or you can use /proc/self/mountinfo for the mapping. There you can see
> >> device numbers, real device names if applicable and mountpoints. This has
> >> the advantage that it works even if filesystem mountpoints change.
> > 
> > Ok, then that brings up my next question, how does this handle
> > namespaces?  What namespace is the event being sent in?  block devices
> > aren't namespaced, but the mount points are, is that going to cause
> > problems?
> > 
> 
> The path should get resolved properly (as from root level). though I must
> admit I'm not sure if there will be no issues when it comes to the network
> namespaces. I'll double check it. Any hints though are more than welcomed :)

What is "root level" here?  You can mount things in different namespaces
all over the place.

This is going to get really complex very quickly :(

I still think you should tie this to an existing sysfs device, which
handles the namespace issues for you, and it also handles the fact that
userspace can properly identify the device, if at all possible.

thanks,

greg k-h

^ permalink raw reply

* [RFC PATCH] mmap.2: clarify MAP_LOCKED semantic (was: Re: Should mmap MAP_LOCKED fail if mm_poppulate fails?)
From: Michal Hocko @ 2015-04-29 11:38 UTC (permalink / raw)
  To: Linus Torvalds, Michael Kerrisk
  Cc: linux-mm, Cyril Hrubis, Andrew Morton, Hugh Dickins,
	Michel Lespinasse, Rik van Riel, LKML, Linux API
In-Reply-To: <CA+55aFyajquhGhw59qNWKGK4dBV0TPmDD7-1XqPo7DZWvO_hPg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Tue 28-04-15 11:38:35, Linus Torvalds wrote:
> On Tue, Apr 28, 2015 at 11:35 AM, Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org> wrote:
> >
> > I am still not sure I see the problem here.
> 
> Basically, I absolutely hate the notion of us doing something
> unsynchronized, when I can see us undoing a mmap that another thread
> is doing. It's wrong.

OK, I have checked the mmap(2) man page and there is no single mention
about multi-threaded usage. So even though I personally think that
user fault handlers which do mmap(MAP_FIXED) without synchronization
to parallel mmaps are broken by definition we cannot simply rule them
out and it is not the kernel job to make them broken even more or in a
subtly different way.
So here is an RFC for the man page patch. I am not very good in the
format but man doesn't complain about any formating issues.
---
>From 903ed733187afaa4d27fef3c24f413304494411c Mon Sep 17 00:00:00 2001
From: Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org>
Date: Wed, 29 Apr 2015 11:02:19 +0200
Subject: [RFC PATCH] mmap.2: clarify MAP_LOCKED semantic

MAP_LOCKED had a subtly different semantic from mmap(2)+mlock(2) since
it has been introduced.
mlock(2) fails if the memory range cannot get populated to guarantee
that no future major faults will happen on the range. mmap(MAP_LOCKED) on
the other hand silently succeeds even if the range was populated only
partially.

Fixing this subtle difference in the kernel is rather awkward because
the memory population happens after mm locks have been dropped and so
the cleanup before returning failure (munlock) could operate on something
else than the originally mapped area.

E.g. speculative userspace page fault handler catching SEGV and doing
mmap(fault_addr, MAP_FIXED|MAP_LOCKED) might discard portion of a racing
mmap and lead to lost data. Although it is not clear whether such a
usage would be valid, mmap page doesn't explicitly describe requirements
for threaded applications so we cannot exclude this possibility.

This patch makes the semantic of MAP_LOCKED explicit and suggest using
mmap + mlock as the only way to guarantee no later major page faults.

Signed-off-by: Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org>
---
 man2/mmap.2 | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/man2/mmap.2 b/man2/mmap.2
index 54d68cf87e9e..1486be2e96b3 100644
--- a/man2/mmap.2
+++ b/man2/mmap.2
@@ -235,8 +235,19 @@ See the Linux kernel source file
 for further information.
 .TP
 .BR MAP_LOCKED " (since Linux 2.5.37)"
-Lock the pages of the mapped region into memory in the manner of
+Mark the mmaped region to be locked in the same way as
 .BR mlock (2).
+This implementation will try to populate (prefault) the whole range but
+the mmap call doesn't fail with
+.B ENOMEM
+if this fails. Therefore major faults might happen later on. So the semantic
+is not as strong as
+.BR mlock (2).
+.BR mmap (2)
++
+.BR mlock (2)
+should be used when major faults are not acceptable after the initialization
+of the mapping.
 This flag is ignored in older kernels.
 .\" If set, the mapped pages will not be swapped out.
 .TP
-- 
2.1.4

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply related

* [RFC PATCH 3/3] iio: accel: bmc150: add support for hwfifo_flush and flush events
From: Octavian Purdila @ 2015-04-29 11:19 UTC (permalink / raw)
  To: jic23
  Cc: knaack.h, lars, pmeerw, linux-iio, linux-kernel, adriana.reus,
	linux-api, Octavian Purdila
In-Reply-To: <1430306340-5026-1-git-send-email-octavian.purdila@intel.com>

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/iio/accel/bmc150-accel.c | 68 ++++++++++++++++++++++++++++++----------
 1 file changed, 51 insertions(+), 17 deletions(-)

diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index b4ca361..0c5fdf6 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -870,19 +870,6 @@ static ssize_t bmc150_accel_get_fifo_state(struct device *dev,
 	return sprintf(buf, "%d\n", state);
 }
 
-static IIO_CONST_ATTR_HWFIFO_WATERMARK_MIN(1);
-static IIO_CONST_ATTR_HWFIFO_WATERMARK_MAX(BMC150_ACCEL_FIFO_LENGTH);
-static IIO_DEV_ATTR_HWFIFO_ENABLED(bmc150_accel_get_fifo_state);
-static IIO_DEV_ATTR_HWFIFO_WATERMARK(bmc150_accel_get_fifo_watermark);
-
-static const struct attribute *bmc150_accel_fifo_attributes[] = {
-	&iio_const_attr_hwfifo_watermark_min.dev_attr.attr,
-	&iio_const_attr_hwfifo_watermark_max.dev_attr.attr,
-	&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
-	&iio_dev_attr_hwfifo_enabled.dev_attr.attr,
-	NULL,
-};
-
 static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val)
 {
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
@@ -952,7 +939,8 @@ static int bmc150_accel_fifo_transfer(const struct i2c_client *client,
 }
 
 static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
-				     unsigned samples, bool irq)
+				     unsigned samples, bool irq,
+				     bool event)
 {
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
 	int ret, i;
@@ -1030,6 +1018,12 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
 		tstamp += sample_period;
 	}
 
+	if (event)
+		iio_push_event(indio_dev,
+			       IIO_UNMOD_EVENT_CODE(IIO_ACCEL, 0,
+						    IIO_EV_TYPE_HWFIFO_FLUSHED,
+						    IIO_EV_DIR_NONE),
+			       tstamp);
 	return count;
 }
 
@@ -1039,12 +1033,50 @@ static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev, unsigned samples)
 	int ret;
 
 	mutex_lock(&data->mutex);
-	ret = __bmc150_accel_fifo_flush(indio_dev, samples, false);
+	ret = __bmc150_accel_fifo_flush(indio_dev, samples, false, false);
 	mutex_unlock(&data->mutex);
 
 	return ret;
 }
 
+static ssize_t bmc150_accel_sysfs_fifo_flush(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf,
+					     size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	unsigned int samples;
+	int ret;
+
+	ret = kstrtouint(buf, 10, &samples);
+	if (ret)
+		return ret;
+	if (!samples)
+		return -EINVAL;
+
+	mutex_lock(&data->mutex);
+	ret = __bmc150_accel_fifo_flush(indio_dev, samples, false, true);
+	mutex_unlock(&data->mutex);
+
+	return ret ? ret : len;
+}
+
+static IIO_CONST_ATTR_HWFIFO_WATERMARK_MIN(1);
+static IIO_CONST_ATTR_HWFIFO_WATERMARK_MAX(BMC150_ACCEL_FIFO_LENGTH);
+static IIO_DEV_ATTR_HWFIFO_ENABLED(bmc150_accel_get_fifo_state);
+static IIO_DEV_ATTR_HWFIFO_WATERMARK(bmc150_accel_get_fifo_watermark);
+static IIO_DEV_ATTR_HWFIFO_FLUSH(bmc150_accel_sysfs_fifo_flush);
+
+static const struct attribute *bmc150_accel_fifo_attributes[] = {
+	&iio_const_attr_hwfifo_watermark_min.dev_attr.attr,
+	&iio_const_attr_hwfifo_watermark_max.dev_attr.attr,
+	&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
+	&iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+	&iio_dev_attr_hwfifo_flush.dev_attr.attr,
+	NULL,
+};
+
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
 		"15.620000 31.260000 62.50000 125 250 500 1000 2000");
 
@@ -1346,7 +1378,8 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private)
 
 	if (data->fifo_mode) {
 		ret = __bmc150_accel_fifo_flush(indio_dev,
-						BMC150_ACCEL_FIFO_LENGTH, true);
+						BMC150_ACCEL_FIFO_LENGTH, true,
+						false);
 		if (ret > 0)
 			ack = true;
 	}
@@ -1578,7 +1611,8 @@ static int bmc150_accel_buffer_predisable(struct iio_dev *indio_dev)
 		goto out;
 
 	bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, false);
-	__bmc150_accel_fifo_flush(indio_dev, BMC150_ACCEL_FIFO_LENGTH, false);
+	__bmc150_accel_fifo_flush(indio_dev, BMC150_ACCEL_FIFO_LENGTH, false,
+				  false);
 	data->fifo_mode = 0;
 	bmc150_accel_fifo_set_mode(data);
 
-- 
1.9.1

^ permalink raw reply related

* [RFC PATCH 2/3] iio: allow better control for flushing the hardware fifo
From: Octavian Purdila @ 2015-04-29 11:18 UTC (permalink / raw)
  To: jic23-DgEjT+Ai2ygdnm+yROfE0A
  Cc: knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	adriana.reus-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA, Octavian Purdila
In-Reply-To: <1430306340-5026-1-git-send-email-octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>

Some applications need to be able to flush [1] the hardware fifo of
the device and to receive events of when that happened [2] so that it
can ignore stale data.

This patch adds a new event (IIO_EV_TYPE_HWFIFO_FLUSHED) that should
be sent to userspace when a flush has been completed. The application
will be able to identify which are the samples to ignore based on the
timestamp of the event.

To allow applications to accurately generate a hardware fifo flush on
demand, this patch also adds a new sysfs entry that triggers a
hardware fifo flush when written to.

[1] https://source.android.com/devices/sensors/hal-interface.html#flush_sensor
[2] https://source.android.com/devices/sensors/hal-interface.html#metadata_flush_complete_events

Signed-off-by: Octavian Purdila <octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
 Documentation/ABI/testing/sysfs-bus-iio | 11 +++++++++++
 include/linux/iio/sysfs.h               |  3 +++
 include/uapi/linux/iio/types.h          |  1 +
 3 files changed, 15 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 866b4ec..bb4d8de 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -1375,3 +1375,14 @@ Description:
 		The emissivity ratio of the surface in the field of view of the
 		contactless temperature sensor.  Emissivity varies from 0 to 1,
 		with 1 being the emissivity of a black body.
+
+What:		/sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_flush
+KernelVersion:	4.2
+Contact:	linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+Description:
+		Write only entry that accepts a single strictly positive integer
+		specifying the number of samples to flush from the hardware fifo
+		to the device buffer. When the flush is completed an
+		IIO_EV_TYPE_HWFIFO_FLUSHED event is generated. The event has the
+		timestamp equal with the timestamp of last sample that was
+		flushed from the hardware fifo.
diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h
index 8822bab..8fcc25b 100644
--- a/include/linux/iio/sysfs.h
+++ b/include/linux/iio/sysfs.h
@@ -136,4 +136,7 @@ struct iio_const_attr {
 #define IIO_DEV_ATTR_HWFIFO_WATERMARK(_hwfifo_get_wm)	\
 	IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO, _hwfifo_get_wm, NULL, 0)
 
+#define IIO_DEV_ATTR_HWFIFO_FLUSH(_hwfifo_flush)	\
+	IIO_DEVICE_ATTR(hwfifo_flush, S_IWUSR, NULL, _hwfifo_flush, 0)
+
 #endif /* _INDUSTRIAL_IO_SYSFS_H_ */
diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h
index 5c46019..4600157 100644
--- a/include/uapi/linux/iio/types.h
+++ b/include/uapi/linux/iio/types.h
@@ -79,6 +79,7 @@ enum iio_event_type {
 	IIO_EV_TYPE_THRESH_ADAPTIVE,
 	IIO_EV_TYPE_MAG_ADAPTIVE,
 	IIO_EV_TYPE_CHANGE,
+	IIO_EV_TYPE_HWFIFO_FLUSHED,
 };
 
 enum iio_event_direction {
-- 
1.9.1

^ permalink raw reply related

* [RFC PATCH 1/3] iio: add hwfifo attributes helpers
From: Octavian Purdila @ 2015-04-29 11:18 UTC (permalink / raw)
  To: jic23-DgEjT+Ai2ygdnm+yROfE0A
  Cc: knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	adriana.reus-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA, Octavian Purdila
In-Reply-To: <1430306340-5026-1-git-send-email-octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>

Signed-off-by: Octavian Purdila <octavian.purdila-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
 drivers/iio/accel/bmc150-accel.c | 11 ++++-------
 include/linux/iio/sysfs.h        | 12 ++++++++++++
 2 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index 73e8773..b4ca361 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -870,13 +870,10 @@ static ssize_t bmc150_accel_get_fifo_state(struct device *dev,
 	return sprintf(buf, "%d\n", state);
 }
 
-static IIO_CONST_ATTR(hwfifo_watermark_min, "1");
-static IIO_CONST_ATTR(hwfifo_watermark_max,
-		      __stringify(BMC150_ACCEL_FIFO_LENGTH));
-static IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO,
-		       bmc150_accel_get_fifo_state, NULL, 0);
-static IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO,
-		       bmc150_accel_get_fifo_watermark, NULL, 0);
+static IIO_CONST_ATTR_HWFIFO_WATERMARK_MIN(1);
+static IIO_CONST_ATTR_HWFIFO_WATERMARK_MAX(BMC150_ACCEL_FIFO_LENGTH);
+static IIO_DEV_ATTR_HWFIFO_ENABLED(bmc150_accel_get_fifo_state);
+static IIO_DEV_ATTR_HWFIFO_WATERMARK(bmc150_accel_get_fifo_watermark);
 
 static const struct attribute *bmc150_accel_fifo_attributes[] = {
 	&iio_const_attr_hwfifo_watermark_min.dev_attr.attr,
diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h
index 8a1d186..8822bab 100644
--- a/include/linux/iio/sysfs.h
+++ b/include/linux/iio/sysfs.h
@@ -124,4 +124,16 @@ struct iio_const_attr {
 #define IIO_CONST_ATTR_TEMP_SCALE(_string)		\
 	IIO_CONST_ATTR(in_temp_scale, _string)
 
+#define IIO_CONST_ATTR_HWFIFO_WATERMARK_MIN(_min)	\
+	IIO_CONST_ATTR(hwfifo_watermark_min, __stringify(_min))
+
+#define IIO_CONST_ATTR_HWFIFO_WATERMARK_MAX(_max)	\
+	IIO_CONST_ATTR(hwfifo_watermark_max, __stringify(_max))
+
+#define IIO_DEV_ATTR_HWFIFO_ENABLED(_hwfifo_get_state)	\
+	IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO, _hwfifo_get_state, NULL, 0)
+
+#define IIO_DEV_ATTR_HWFIFO_WATERMARK(_hwfifo_get_wm)	\
+	IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO, _hwfifo_get_wm, NULL, 0)
+
 #endif /* _INDUSTRIAL_IO_SYSFS_H_ */
-- 
1.9.1

^ permalink raw reply related

* [RFC PATCH 0/3] allow better control for flushing the hardware fifo
From: Octavian Purdila @ 2015-04-29 11:18 UTC (permalink / raw)
  To: jic23-DgEjT+Ai2ygdnm+yROfE0A
  Cc: knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	adriana.reus-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA, Octavian Purdila

Hi Jonathan,

The first patch is a small enhancement that makes it easier to add
hwfifo support in drivers.

The other two are adding new ABIs to allow on demand trigger of a
hardware fifo flush operation and to signal when the flush operation
has been completed. The user for this interface is Android's sensor
HAL.

Thanks,
Tavi

Octavian Purdila (3):
  iio: add hwfifo attributes helpers
  iio: allow better control for flushing the hardware fifo
  iio: accel: bmc150: add support for hwfifo_flush and flush events

 Documentation/ABI/testing/sysfs-bus-iio | 11 +++++
 drivers/iio/accel/bmc150-accel.c        | 71 +++++++++++++++++++++++----------
 include/linux/iio/sysfs.h               | 15 +++++++
 include/uapi/linux/iio/types.h          |  1 +
 4 files changed, 78 insertions(+), 20 deletions(-)

-- 
1.9.1

^ permalink raw reply

* Re: [RFC v2 1/4] fs: Add generic file system event notifications
From: Beata Michalska @ 2015-04-29 11:10 UTC (permalink / raw)
  To: Greg KH
  Cc: Jan Kara, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
	adilger.kernel-m1MBpc4rdrD3fQ9qLvQP4Q,
	hughd-hpIqsD4AKlfQT0dZR+AlfA, lczerner-H+wXaHxf7aLQT0dZR+AlfA,
	hch-wEGCiKHe2LqWVfeAwA7xHQ, linux-ext4-u79uwXL29TY76Z2rM5mHXA,
	linux-mm-Bw31MaZKKs3YtjvyW6yDsg,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	kmpark-wEGCiKHe2LqWVfeAwA7xHQ
In-Reply-To: <20150429091303.GA4090-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>

On 04/29/2015 11:13 AM, Greg KH wrote:
> On Wed, Apr 29, 2015 at 09:42:59AM +0200, Jan Kara wrote:
>> On Wed 29-04-15 09:03:08, Beata Michalska wrote:
>>> On 04/28/2015 07:39 PM, Greg KH wrote:
>>>> On Tue, Apr 28, 2015 at 04:46:46PM +0200, Beata Michalska wrote:
>>>>> On 04/28/2015 04:09 PM, Greg KH wrote:
>>>>>> On Tue, Apr 28, 2015 at 03:56:53PM +0200, Jan Kara wrote:
>>>>>>> On Mon 27-04-15 17:37:11, Greg KH wrote:
>>>>>>>> On Mon, Apr 27, 2015 at 05:08:27PM +0200, Beata Michalska wrote:
>>>>>>>>> On 04/27/2015 04:24 PM, Greg KH wrote:
>>>>>>>>>> On Mon, Apr 27, 2015 at 01:51:41PM +0200, Beata Michalska wrote:
>>>>>>>>>>> Introduce configurable generic interface for file
>>>>>>>>>>> system-wide event notifications, to provide file
>>>>>>>>>>> systems with a common way of reporting any potential
>>>>>>>>>>> issues as they emerge.
>>>>>>>>>>>
>>>>>>>>>>> The notifications are to be issued through generic
>>>>>>>>>>> netlink interface by newly introduced multicast group.
>>>>>>>>>>>
>>>>>>>>>>> Threshold notifications have been included, allowing
>>>>>>>>>>> triggering an event whenever the amount of free space drops
>>>>>>>>>>> below a certain level - or levels to be more precise as two
>>>>>>>>>>> of them are being supported: the lower and the upper range.
>>>>>>>>>>> The notifications work both ways: once the threshold level
>>>>>>>>>>> has been reached, an event shall be generated whenever
>>>>>>>>>>> the number of available blocks goes up again re-activating
>>>>>>>>>>> the threshold.
>>>>>>>>>>>
>>>>>>>>>>> The interface has been exposed through a vfs. Once mounted,
>>>>>>>>>>> it serves as an entry point for the set-up where one can
>>>>>>>>>>> register for particular file system events.
>>>>>>>>>>>
>>>>>>>>>>> Signed-off-by: Beata Michalska <b.michalska-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>>>>>>>>>>> ---
>>>>>>>>>>>  Documentation/filesystems/events.txt |  231 ++++++++++
>>>>>>>>>>>  fs/Makefile                          |    1 +
>>>>>>>>>>>  fs/events/Makefile                   |    6 +
>>>>>>>>>>>  fs/events/fs_event.c                 |  770 ++++++++++++++++++++++++++++++++++
>>>>>>>>>>>  fs/events/fs_event.h                 |   25 ++
>>>>>>>>>>>  fs/events/fs_event_netlink.c         |   99 +++++
>>>>>>>>>>>  fs/namespace.c                       |    1 +
>>>>>>>>>>>  include/linux/fs.h                   |    6 +-
>>>>>>>>>>>  include/linux/fs_event.h             |   58 +++
>>>>>>>>>>>  include/uapi/linux/fs_event.h        |   54 +++
>>>>>>>>>>>  include/uapi/linux/genetlink.h       |    1 +
>>>>>>>>>>>  net/netlink/genetlink.c              |    7 +-
>>>>>>>>>>>  12 files changed, 1257 insertions(+), 2 deletions(-)
>>>>>>>>>>>  create mode 100644 Documentation/filesystems/events.txt
>>>>>>>>>>>  create mode 100644 fs/events/Makefile
>>>>>>>>>>>  create mode 100644 fs/events/fs_event.c
>>>>>>>>>>>  create mode 100644 fs/events/fs_event.h
>>>>>>>>>>>  create mode 100644 fs/events/fs_event_netlink.c
>>>>>>>>>>>  create mode 100644 include/linux/fs_event.h
>>>>>>>>>>>  create mode 100644 include/uapi/linux/fs_event.h
>>>>>>>>>>
>>>>>>>>>> Any reason why you just don't do uevents for the block devices today,
>>>>>>>>>> and not create a new type of netlink message and userspace tool required
>>>>>>>>>> to read these?
>>>>>>>>>
>>>>>>>>> The idea here is to have support for filesystems with no backing device as well.
>>>>>>>>> Parsing the message with libnl is really simple and requires few lines of code
>>>>>>>>> (sample application has been presented in the initial version of this RFC)
>>>>>>>>
>>>>>>>> I'm not saying it's not "simple" to parse, just that now you are doing
>>>>>>>> something that requires a different tool.  If you have a block device,
>>>>>>>> you should be able to emit uevents for it, you don't need a backing
>>>>>>>> device, we handle virtual filesystems in /sys/block/ just fine :)
>>>>>>>>
>>>>>>>> People already have tools that listen to libudev for system monitoring
>>>>>>>> and management, why require them to hook up to yet-another-library?  And
>>>>>>>> what is going to provide the ability for multiple userspace tools to
>>>>>>>> listen to these netlink messages in case you have more than one program
>>>>>>>> that wants to watch for these things (i.e. multiple desktop filesystem
>>>>>>>> monitoring tools, system-health checkers, etc.)?
>>>>>>>   As much as I understand your concerns I'm not convinced uevent interface
>>>>>>> is a good fit. There are filesystems that don't have underlying block
>>>>>>> device - think of e.g. tmpfs or filesystems working directly on top of
>>>>>>> flash devices.  These still want to send notification to userspace (one of
>>>>>>> primary motivation for this interfaces was so that tmpfs can notify about
>>>>>>> something). And creating some fake nodes in /sys/block for tmpfs and
>>>>>>> similar filesystems seems like doing more harm than good to me...
>>>>>>
>>>>>> If these are "fake" block devices, what's going to be present in the
>>>>>> block major/minor fields of the netlink message?  For some reason I
>>>>>> thought it was a required field, and because of that, I thought we had a
>>>>>> "real" filesystem somewhere to refer to, otherwise how would userspace
>>>>>> know what filesystem was creating these events?
>>>>>>
>>>>>> What am I missing here?
>>>>>>
>>>>>> confused,
>>>>>>
>>>>>> greg k-h
>>>>>>
>>>>>
>>>>> For those 'fake' block devs, upon mount, get_anon_bdev will assign
>>>>> the major:minor numbers. Userspace might get those through stat.
>>>>
>>>> How can userspace do the mapping backwards from this "anonymous"
>>>> major:minor number for these types of filesystems in such a way that
>>>> they can "know" how to report the block device that is causing the
>>>> event?
>>>>
>>>> thanks,
>>>>
>>>> greg k-h
>>>>
>>>
>>> It needs to be done internally by the app but is doable.
>>> The app knows what it is watching, so it can maintain the mappings.
>>> So prior to activating the notifications it can call 'stat' on the mount point.
>>> Stat struct gives the 'st_dev' which is the device id. Same will be reported
>>> within the message payload (through major:minor numbers). So having this,
>>> the app is able to get any other information it needs. 
>>> Note that the events refer to the file system as a whole and they may not
>>> necessarily have anything to do with the actual block device. 
> 
> How are you going to show an event for a filesystem that is made up of
> multiple block devices?

AFAIK, for such filesystems there will be similar case with the anonymous
major:minor numbers - at least the btrfs is doing so. Not sure we can
differentiate here the actual block device. So in this case such events
serves merely as a hint for the userspace. At this point a user might
decide to run some scanning tools. We might extend the scope of the
info being sent, though I would consider this as a nice-to-have but not
required for this initial version of notifications. The filesystems
might also want to decide to send their own custom messages so it is
possible for filesystems like btrfs to send more detailed information
using the new genetlink multicast group.


> 
>>   Or you can use /proc/self/mountinfo for the mapping. There you can see
>> device numbers, real device names if applicable and mountpoints. This has
>> the advantage that it works even if filesystem mountpoints change.
> 
> Ok, then that brings up my next question, how does this handle
> namespaces?  What namespace is the event being sent in?  block devices
> aren't namespaced, but the mount points are, is that going to cause
> problems?
> 

The path should get resolved properly (as from root level). though I must
admit I'm not sure if there will be no issues when it comes to the network
namespaces. I'll double check it. Any hints though are more than welcomed :)

> thanks,
> 
> greg k-h
> 

BR
Beata

^ permalink raw reply

* Re: [PATCH] usb: core: add usb3 lpm sysfs
From: Greg KH @ 2015-04-29 11:06 UTC (permalink / raw)
  To: Zhuang Jin Can
  Cc: rafael.j.wysocki-ral2JQCrhuEAvxtiuMwx3w,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w, pmladek-AlSwsSmVLrQ,
	peter.chen-KZfg59tc24xl57MIdRCFDg, jwerner-F7+t8E8rja9g9hUCZPvPmw,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150429105730.GA12505-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>

On Wed, Apr 29, 2015 at 06:57:30PM +0800, Zhuang Jin Can wrote:
> On Wed, Apr 29, 2015 at 11:01:48AM +0200, Greg KH wrote:
> > On Wed, Apr 29, 2015 at 03:20:04PM +0800, Zhuang Jin Can wrote:
> > > On Tue, Apr 28, 2015 at 11:11:10PM +0200, Greg KH wrote:
> > > > On Wed, Apr 29, 2015 at 12:51:27AM +0800, Zhuang Jin Can wrote:
> > > > > Hi Greg KH,
> > > > > 
> > > > > On Tue, Apr 28, 2015 at 12:42:24PM +0200, Greg KH wrote:
> > > > > > On Sun, Apr 19, 2015 at 11:46:12AM +0800, Zhuang Jin Can wrote:
> > > > > > > Some usb3 devices may not support usb3 lpm well.
> > > > > > > The patch adds a sysfs to enable/disable u1 or u2 of the port.The
> > > > > > > settings apply to both before and after device enumeration.
> > > > > > > Supported values are "0" - u1 and u2 are disabled, "u1" - only u1 is
> > > > > > > enabled, "u2" - only u2 is enabled, "u1_u2" - u1 and u2 are enabled.
> > > > > > > 
> > > > > > > The interface is useful for testing some USB3 devices during
> > > > > > > development, and provides a way to disable usb3 lpm if the issues can
> > > > > > > not be fixed in final products.
> > > > > > 
> > > > > > How is a user supposed to "know" to make this setting for a device?  Why
> > > > > > can't the kernel automatically set this value properly?  Why does it
> > > > > > need to be a kernel issue at all?
> > > > > > 
> > > > > By default kernel enables u1 u2 of all USB3 devices. This interface
> > > > > provides the user to change this policy. User may set the policy
> > > > > according to PID/VID of uevent or according to the platform information
> > > > > known by userspace.
> > > > 
> > > > And why would they ever want to do that?
> > > > 
> > > > > It's not a kernel issue, as u1 u2 is mandatory by USB3 compliance. But
> > > > > for some internal hardwired USB3 connection, e.g. SSIC, passing USB3
> > > > > compliance is not mandatory. So the interface provides a way for vendor
> > > > > to ship with u1 or u2 broken products. Of course, this is not encouraged :).
> > > > 
> > > > If the state is broken for those devices, we can't require the user to
> > > > fix it for us, the kernel should do it automatically.
> > > > 
> > > > > > And when you are doing development of broken devices, the kernel doesn't
> > > > > > have to support you, you can run with debugging patches of your own
> > > > > > until you fix your firmware :)
> > > > > > 
> > > > > Understood. But I think other vendor or developer may face the same
> > > > > issue in final product shipment or during development. Moreover, the
> > > > > interface provide the flexibility for developer to separately
> > > > > disable/enable u1 or u2, e.g. If they're debugging an u2 issue, they
> > > > > can disable u1 to simplify the situtation.
> > > > 
> > > > For debugging only, perhaps, but for a "normal" user, please let's
> > > > handle this automatically and don't create a switch that never gets used
> > > > by anyone or anything.
> > > > 
> > > Thanks Greg. Since so far the patch has no interesting value to the
> > > community, I'll drop the patch.
> > 
> > I didn't say that, I said it needed some more work to be accepted.
> Sorry for misunderstanding. Let me explain more why we need this interface.
> 
> We have a modem USB3 device (in stepping C) hardwired to one specific port of xHCI.
> The device was expected to work with u1 u2, however, due to a HW issue, it doesn't
> work stably. To workaround the issue, we let the init.rc script disable u1 u2 for
> this specific port.

Modern Linux systems don't have init.rc scripts anymore :)

> Then maybe we want to start debug u1 issue first, to avoid hitting u2 issue,
> we can disable u2. After u1 issue is resolved, we can enable back u2 to continue to
> debug u2 issue. This provides the flexibility to isolate u1 u2 debugging.
> This is valuable I think :)

I agree.

> The HW issue will be fixed in stepping D, however C and D will have the same PID/VID.
> There's no way for kernel to know the difference between C and D.
> Even after fixing in D, C will still be used for development (to save money..)

That sounds like a big design flaw, what about looking at the version of
the device?  That's what that field in the USB descriptors is for.

> If somehow finally we decide to ship stepping C (suppose HW issue can't be fixed in D in time),
> we'll have to disable both u1 and u2.
> 
> If we fix only u1 issue, we can just disable u2, etc..
> 
> To summarize, it provide users an opptunity to change the u1 u2 policy to
> debug and ship broken products.

That's good, but you need to do it somehow "automatically", as again,
systems don't have a init.rc file anymore :)

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH] usb: core: add usb3 lpm sysfs
From: Zhuang Jin Can @ 2015-04-29 10:57 UTC (permalink / raw)
  To: Greg KH
  Cc: rafael.j.wysocki-ral2JQCrhuEAvxtiuMwx3w,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w, pmladek-AlSwsSmVLrQ,
	peter.chen-KZfg59tc24xl57MIdRCFDg, jwerner-F7+t8E8rja9g9hUCZPvPmw,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150429090148.GA22743-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>

On Wed, Apr 29, 2015 at 11:01:48AM +0200, Greg KH wrote:
> On Wed, Apr 29, 2015 at 03:20:04PM +0800, Zhuang Jin Can wrote:
> > On Tue, Apr 28, 2015 at 11:11:10PM +0200, Greg KH wrote:
> > > On Wed, Apr 29, 2015 at 12:51:27AM +0800, Zhuang Jin Can wrote:
> > > > Hi Greg KH,
> > > > 
> > > > On Tue, Apr 28, 2015 at 12:42:24PM +0200, Greg KH wrote:
> > > > > On Sun, Apr 19, 2015 at 11:46:12AM +0800, Zhuang Jin Can wrote:
> > > > > > Some usb3 devices may not support usb3 lpm well.
> > > > > > The patch adds a sysfs to enable/disable u1 or u2 of the port.The
> > > > > > settings apply to both before and after device enumeration.
> > > > > > Supported values are "0" - u1 and u2 are disabled, "u1" - only u1 is
> > > > > > enabled, "u2" - only u2 is enabled, "u1_u2" - u1 and u2 are enabled.
> > > > > > 
> > > > > > The interface is useful for testing some USB3 devices during
> > > > > > development, and provides a way to disable usb3 lpm if the issues can
> > > > > > not be fixed in final products.
> > > > > 
> > > > > How is a user supposed to "know" to make this setting for a device?  Why
> > > > > can't the kernel automatically set this value properly?  Why does it
> > > > > need to be a kernel issue at all?
> > > > > 
> > > > By default kernel enables u1 u2 of all USB3 devices. This interface
> > > > provides the user to change this policy. User may set the policy
> > > > according to PID/VID of uevent or according to the platform information
> > > > known by userspace.
> > > 
> > > And why would they ever want to do that?
> > > 
> > > > It's not a kernel issue, as u1 u2 is mandatory by USB3 compliance. But
> > > > for some internal hardwired USB3 connection, e.g. SSIC, passing USB3
> > > > compliance is not mandatory. So the interface provides a way for vendor
> > > > to ship with u1 or u2 broken products. Of course, this is not encouraged :).
> > > 
> > > If the state is broken for those devices, we can't require the user to
> > > fix it for us, the kernel should do it automatically.
> > > 
> > > > > And when you are doing development of broken devices, the kernel doesn't
> > > > > have to support you, you can run with debugging patches of your own
> > > > > until you fix your firmware :)
> > > > > 
> > > > Understood. But I think other vendor or developer may face the same
> > > > issue in final product shipment or during development. Moreover, the
> > > > interface provide the flexibility for developer to separately
> > > > disable/enable u1 or u2, e.g. If they're debugging an u2 issue, they
> > > > can disable u1 to simplify the situtation.
> > > 
> > > For debugging only, perhaps, but for a "normal" user, please let's
> > > handle this automatically and don't create a switch that never gets used
> > > by anyone or anything.
> > > 
> > Thanks Greg. Since so far the patch has no interesting value to the
> > community, I'll drop the patch.
> 
> I didn't say that, I said it needed some more work to be accepted.
Sorry for misunderstanding. Let me explain more why we need this interface.

We have a modem USB3 device (in stepping C) hardwired to one specific port of xHCI.
The device was expected to work with u1 u2, however, due to a HW issue, it doesn't
work stably. To workaround the issue, we let the init.rc script disable u1 u2 for
this specific port.

Then maybe we want to start debug u1 issue first, to avoid hitting u2 issue,
we can disable u2. After u1 issue is resolved, we can enable back u2 to continue to
debug u2 issue. This provides the flexibility to isolate u1 u2 debugging.
This is valuable I think :)

The HW issue will be fixed in stepping D, however C and D will have the same PID/VID.
There's no way for kernel to know the difference between C and D.
Even after fixing in D, C will still be used for development (to save money..)

If somehow finally we decide to ship stepping C (suppose HW issue can't be fixed in D in time),
we'll have to disable both u1 and u2.

If we fix only u1 issue, we can just disable u2, etc..

To summarize, it provide users an opptunity to change the u1 u2 policy to
debug and ship broken products.



Thanks
Jincan

^ permalink raw reply

* Re: [RFC v2 1/4] fs: Add generic file system event notifications
From: Greg KH @ 2015-04-29  9:13 UTC (permalink / raw)
  To: Jan Kara
  Cc: Beata Michalska, linux-kernel, linux-fsdevel, linux-api, tytso,
	adilger.kernel, hughd, lczerner, hch, linux-ext4, linux-mm,
	kyungmin.park, kmpark
In-Reply-To: <20150429074259.GA31089@quack.suse.cz>

On Wed, Apr 29, 2015 at 09:42:59AM +0200, Jan Kara wrote:
> On Wed 29-04-15 09:03:08, Beata Michalska wrote:
> > On 04/28/2015 07:39 PM, Greg KH wrote:
> > > On Tue, Apr 28, 2015 at 04:46:46PM +0200, Beata Michalska wrote:
> > >> On 04/28/2015 04:09 PM, Greg KH wrote:
> > >>> On Tue, Apr 28, 2015 at 03:56:53PM +0200, Jan Kara wrote:
> > >>>> On Mon 27-04-15 17:37:11, Greg KH wrote:
> > >>>>> On Mon, Apr 27, 2015 at 05:08:27PM +0200, Beata Michalska wrote:
> > >>>>>> On 04/27/2015 04:24 PM, Greg KH wrote:
> > >>>>>>> On Mon, Apr 27, 2015 at 01:51:41PM +0200, Beata Michalska wrote:
> > >>>>>>>> Introduce configurable generic interface for file
> > >>>>>>>> system-wide event notifications, to provide file
> > >>>>>>>> systems with a common way of reporting any potential
> > >>>>>>>> issues as they emerge.
> > >>>>>>>>
> > >>>>>>>> The notifications are to be issued through generic
> > >>>>>>>> netlink interface by newly introduced multicast group.
> > >>>>>>>>
> > >>>>>>>> Threshold notifications have been included, allowing
> > >>>>>>>> triggering an event whenever the amount of free space drops
> > >>>>>>>> below a certain level - or levels to be more precise as two
> > >>>>>>>> of them are being supported: the lower and the upper range.
> > >>>>>>>> The notifications work both ways: once the threshold level
> > >>>>>>>> has been reached, an event shall be generated whenever
> > >>>>>>>> the number of available blocks goes up again re-activating
> > >>>>>>>> the threshold.
> > >>>>>>>>
> > >>>>>>>> The interface has been exposed through a vfs. Once mounted,
> > >>>>>>>> it serves as an entry point for the set-up where one can
> > >>>>>>>> register for particular file system events.
> > >>>>>>>>
> > >>>>>>>> Signed-off-by: Beata Michalska <b.michalska@samsung.com>
> > >>>>>>>> ---
> > >>>>>>>>  Documentation/filesystems/events.txt |  231 ++++++++++
> > >>>>>>>>  fs/Makefile                          |    1 +
> > >>>>>>>>  fs/events/Makefile                   |    6 +
> > >>>>>>>>  fs/events/fs_event.c                 |  770 ++++++++++++++++++++++++++++++++++
> > >>>>>>>>  fs/events/fs_event.h                 |   25 ++
> > >>>>>>>>  fs/events/fs_event_netlink.c         |   99 +++++
> > >>>>>>>>  fs/namespace.c                       |    1 +
> > >>>>>>>>  include/linux/fs.h                   |    6 +-
> > >>>>>>>>  include/linux/fs_event.h             |   58 +++
> > >>>>>>>>  include/uapi/linux/fs_event.h        |   54 +++
> > >>>>>>>>  include/uapi/linux/genetlink.h       |    1 +
> > >>>>>>>>  net/netlink/genetlink.c              |    7 +-
> > >>>>>>>>  12 files changed, 1257 insertions(+), 2 deletions(-)
> > >>>>>>>>  create mode 100644 Documentation/filesystems/events.txt
> > >>>>>>>>  create mode 100644 fs/events/Makefile
> > >>>>>>>>  create mode 100644 fs/events/fs_event.c
> > >>>>>>>>  create mode 100644 fs/events/fs_event.h
> > >>>>>>>>  create mode 100644 fs/events/fs_event_netlink.c
> > >>>>>>>>  create mode 100644 include/linux/fs_event.h
> > >>>>>>>>  create mode 100644 include/uapi/linux/fs_event.h
> > >>>>>>>
> > >>>>>>> Any reason why you just don't do uevents for the block devices today,
> > >>>>>>> and not create a new type of netlink message and userspace tool required
> > >>>>>>> to read these?
> > >>>>>>
> > >>>>>> The idea here is to have support for filesystems with no backing device as well.
> > >>>>>> Parsing the message with libnl is really simple and requires few lines of code
> > >>>>>> (sample application has been presented in the initial version of this RFC)
> > >>>>>
> > >>>>> I'm not saying it's not "simple" to parse, just that now you are doing
> > >>>>> something that requires a different tool.  If you have a block device,
> > >>>>> you should be able to emit uevents for it, you don't need a backing
> > >>>>> device, we handle virtual filesystems in /sys/block/ just fine :)
> > >>>>>
> > >>>>> People already have tools that listen to libudev for system monitoring
> > >>>>> and management, why require them to hook up to yet-another-library?  And
> > >>>>> what is going to provide the ability for multiple userspace tools to
> > >>>>> listen to these netlink messages in case you have more than one program
> > >>>>> that wants to watch for these things (i.e. multiple desktop filesystem
> > >>>>> monitoring tools, system-health checkers, etc.)?
> > >>>>   As much as I understand your concerns I'm not convinced uevent interface
> > >>>> is a good fit. There are filesystems that don't have underlying block
> > >>>> device - think of e.g. tmpfs or filesystems working directly on top of
> > >>>> flash devices.  These still want to send notification to userspace (one of
> > >>>> primary motivation for this interfaces was so that tmpfs can notify about
> > >>>> something). And creating some fake nodes in /sys/block for tmpfs and
> > >>>> similar filesystems seems like doing more harm than good to me...
> > >>>
> > >>> If these are "fake" block devices, what's going to be present in the
> > >>> block major/minor fields of the netlink message?  For some reason I
> > >>> thought it was a required field, and because of that, I thought we had a
> > >>> "real" filesystem somewhere to refer to, otherwise how would userspace
> > >>> know what filesystem was creating these events?
> > >>>
> > >>> What am I missing here?
> > >>>
> > >>> confused,
> > >>>
> > >>> greg k-h
> > >>>
> > >>
> > >> For those 'fake' block devs, upon mount, get_anon_bdev will assign
> > >> the major:minor numbers. Userspace might get those through stat.
> > > 
> > > How can userspace do the mapping backwards from this "anonymous"
> > > major:minor number for these types of filesystems in such a way that
> > > they can "know" how to report the block device that is causing the
> > > event?
> > > 
> > > thanks,
> > > 
> > > greg k-h
> > > 
> > 
> > It needs to be done internally by the app but is doable.
> > The app knows what it is watching, so it can maintain the mappings.
> > So prior to activating the notifications it can call 'stat' on the mount point.
> > Stat struct gives the 'st_dev' which is the device id. Same will be reported
> > within the message payload (through major:minor numbers). So having this,
> > the app is able to get any other information it needs. 
> > Note that the events refer to the file system as a whole and they may not
> > necessarily have anything to do with the actual block device. 

How are you going to show an event for a filesystem that is made up of
multiple block devices?

>   Or you can use /proc/self/mountinfo for the mapping. There you can see
> device numbers, real device names if applicable and mountpoints. This has
> the advantage that it works even if filesystem mountpoints change.

Ok, then that brings up my next question, how does this handle
namespaces?  What namespace is the event being sent in?  block devices
aren't namespaced, but the mount points are, is that going to cause
problems?

thanks,

greg k-h

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [PATCH v3 3/3] proc: add kpageidle file
From: Vladimir Davydov @ 2015-04-29  9:12 UTC (permalink / raw)
  To: Minchan Kim
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Greg Thelen,
	Michel Lespinasse, David Rientjes, Pavel Emelyanov,
	Cyrill Gorcunov, Jonathan Corbet, linux-api, linux-doc, linux-mm,
	cgroups, linux-kernel
In-Reply-To: <20150429043536.GB11486@blaptop>

On Wed, Apr 29, 2015 at 01:35:36PM +0900, Minchan Kim wrote:
> On Tue, Apr 28, 2015 at 03:24:42PM +0300, Vladimir Davydov wrote:
> > diff --git a/fs/proc/page.c b/fs/proc/page.c
> > index 70d23245dd43..cfc55ba7fee6 100644
> > --- a/fs/proc/page.c
> > +++ b/fs/proc/page.c
> > @@ -275,6 +275,156 @@ static const struct file_operations proc_kpagecgroup_operations = {
> >  };
> >  #endif /* CONFIG_MEMCG */
> >  
> > +#ifdef CONFIG_IDLE_PAGE_TRACKING
> > +static struct page *kpageidle_get_page(unsigned long pfn)
> > +{
> > +	struct page *page;
> > +
> > +	if (!pfn_valid(pfn))
> > +		return NULL;
> > +	page = pfn_to_page(pfn);
> > +	/*
> > +	 * We are only interested in user memory pages, i.e. pages that are
> > +	 * allocated and on an LRU list.
> > +	 */
> > +	if (!page || page_count(page) == 0 || !PageLRU(page))
> 
> Why do you check (page_count == 0) even if we check it with get_page_unless_zero
> below?

I intended to avoid overhead of cmpxchg in case page_count is 0, but
diving deeper into get_page_unless_zero, I see that it already handles
such a scenario, so this check is useless. I'll remove it.

> 
> > +		return NULL;
> > +	if (!get_page_unless_zero(page))
> > +		return NULL;
> > +	if (unlikely(!PageLRU(page))) {
> 
> What lock protect the check PageLRU?
> If it is racing ClearPageLRU, what happens?

If we hold a reference to a page and see that it's on an LRU list, it
will surely remain a user memory page at least until we release the
reference to it, so it must be safe to play with idle/young flags. If we
race with isolate_lru_page, or any similar function temporarily clearing
PG_lru, we will silently skip the page w/o touching its idle/young
flags. We could consider isolated pages too, but that would increase the
cost of this function.

If you find this explanation OK, I'll add it to the comment to this
function.

> 
> > +		put_page(page);
> > +		return NULL;
> > +	}
> > +	return page;
> > +}
> > +
> > +static void kpageidle_clear_refs(struct page *page)
> > +{
> > +	unsigned long dummy;
> > +
> > +	if (page_referenced(page, 0, NULL, &dummy))
> > +		/*
> > +		 * This page was referenced. To avoid interference with the
> > +		 * reclaimer, mark it young so that the next call will also
> 
>                                                         next what call?
> 
> It just works with mapped page so kpageidle_clear_pte_refs as function name
> is more clear.
> 
> One more, kpageidle_clear_refs removes PG_idle via page_referenced which
> is important feature for the function. Please document it so we could
> understand why we need double check for PG_idle after calling
> kpageidle_clear_refs for pte access bit.

Sounds reasonable, will do.

> > diff --git a/mm/rmap.c b/mm/rmap.c
> > index 24dd3f9fee27..12e73b758d9e 100644
> > --- a/mm/rmap.c
> > +++ b/mm/rmap.c
> > @@ -784,6 +784,13 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,
> >  	if (referenced) {
> >  		pra->referenced++;
> >  		pra->vm_flags |= vma->vm_flags;
> > +		if (page_is_idle(page))
> > +			clear_page_idle(page);
> > +	}
> > +
> > +	if (page_is_young(page)) {
> > +		clear_page_young(page);
> > +		pra->referenced++;
> 
> If a page was page_is_young and referenced recenlty,
> pra->referenced is increased doubly and it changes current
> behavior for file-backed page promotion. Look at page_check_references.

Yeah, you're quite right, I missed that. Something like this should get
rid of this extra reference:

diff --git a/mm/rmap.c b/mm/rmap.c
index 24dd3f9fee27..eca7416f55d7 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -781,6 +781,14 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,
 		pte_unmap_unlock(pte, ptl);
 	}
 
+	if (referenced && page_is_idle(page))
+		clear_page_idle(page);
+
+	if (page_is_young(page)) {
+		clear_page_young(page);
+		referenced++;
+	}
+
 	if (referenced) {
 		pra->referenced++;
 		pra->vm_flags |= vma->vm_flags;

Thanks,
Vladimir

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply related

* Re: [PATCH] usb: core: add usb3 lpm sysfs
From: Greg KH @ 2015-04-29  9:01 UTC (permalink / raw)
  To: Zhuang Jin Can
  Cc: rafael.j.wysocki-ral2JQCrhuEAvxtiuMwx3w,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	dan.j.williams-ral2JQCrhuEAvxtiuMwx3w, pmladek-AlSwsSmVLrQ,
	peter.chen-KZfg59tc24xl57MIdRCFDg, jwerner-F7+t8E8rja9g9hUCZPvPmw,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150429072004.GA20961-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>

On Wed, Apr 29, 2015 at 03:20:04PM +0800, Zhuang Jin Can wrote:
> On Tue, Apr 28, 2015 at 11:11:10PM +0200, Greg KH wrote:
> > On Wed, Apr 29, 2015 at 12:51:27AM +0800, Zhuang Jin Can wrote:
> > > Hi Greg KH,
> > > 
> > > On Tue, Apr 28, 2015 at 12:42:24PM +0200, Greg KH wrote:
> > > > On Sun, Apr 19, 2015 at 11:46:12AM +0800, Zhuang Jin Can wrote:
> > > > > Some usb3 devices may not support usb3 lpm well.
> > > > > The patch adds a sysfs to enable/disable u1 or u2 of the port.The
> > > > > settings apply to both before and after device enumeration.
> > > > > Supported values are "0" - u1 and u2 are disabled, "u1" - only u1 is
> > > > > enabled, "u2" - only u2 is enabled, "u1_u2" - u1 and u2 are enabled.
> > > > > 
> > > > > The interface is useful for testing some USB3 devices during
> > > > > development, and provides a way to disable usb3 lpm if the issues can
> > > > > not be fixed in final products.
> > > > 
> > > > How is a user supposed to "know" to make this setting for a device?  Why
> > > > can't the kernel automatically set this value properly?  Why does it
> > > > need to be a kernel issue at all?
> > > > 
> > > By default kernel enables u1 u2 of all USB3 devices. This interface
> > > provides the user to change this policy. User may set the policy
> > > according to PID/VID of uevent or according to the platform information
> > > known by userspace.
> > 
> > And why would they ever want to do that?
> > 
> > > It's not a kernel issue, as u1 u2 is mandatory by USB3 compliance. But
> > > for some internal hardwired USB3 connection, e.g. SSIC, passing USB3
> > > compliance is not mandatory. So the interface provides a way for vendor
> > > to ship with u1 or u2 broken products. Of course, this is not encouraged :).
> > 
> > If the state is broken for those devices, we can't require the user to
> > fix it for us, the kernel should do it automatically.
> > 
> > > > And when you are doing development of broken devices, the kernel doesn't
> > > > have to support you, you can run with debugging patches of your own
> > > > until you fix your firmware :)
> > > > 
> > > Understood. But I think other vendor or developer may face the same
> > > issue in final product shipment or during development. Moreover, the
> > > interface provide the flexibility for developer to separately
> > > disable/enable u1 or u2, e.g. If they're debugging an u2 issue, they
> > > can disable u1 to simplify the situtation.
> > 
> > For debugging only, perhaps, but for a "normal" user, please let's
> > handle this automatically and don't create a switch that never gets used
> > by anyone or anything.
> > 
> Thanks Greg. Since so far the patch has no interesting value to the
> community, I'll drop the patch.

I didn't say that, I said it needed some more work to be accepted.

^ permalink raw reply

* Re: [PATCH v3 3/3] proc: add kpageidle file
From: Vladimir Davydov @ 2015-04-29  8:31 UTC (permalink / raw)
  To: Minchan Kim
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Greg Thelen,
	Michel Lespinasse, David Rientjes, Pavel Emelyanov,
	Cyrill Gorcunov, Jonathan Corbet, linux-api, linux-doc, linux-mm,
	cgroups, linux-kernel
In-Reply-To: <20150429045759.GA27051@blaptop>

On Wed, Apr 29, 2015 at 01:57:59PM +0900, Minchan Kim wrote:
> On Tue, Apr 28, 2015 at 03:24:42PM +0300, Vladimir Davydov wrote:
> > @@ -69,6 +69,14 @@ There are four components to pagemap:
> >     memory cgroup each page is charged to, indexed by PFN. Only available when
> >     CONFIG_MEMCG is set.
> >  
> > + * /proc/kpageidle.  For each page this file contains a 64-bit number, which
> > +   equals 1 if the page is idle or 0 otherwise, indexed by PFN. A page is
> > +   considered idle if it has not been accessed since it was marked idle. To
> > +   mark a page idle one should write 1 to this file at the offset corresponding
> > +   to the page. Only user memory pages can be marked idle, for other page types
> > +   input is silently ignored. Writing to this file beyond max PFN results in
> > +   the ENXIO error. Only available when CONFIG_IDLE_PAGE_TRACKING is set.
> > +
> 
> How about using kpageflags for reading part?
> 
> I mean PG_idle is one of the page flags and we already have a feature to
> parse of each PFN flag so we could reuse existing feature for reading
> idleness.

Reading PG_idle implies clearing all pte references to make sure the
page was not referenced via a pte. This means that exporting it via
/proc/kpageflags would increase the cost of reading this file, even for
users that don't care about PG_idle. I'm not sure all users of
/proc/kpageflags will be fine with it.

Thanks,
Vladimir

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox