* [PATCH 01/20] stm class: Use a signed return type for stm_find_master_chan
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
@ 2016-02-15 17:11 ` Alexander Shishkin
2016-02-15 17:11 ` [PATCH 02/20] stm class: Fix master deallocation in device unregistering Alexander Shishkin
` (18 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:11 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Lucas Tanure, Alexander Shishkin
From: Lucas Tanure <tanure@linux.com>
The return type "unsigned int" was used by the stm_find_master_chan function
despite of the aspect that it will eventually return a negative error code.
Done with the help of Coccinelle.
Signed-off-by: Lucas Tanure <tanure@linux.com>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index aef8ddb244..cdec240bd6 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -233,7 +233,7 @@ static int find_free_channels(unsigned long *bitmap, unsigned int start,
return -1;
}
-static unsigned int
+static int
stm_find_master_chan(struct stm_device *stm, unsigned int width,
unsigned int *mstart, unsigned int mend,
unsigned int *cstart, unsigned int cend)
@@ -293,7 +293,7 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width,
goto unlock;
ret = stm_find_master_chan(stm, width, &midx, mend, &cidx, cend);
- if (ret)
+ if (ret < 0)
goto unlock;
output->master = midx;
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 02/20] stm class: Fix master deallocation in device unregistering
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
2016-02-15 17:11 ` [PATCH 01/20] stm class: Use a signed return type for stm_find_master_chan Alexander Shishkin
@ 2016-02-15 17:11 ` Alexander Shishkin
2016-02-15 17:11 ` [PATCH 03/20] intel_th: Depend on HAS_IOMEM Alexander Shishkin
` (17 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:11 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
From: Chunyan Zhang <zhang.chunyan@linaro.org>
The device unregister path uses wrong master index range when it tries
to free the allocated masters, it should, as does the rest of the stm
class code, use real master IDs.
This patch fixes the device unregister path to use real master IDs to
avoid memory leaks after unloading the stm driver.
Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>
[alexander.shishkin@intel.com: re-wrote the commit message]
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index cdec240bd6..79cca94bfb 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -690,7 +690,7 @@ void stm_unregister_device(struct stm_data *stm_data)
stp_policy_unbind(stm->policy);
mutex_unlock(&stm->policy_mutex);
- for (i = 0; i < stm->sw_nmasters; i++)
+ for (i = stm->data->sw_start; i <= stm->data->sw_end; i++)
stp_master_free(stm, i);
device_unregister(&stm->dev);
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 03/20] intel_th: Depend on HAS_IOMEM
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
2016-02-15 17:11 ` [PATCH 01/20] stm class: Use a signed return type for stm_find_master_chan Alexander Shishkin
2016-02-15 17:11 ` [PATCH 02/20] stm class: Fix master deallocation in device unregistering Alexander Shishkin
@ 2016-02-15 17:11 ` Alexander Shishkin
2016-02-15 17:11 ` [PATCH 04/20] intel_th: gth: Remove commented-out code Alexander Shishkin
` (16 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:11 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
This driver requires io memory to operate, so don't even consider it
for NO_IOMEM architectures.
Reported-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/intel_th/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/hwtracing/intel_th/Kconfig b/drivers/hwtracing/intel_th/Kconfig
index 90b0844093..1b412f8a56 100644
--- a/drivers/hwtracing/intel_th/Kconfig
+++ b/drivers/hwtracing/intel_th/Kconfig
@@ -1,6 +1,6 @@
config INTEL_TH
tristate "Intel(R) Trace Hub controller"
- depends on HAS_DMA
+ depends on HAS_DMA && HAS_IOMEM
help
Intel(R) Trace Hub (TH) is a set of hardware blocks (subdevices) that
produce, switch and output trace data from multiple hardware and
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 04/20] intel_th: gth: Remove commented-out code
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (2 preceding siblings ...)
2016-02-15 17:11 ` [PATCH 03/20] intel_th: Depend on HAS_IOMEM Alexander Shishkin
@ 2016-02-15 17:11 ` Alexander Shishkin
2016-02-15 17:11 ` [PATCH 05/20] intel_th: Update scratchpad bits according to enabled output activity Alexander Shishkin
` (15 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:11 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
There's a commented-out function in the GTH driver that's a leftover
from previous versions of the driver, where we tried to inherit the
pre-existing configuration, which didn't prove to be a sound idea.
This patch removes the function. No functional changes.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/intel_th/gth.c | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c
index 2dc5378ccd..e4c9811c1f 100644
--- a/drivers/hwtracing/intel_th/gth.c
+++ b/drivers/hwtracing/intel_th/gth.c
@@ -146,24 +146,6 @@ gth_master_set(struct gth_device *gth, unsigned int master, int port)
iowrite32(val, gth->base + reg);
}
-/*static int gth_master_get(struct gth_device *gth, unsigned int master)
-{
- unsigned int reg = REG_GTH_SWDEST0 + ((master >> 1) & ~3u);
- unsigned int shift = (master & 0x7) * 4;
- u32 val;
-
- if (master >= 256) {
- reg = REG_GTH_GSWTDEST;
- shift = 0;
- }
-
- val = ioread32(gth->base + reg);
- val &= (0xf << shift);
- val >>= shift;
-
- return val ? val & 0x7 : -1;
- }*/
-
static ssize_t master_attr_show(struct device *dev,
struct device_attribute *attr,
char *buf)
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 05/20] intel_th: Update scratchpad bits according to enabled output activity
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (3 preceding siblings ...)
2016-02-15 17:11 ` [PATCH 04/20] intel_th: gth: Remove commented-out code Alexander Shishkin
@ 2016-02-15 17:11 ` Alexander Shishkin
2016-02-15 17:11 ` [PATCH 06/20] intel_th: msu: Fix offset for wrapped block Alexander Shishkin
` (14 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:11 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
Intel TH implements a scratchpad register to indicate to the firmware
and external debuggers what trace configuration is enabled so that
everybody plays nicely together. The register is a bit field and the
bit assignment convention is described in the developer's manual.
This patch enables the driver to automatically set scratchpad register
bits according to the output configuration that's enabled.
Based on work by Yann Fouassier.
Signed-off-by: Yann Fouassier <yann.fouassier@intel.com>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/intel_th/core.c | 5 +++++
drivers/hwtracing/intel_th/gth.c | 14 +++++++++++-
drivers/hwtracing/intel_th/gth.h | 3 ---
drivers/hwtracing/intel_th/intel_th.h | 41 +++++++++++++++++++++++++++++++++++
4 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 165d3001c3..b8b9895da5 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -319,6 +319,7 @@ static struct intel_th_subdevice {
unsigned nres;
unsigned type;
unsigned otype;
+ unsigned scrpd;
int id;
} intel_th_subdevices[TH_SUBDEVICE_MAX] = {
{
@@ -352,6 +353,7 @@ static struct intel_th_subdevice {
.id = 0,
.type = INTEL_TH_OUTPUT,
.otype = GTH_MSU,
+ .scrpd = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC0_IS_ENABLED,
},
{
.nres = 2,
@@ -371,6 +373,7 @@ static struct intel_th_subdevice {
.id = 1,
.type = INTEL_TH_OUTPUT,
.otype = GTH_MSU,
+ .scrpd = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC1_IS_ENABLED,
},
{
.nres = 2,
@@ -403,6 +406,7 @@ static struct intel_th_subdevice {
.name = "pti",
.type = INTEL_TH_OUTPUT,
.otype = GTH_PTI,
+ .scrpd = SCRPD_PTI_IS_PRIM_DEST,
},
{
.nres = 1,
@@ -477,6 +481,7 @@ static int intel_th_populate(struct intel_th *th, struct resource *devres,
thdev->dev.devt = MKDEV(th->major, i);
thdev->output.type = subdev->otype;
thdev->output.port = -1;
+ thdev->output.scratchpad = subdev->scrpd;
}
err = device_add(&thdev->dev);
diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c
index e4c9811c1f..9beea0b542 100644
--- a/drivers/hwtracing/intel_th/gth.c
+++ b/drivers/hwtracing/intel_th/gth.c
@@ -286,6 +286,10 @@ static int intel_th_gth_reset(struct gth_device *gth)
if (scratchpad & SCRPD_DEBUGGER_IN_USE)
return -EBUSY;
+ /* Always save/restore STH and TU registers in S0ix entry/exit */
+ scratchpad |= SCRPD_STH_IS_ENABLED | SCRPD_TRIGGER_IS_ENABLED;
+ iowrite32(scratchpad, gth->base + REG_GTH_SCRPD0);
+
/* output ports */
for (port = 0; port < 8; port++) {
if (gth_output_parm_get(gth, port, TH_OUTPUT_PARM(port)) ==
@@ -488,6 +492,10 @@ static void intel_th_gth_disable(struct intel_th_device *thdev,
if (!count)
dev_dbg(&thdev->dev, "timeout waiting for GTH[%d] PLE\n",
output->port);
+
+ reg = ioread32(gth->base + REG_GTH_SCRPD0);
+ reg &= ~output->scratchpad;
+ iowrite32(reg, gth->base + REG_GTH_SCRPD0);
}
/**
@@ -502,7 +510,7 @@ static void intel_th_gth_enable(struct intel_th_device *thdev,
struct intel_th_output *output)
{
struct gth_device *gth = dev_get_drvdata(&thdev->dev);
- u32 scr = 0xfc0000;
+ u32 scr = 0xfc0000, scrpd;
int master;
spin_lock(>h->gth_lock);
@@ -517,6 +525,10 @@ static void intel_th_gth_enable(struct intel_th_device *thdev,
output->active = true;
spin_unlock(>h->gth_lock);
+ scrpd = ioread32(gth->base + REG_GTH_SCRPD0);
+ scrpd |= output->scratchpad;
+ iowrite32(scrpd, gth->base + REG_GTH_SCRPD0);
+
iowrite32(scr, gth->base + REG_GTH_SCR);
iowrite32(0, gth->base + REG_GTH_SCR2);
}
diff --git a/drivers/hwtracing/intel_th/gth.h b/drivers/hwtracing/intel_th/gth.h
index 3b714b7a61..56f0d26205 100644
--- a/drivers/hwtracing/intel_th/gth.h
+++ b/drivers/hwtracing/intel_th/gth.h
@@ -57,9 +57,6 @@ enum {
REG_GTH_SCRPD3 = 0xec, /* ScratchPad[3] */
};
-/* Externall debugger is using Intel TH */
-#define SCRPD_DEBUGGER_IN_USE BIT(24)
-
/* waiting for Pipeline Empty bit(s) to assert for GTH */
#define GTH_PLE_WAITLOOP_DEPTH 10000
diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h
index 57fd72b20f..eedd09332d 100644
--- a/drivers/hwtracing/intel_th/intel_th.h
+++ b/drivers/hwtracing/intel_th/intel_th.h
@@ -30,6 +30,7 @@ enum {
* struct intel_th_output - descriptor INTEL_TH_OUTPUT type devices
* @port: output port number, assigned by the switch
* @type: GTH_{MSU,CTP,PTI}
+ * @scratchpad: scratchpad bits to flag when this output is enabled
* @multiblock: true for multiblock output configuration
* @active: true when this output is enabled
*
@@ -41,6 +42,7 @@ enum {
struct intel_th_output {
int port;
unsigned int type;
+ unsigned int scratchpad;
bool multiblock;
bool active;
};
@@ -241,4 +243,43 @@ enum {
GTH_PTI = 4, /* MIPI-PTI */
};
+/*
+ * Scratchpad bits: tell firmware and external debuggers
+ * what we are up to.
+ */
+enum {
+ /* Memory is the primary destination */
+ SCRPD_MEM_IS_PRIM_DEST = BIT(0),
+ /* XHCI DbC is the primary destination */
+ SCRPD_DBC_IS_PRIM_DEST = BIT(1),
+ /* PTI is the primary destination */
+ SCRPD_PTI_IS_PRIM_DEST = BIT(2),
+ /* BSSB is the primary destination */
+ SCRPD_BSSB_IS_PRIM_DEST = BIT(3),
+ /* PTI is the alternate destination */
+ SCRPD_PTI_IS_ALT_DEST = BIT(4),
+ /* BSSB is the alternate destination */
+ SCRPD_BSSB_IS_ALT_DEST = BIT(5),
+ /* DeepSx exit occurred */
+ SCRPD_DEEPSX_EXIT = BIT(6),
+ /* S4 exit occurred */
+ SCRPD_S4_EXIT = BIT(7),
+ /* S5 exit occurred */
+ SCRPD_S5_EXIT = BIT(8),
+ /* MSU controller 0/1 is enabled */
+ SCRPD_MSC0_IS_ENABLED = BIT(9),
+ SCRPD_MSC1_IS_ENABLED = BIT(10),
+ /* Sx exit occurred */
+ SCRPD_SX_EXIT = BIT(11),
+ /* Trigger Unit is enabled */
+ SCRPD_TRIGGER_IS_ENABLED = BIT(12),
+ SCRPD_ODLA_IS_ENABLED = BIT(13),
+ SCRPD_SOCHAP_IS_ENABLED = BIT(14),
+ SCRPD_STH_IS_ENABLED = BIT(15),
+ SCRPD_DCIH_IS_ENABLED = BIT(16),
+ SCRPD_VER_IS_ENABLED = BIT(17),
+ /* External debugger is using Intel TH */
+ SCRPD_DEBUGGER_IN_USE = BIT(24),
+};
+
#endif
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 06/20] intel_th: msu: Fix offset for wrapped block
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (4 preceding siblings ...)
2016-02-15 17:11 ` [PATCH 05/20] intel_th: Update scratchpad bits according to enabled output activity Alexander Shishkin
@ 2016-02-15 17:11 ` Alexander Shishkin
2016-02-15 17:11 ` [PATCH 07/20] intel_th: msu: Release resources on read error Alexander Shishkin
` (13 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:11 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
From: Laurent FERT <laurent.fert@intel.com>
Fix offset for the second pass on the wrapped block when iterating over
memory in multi-block mode, otherwise wrong part of the block will get
copied.
Signed-off-by: Laurent FERT <laurent.fert@intel.com>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/intel_th/msu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
index 70ca27e456..3c793bbf6a 100644
--- a/drivers/hwtracing/intel_th/msu.c
+++ b/drivers/hwtracing/intel_th/msu.c
@@ -408,7 +408,7 @@ msc_buffer_iterate(struct msc_iter *iter, size_t size, void *data,
* Second time (wrap_count==1), it's just like any other block,
* containing data in the range of [MSC_BDESC..data_bytes].
*/
- if (iter->block == iter->start_block && iter->wrap_count) {
+ if (iter->block == iter->start_block && iter->wrap_count == 2) {
tocopy = DATA_IN_PAGE - data_bytes;
src += data_bytes;
}
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 07/20] intel_th: msu: Release resources on read error
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (5 preceding siblings ...)
2016-02-15 17:11 ` [PATCH 06/20] intel_th: msu: Fix offset for wrapped block Alexander Shishkin
@ 2016-02-15 17:11 ` Alexander Shishkin
2016-02-15 17:11 ` [PATCH 08/20] intel_th: sth: Sanitize packet callback's return values Alexander Shishkin
` (12 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:11 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
From: Laurent FERT <laurent.fert@intel.com>
Right now, reading from msc character device will leak its's user count
on read error.
This patch makes sure resources are released when there is no data left
to read from the buffer.
Signed-off-by: Laurent FERT <laurent.fert@intel.com>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/intel_th/msu.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
index 3c793bbf6a..d9d6022c5a 100644
--- a/drivers/hwtracing/intel_th/msu.c
+++ b/drivers/hwtracing/intel_th/msu.c
@@ -1112,12 +1112,11 @@ static ssize_t intel_th_msc_read(struct file *file, char __user *buf,
size = msc->nr_pages << PAGE_SHIFT;
if (!size)
- return 0;
+ goto put_count;
- if (off >= size) {
- len = 0;
+ if (off >= size)
goto put_count;
- }
+
if (off + len >= size)
len = size - off;
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 08/20] intel_th: sth: Sanitize packet callback's return values
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (6 preceding siblings ...)
2016-02-15 17:11 ` [PATCH 07/20] intel_th: msu: Release resources on read error Alexander Shishkin
@ 2016-02-15 17:11 ` Alexander Shishkin
2016-02-15 17:11 ` [PATCH 09/20] intel_th: Set root device's drvdata early Alexander Shishkin
` (11 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:11 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
According to the stm class interface, the packet callback should return
an error if it is asked to generate packets that it doesn't support.
When it succeeds, it should return number of bytes consumed from its
payload. Currently, for FLAG packet it mistakenly returns 1.
This patch addresses these issues.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/intel_th/sth.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/hwtracing/intel_th/sth.c b/drivers/hwtracing/intel_th/sth.c
index 56101c33e1..e1aee61dd7 100644
--- a/drivers/hwtracing/intel_th/sth.c
+++ b/drivers/hwtracing/intel_th/sth.c
@@ -94,10 +94,13 @@ static ssize_t sth_stm_packet(struct stm_data *stm_data, unsigned int master,
case STP_PACKET_TRIG:
if (flags & STP_PACKET_TIMESTAMPED)
reg += 4;
- iowrite8(*payload, sth->base + reg);
+ writeb_relaxed(*payload, sth->base + reg);
break;
case STP_PACKET_MERR:
+ if (size > 4)
+ size = 4;
+
sth_iowrite(&out->MERR, payload, size);
break;
@@ -107,8 +110,8 @@ static ssize_t sth_stm_packet(struct stm_data *stm_data, unsigned int master,
else
outp = (u64 __iomem *)&out->FLAG;
- size = 1;
- sth_iowrite(outp, payload, size);
+ size = 0;
+ writeb_relaxed(0, outp);
break;
case STP_PACKET_USER:
@@ -129,6 +132,8 @@ static ssize_t sth_stm_packet(struct stm_data *stm_data, unsigned int master,
sth_iowrite(outp, payload, size);
break;
+ default:
+ return -ENOTSUPP;
}
return size;
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 09/20] intel_th: Set root device's drvdata early
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (7 preceding siblings ...)
2016-02-15 17:11 ` [PATCH 08/20] intel_th: sth: Sanitize packet callback's return values Alexander Shishkin
@ 2016-02-15 17:11 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 10/20] intel_th: Use real device index in the node names Alexander Shishkin
` (10 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:11 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
Already during the subdevice initialization time, devices will need
to reference Intel TH controller descriptor structure.
This patch moves setting the drvdata from the pci glue to intel_th
core, before subdevices are populated.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/intel_th/core.c | 2 ++
drivers/hwtracing/intel_th/pci.c | 2 --
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index b8b9895da5..6df3cd9774 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -584,6 +584,8 @@ intel_th_alloc(struct device *dev, struct resource *devres,
}
th->dev = dev;
+ dev_set_drvdata(dev, th);
+
err = intel_th_populate(th, devres, ndevres, irq);
if (err)
goto err_chrdev;
diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c
index 09017073d7..bca7a2ac00 100644
--- a/drivers/hwtracing/intel_th/pci.c
+++ b/drivers/hwtracing/intel_th/pci.c
@@ -46,8 +46,6 @@ static int intel_th_pci_probe(struct pci_dev *pdev,
if (IS_ERR(th))
return PTR_ERR(th);
- pci_set_drvdata(pdev, th);
-
return 0;
}
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 10/20] intel_th: Use real device index in the node names
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (8 preceding siblings ...)
2016-02-15 17:11 ` [PATCH 09/20] intel_th: Set root device's drvdata early Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 11/20] stm class: Use driver's packet callback return value Alexander Shishkin
` (9 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
Most of the intel_th core supports multiple co-existing TH devices,
except for output device nodes, where intel_th device id is hardcoded
to be zero.
Fix this by fetching the actual intel_th device id from the parent
device's drvdata.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/intel_th/core.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 6df3cd9774..4272f2ce5f 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -124,17 +124,34 @@ static struct device_type intel_th_source_device_type = {
.release = intel_th_device_release,
};
+static struct intel_th *to_intel_th(struct intel_th_device *thdev)
+{
+ /*
+ * subdevice tree is flat: if this one is not a switch, its
+ * parent must be
+ */
+ if (thdev->type != INTEL_TH_SWITCH)
+ thdev = to_intel_th_hub(thdev);
+
+ if (WARN_ON_ONCE(!thdev || thdev->type != INTEL_TH_SWITCH))
+ return NULL;
+
+ return dev_get_drvdata(thdev->dev.parent);
+}
+
static char *intel_th_output_devnode(struct device *dev, umode_t *mode,
kuid_t *uid, kgid_t *gid)
{
struct intel_th_device *thdev = to_intel_th_device(dev);
+ struct intel_th *th = to_intel_th(thdev);
char *node;
if (thdev->id >= 0)
- node = kasprintf(GFP_KERNEL, "intel_th%d/%s%d", 0, thdev->name,
- thdev->id);
+ node = kasprintf(GFP_KERNEL, "intel_th%d/%s%d", th->id,
+ thdev->name, thdev->id);
else
- node = kasprintf(GFP_KERNEL, "intel_th%d/%s", 0, thdev->name);
+ node = kasprintf(GFP_KERNEL, "intel_th%d/%s", th->id,
+ thdev->name);
return node;
}
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 11/20] stm class: Use driver's packet callback return value
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (9 preceding siblings ...)
2016-02-15 17:12 ` [PATCH 10/20] intel_th: Use real device index in the node names Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 12/20] stm class: Support devices with multiple instances Alexander Shishkin
` (8 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
STM drivers provide a callback to generate/send individual STP packets;
it also tells the stm core how many bytes of payload it has consumed.
However, we would also need to use the negative space of this return
value to communicate errors that occur during the packet generation,
in which case the stm core will have to take appropriate action.
For now, we need to account for the possibility that the stm driver may
not support certain combinations of packet type/flags, in which case
it is expected to signal an error.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/core.c | 19 ++++++++++++-------
include/linux/stm.h | 7 +++++++
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index 79cca94bfb..0db303b50e 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -380,8 +380,8 @@ static int stm_file_assign(struct stm_file *stmf, char *id, unsigned int width)
return ret;
}
-static void stm_write(struct stm_data *data, unsigned int master,
- unsigned int channel, const char *buf, size_t count)
+static ssize_t stm_write(struct stm_data *data, unsigned int master,
+ unsigned int channel, const char *buf, size_t count)
{
unsigned int flags = STP_PACKET_TIMESTAMPED;
const unsigned char *p = buf, nil = 0;
@@ -393,9 +393,14 @@ static void stm_write(struct stm_data *data, unsigned int master,
sz = data->packet(data, master, channel, STP_PACKET_DATA, flags,
sz, p);
flags = 0;
+
+ if (sz < 0)
+ break;
}
data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, &nil);
+
+ return pos;
}
static ssize_t stm_char_write(struct file *file, const char __user *buf,
@@ -433,8 +438,8 @@ static ssize_t stm_char_write(struct file *file, const char __user *buf,
return -EFAULT;
}
- stm_write(stm->data, stmf->output.master, stmf->output.channel, kbuf,
- count);
+ count = stm_write(stm->data, stmf->output.master, stmf->output.channel,
+ kbuf, count);
kfree(kbuf);
@@ -996,9 +1001,9 @@ int stm_source_write(struct stm_source_data *data, unsigned int chan,
stm = srcu_dereference(src->link, &stm_source_srcu);
if (stm)
- stm_write(stm->data, src->output.master,
- src->output.channel + chan,
- buf, count);
+ count = stm_write(stm->data, src->output.master,
+ src->output.channel + chan,
+ buf, count);
else
count = -ENODEV;
diff --git a/include/linux/stm.h b/include/linux/stm.h
index 9d0083d364..ab8ceca4f5 100644
--- a/include/linux/stm.h
+++ b/include/linux/stm.h
@@ -67,6 +67,13 @@ struct stm_device;
* description. That is, the lowest master that can be allocated to software
* writers is @sw_start and data from this writer will appear is @sw_start
* master in the STP stream.
+ *
+ * The @packet callback should adhere to the following rules:
+ * 1) it must return the number of bytes it consumed from the payload;
+ * 2) therefore, if it sent a packet that does not have payload (like FLAG),
+ * it must return zero;
+ * 3) if it does not support the requested packet type/flag combination,
+ * it must return -ENOTSUPP.
*/
struct stm_data {
const char *name;
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 12/20] stm class: Support devices with multiple instances
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (10 preceding siblings ...)
2016-02-15 17:12 ` [PATCH 11/20] stm class: Use driver's packet callback return value Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 13/20] stm class: dummy_stm: Create multiple devices Alexander Shishkin
` (7 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
By convention, the name of the stm policy directory in configfs consists of
the device name to which it applies and the actual policy name, separated
by a dot. Now, some devices already have dots in their names that separate
name of the actual device from its instance identifier. Such devices will
result in two (or more, who can tell) dots in the policy directory name.
Existing policy code, however, will treat the first dot as the one that
separates device name from policy name, therefore failing the above case.
This patch makes the last dot in the directory name be the separator, thus
prohibiting dots from being used in policy names.
Suggested-by: Chunyan Zhang <zhang.chunyan@linaro.org>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/policy.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c
index 94d3abfb73..1db189657b 100644
--- a/drivers/hwtracing/stm/policy.c
+++ b/drivers/hwtracing/stm/policy.c
@@ -332,10 +332,11 @@ stp_policies_make(struct config_group *group, const char *name)
/*
* node must look like <device_name>.<policy_name>, where
- * <device_name> is the name of an existing stm device and
- * <policy_name> is an arbitrary string
+ * <device_name> is the name of an existing stm device; may
+ * contain dots;
+ * <policy_name> is an arbitrary string; may not contain dots
*/
- p = strchr(devname, '.');
+ p = strrchr(devname, '.');
if (!p) {
kfree(devname);
return ERR_PTR(-EINVAL);
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 13/20] stm class: dummy_stm: Create multiple devices
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (11 preceding siblings ...)
2016-02-15 17:12 ` [PATCH 12/20] stm class: Support devices with multiple instances Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 14/20] stm class: Add heartbeat stm source device Alexander Shishkin
` (6 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
STM framework should be able to handle multiple STM devices at a time,
each one with its own master allocation policy.
This patch changes dummy_stm driver to create multiple STM sinks to
help testing the framework.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/dummy_stm.c | 57 ++++++++++++++++++++++++++++++++-------
1 file changed, 48 insertions(+), 9 deletions(-)
diff --git a/drivers/hwtracing/stm/dummy_stm.c b/drivers/hwtracing/stm/dummy_stm.c
index 3709bef0b2..4ff5961cd3 100644
--- a/drivers/hwtracing/stm/dummy_stm.c
+++ b/drivers/hwtracing/stm/dummy_stm.c
@@ -40,22 +40,61 @@ dummy_stm_packet(struct stm_data *stm_data, unsigned int master,
return size;
}
-static struct stm_data dummy_stm = {
- .name = "dummy_stm",
- .sw_start = 0x0000,
- .sw_end = 0xffff,
- .sw_nchannels = 0xffff,
- .packet = dummy_stm_packet,
-};
+#define DUMMY_STM_MAX 32
+
+static struct stm_data dummy_stm[DUMMY_STM_MAX];
+
+static int nr_dummies = 4;
+
+module_param(nr_dummies, int, 0600);
+
+static unsigned int dummy_stm_nr;
static int dummy_stm_init(void)
{
- return stm_register_device(NULL, &dummy_stm, THIS_MODULE);
+ int i, ret = -ENOMEM, __nr_dummies = ACCESS_ONCE(nr_dummies);
+
+ if (__nr_dummies < 0 || __nr_dummies > DUMMY_STM_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < __nr_dummies; i++) {
+ dummy_stm[i].name = kasprintf(GFP_KERNEL, "dummy_stm.%d", i);
+ if (!dummy_stm[i].name)
+ goto fail_unregister;
+
+ dummy_stm[i].sw_start = 0x0000;
+ dummy_stm[i].sw_end = 0xffff;
+ dummy_stm[i].sw_nchannels = 0xffff;
+ dummy_stm[i].packet = dummy_stm_packet;
+
+ ret = stm_register_device(NULL, &dummy_stm[i], THIS_MODULE);
+ if (ret)
+ goto fail_free;
+ }
+
+ dummy_stm_nr = __nr_dummies;
+
+ return 0;
+
+fail_unregister:
+ for (i--; i >= 0; i--) {
+ stm_unregister_device(&dummy_stm[i]);
+fail_free:
+ kfree(dummy_stm[i].name);
+ }
+
+ return ret;
+
}
static void dummy_stm_exit(void)
{
- stm_unregister_device(&dummy_stm);
+ int i;
+
+ for (i = 0; i < dummy_stm_nr; i++) {
+ stm_unregister_device(&dummy_stm[i]);
+ kfree(dummy_stm[i].name);
+ }
}
module_init(dummy_stm_init);
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 14/20] stm class: Add heartbeat stm source device
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (12 preceding siblings ...)
2016-02-15 17:12 ` [PATCH 13/20] stm class: dummy_stm: Create multiple devices Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 15/20] stm class: Fix unlocking braino in the error path Alexander Shishkin
` (5 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
Heartbeat stm source may have multiple instances (for connecting to
different stm devices). Each instance will send a periodic test message
over its stm device when it is linked. This can be used for testing stm
class framework, stm device drivers or as a heartbeat over the stm link.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/Kconfig | 11 ++++
drivers/hwtracing/stm/Makefile | 2 +
drivers/hwtracing/stm/heartbeat.c | 130 ++++++++++++++++++++++++++++++++++++++
3 files changed, 143 insertions(+)
create mode 100644 drivers/hwtracing/stm/heartbeat.c
diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig
index e0ac753955..847a39b353 100644
--- a/drivers/hwtracing/stm/Kconfig
+++ b/drivers/hwtracing/stm/Kconfig
@@ -28,4 +28,15 @@ config STM_SOURCE_CONSOLE
If you want to send kernel console messages over STM devices,
say Y.
+config STM_SOURCE_HEARTBEAT
+ tristate "Heartbeat over STM devices"
+ help
+ This is a kernel space trace source that sends periodic
+ heartbeat messages to trace hosts over STM devices. It is
+ also useful for testing stm class drivers and the stm class
+ framework itself.
+
+ If you want to send heartbeat messages over STM devices,
+ say Y.
+
endif
diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile
index f9312c38dd..a9ce3d487e 100644
--- a/drivers/hwtracing/stm/Makefile
+++ b/drivers/hwtracing/stm/Makefile
@@ -5,5 +5,7 @@ stm_core-y := core.o policy.o
obj-$(CONFIG_STM_DUMMY) += dummy_stm.o
obj-$(CONFIG_STM_SOURCE_CONSOLE) += stm_console.o
+obj-$(CONFIG_STM_SOURCE_HEARTBEAT) += stm_heartbeat.o
stm_console-y := console.o
+stm_heartbeat-y := heartbeat.o
diff --git a/drivers/hwtracing/stm/heartbeat.c b/drivers/hwtracing/stm/heartbeat.c
new file mode 100644
index 0000000000..0133571b50
--- /dev/null
+++ b/drivers/hwtracing/stm/heartbeat.c
@@ -0,0 +1,130 @@
+/*
+ * Simple heartbeat STM source driver
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Heartbeat STM source will send repetitive messages over STM devices to a
+ * trace host.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hrtimer.h>
+#include <linux/slab.h>
+#include <linux/stm.h>
+
+#define STM_HEARTBEAT_MAX 32
+
+static int nr_devs = 4;
+static int interval_ms = 10;
+
+module_param(nr_devs, int, 0600);
+module_param(interval_ms, int, 0600);
+
+static struct stm_heartbeat {
+ struct stm_source_data data;
+ struct hrtimer hrtimer;
+ unsigned int active;
+} stm_heartbeat[STM_HEARTBEAT_MAX];
+
+static unsigned int nr_instances;
+
+static const char str[] = "heartbeat stm source driver is here to serve you";
+
+static enum hrtimer_restart stm_heartbeat_hrtimer_handler(struct hrtimer *hr)
+{
+ struct stm_heartbeat *heartbeat = container_of(hr, struct stm_heartbeat,
+ hrtimer);
+
+ stm_source_write(&heartbeat->data, 0, str, sizeof str);
+ if (heartbeat->active)
+ hrtimer_forward_now(hr, ms_to_ktime(interval_ms));
+
+ return heartbeat->active ? HRTIMER_RESTART : HRTIMER_NORESTART;
+}
+
+static int stm_heartbeat_link(struct stm_source_data *data)
+{
+ struct stm_heartbeat *heartbeat =
+ container_of(data, struct stm_heartbeat, data);
+
+ heartbeat->active = 1;
+ hrtimer_start(&heartbeat->hrtimer, ms_to_ktime(interval_ms),
+ HRTIMER_MODE_ABS);
+
+ return 0;
+}
+
+static void stm_heartbeat_unlink(struct stm_source_data *data)
+{
+ struct stm_heartbeat *heartbeat =
+ container_of(data, struct stm_heartbeat, data);
+
+ heartbeat->active = 0;
+ hrtimer_cancel(&heartbeat->hrtimer);
+}
+
+static int stm_heartbeat_init(void)
+{
+ int i, ret = -ENOMEM, __nr_instances = ACCESS_ONCE(nr_devs);
+
+ if (__nr_instances < 0 || __nr_instances > STM_HEARTBEAT_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < __nr_instances; i++) {
+ stm_heartbeat[i].data.name =
+ kasprintf(GFP_KERNEL, "heartbeat.%d", i);
+ if (!stm_heartbeat[i].data.name)
+ goto fail_unregister;
+
+ stm_heartbeat[i].data.nr_chans = 1;
+ stm_heartbeat[i].data.link = stm_heartbeat_link;
+ stm_heartbeat[i].data.unlink = stm_heartbeat_unlink;
+ hrtimer_init(&stm_heartbeat[i].hrtimer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_ABS);
+ stm_heartbeat[i].hrtimer.function =
+ stm_heartbeat_hrtimer_handler;
+
+ ret = stm_source_register_device(NULL, &stm_heartbeat[i].data);
+ if (ret)
+ goto fail_free;
+ }
+
+ nr_instances = __nr_instances;
+
+ return 0;
+
+fail_unregister:
+ for (i--; i >= 0; i--) {
+ stm_source_unregister_device(&stm_heartbeat[i].data);
+fail_free:
+ kfree(stm_heartbeat[i].data.name);
+ }
+
+ return ret;
+}
+
+static void stm_heartbeat_exit(void)
+{
+ int i;
+
+ for (i = 0; i < nr_instances; i++) {
+ stm_source_unregister_device(&stm_heartbeat[i].data);
+ kfree(stm_heartbeat[i].data.name);
+ }
+}
+
+module_init(stm_heartbeat_init);
+module_exit(stm_heartbeat_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("stm_heartbeat driver");
+MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 15/20] stm class: Fix unlocking braino in the error path
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (13 preceding siblings ...)
2016-02-15 17:12 ` [PATCH 14/20] stm class: Add heartbeat stm source device Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 16/20] stm class: Guard output assignment against concurrency Alexander Shishkin
` (4 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
If an illegal attempt is made to unlink stm source device from an
stm device, the stm device's link spinlock mistakenly remains locked.
While this really shouldn't happen (there's a warning in place), the
locking should remain in order so that we can still recover from this
situation if it indeed does happen.
This patch unifies the unlocking in the exit path of
__stm_source_link_drop() to fix this.
Reported-by: Laurent Fert <laurent.fert@intel.com>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/core.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index 0db303b50e..4a626d8990 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -816,10 +816,8 @@ static void __stm_source_link_drop(struct stm_source_device *src,
spin_lock(&stm->link_lock);
spin_lock(&src->link_lock);
link = srcu_dereference_check(src->link, &stm_source_srcu, 1);
- if (WARN_ON_ONCE(link != stm)) {
- spin_unlock(&src->link_lock);
- return;
- }
+ if (WARN_ON_ONCE(link != stm))
+ goto unlock;
stm_output_free(link, &src->output);
list_del_init(&src->link_entry);
@@ -827,6 +825,7 @@ static void __stm_source_link_drop(struct stm_source_device *src,
stm_put_device(link);
rcu_assign_pointer(src->link, NULL);
+unlock:
spin_unlock(&src->link_lock);
spin_unlock(&stm->link_lock);
}
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 16/20] stm class: Guard output assignment against concurrency
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (14 preceding siblings ...)
2016-02-15 17:12 ` [PATCH 15/20] stm class: Fix unlocking braino in the error path Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 17/20] stm class: Fix unbalanced module/device refcounting Alexander Shishkin
` (3 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
It is possible to concurrently assign the same output (a character
device writer or an stm_source device) to different stm devices,
which sets off a strategically placed warning in stm_output_assign().
To avoid this, use a spinlock to serialize (un)assignments between
outputs and stm devices.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/core.c | 17 +++++++++++++++++
drivers/hwtracing/stm/stm.h | 1 +
2 files changed, 18 insertions(+)
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index 4a626d8990..f6ade21729 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -185,6 +185,9 @@ static void stm_output_claim(struct stm_device *stm, struct stm_output *output)
{
struct stp_master *master = stm_master(stm, output->master);
+ lockdep_assert_held(&stm->mc_lock);
+ lockdep_assert_held(&output->lock);
+
if (WARN_ON_ONCE(master->nr_free < output->nr_chans))
return;
@@ -199,6 +202,9 @@ stm_output_disclaim(struct stm_device *stm, struct stm_output *output)
{
struct stp_master *master = stm_master(stm, output->master);
+ lockdep_assert_held(&stm->mc_lock);
+ lockdep_assert_held(&output->lock);
+
bitmap_release_region(&master->chan_map[0], output->channel,
ilog2(output->nr_chans));
@@ -288,6 +294,7 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width,
}
spin_lock(&stm->mc_lock);
+ spin_lock(&output->lock);
/* output is already assigned -- shouldn't happen */
if (WARN_ON_ONCE(output->nr_chans))
goto unlock;
@@ -304,6 +311,7 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width,
ret = 0;
unlock:
+ spin_unlock(&output->lock);
spin_unlock(&stm->mc_lock);
return ret;
@@ -312,11 +320,18 @@ unlock:
static void stm_output_free(struct stm_device *stm, struct stm_output *output)
{
spin_lock(&stm->mc_lock);
+ spin_lock(&output->lock);
if (output->nr_chans)
stm_output_disclaim(stm, output);
+ spin_unlock(&output->lock);
spin_unlock(&stm->mc_lock);
}
+static void stm_output_init(struct stm_output *output)
+{
+ spin_lock_init(&output->lock);
+}
+
static int major_match(struct device *dev, const void *data)
{
unsigned int major = *(unsigned int *)data;
@@ -339,6 +354,7 @@ static int stm_char_open(struct inode *inode, struct file *file)
if (!stmf)
return -ENOMEM;
+ stm_output_init(&stmf->output);
stmf->stm = to_stm_device(dev);
if (!try_module_get(stmf->stm->owner))
@@ -952,6 +968,7 @@ int stm_source_register_device(struct device *parent,
if (err)
goto err;
+ stm_output_init(&src->output);
spin_lock_init(&src->link_lock);
INIT_LIST_HEAD(&src->link_entry);
src->data = data;
diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h
index 97ee022414..4e8c692626 100644
--- a/drivers/hwtracing/stm/stm.h
+++ b/drivers/hwtracing/stm/stm.h
@@ -57,6 +57,7 @@ struct stm_device {
container_of((_d), struct stm_device, dev)
struct stm_output {
+ spinlock_t lock;
unsigned int master;
unsigned int channel;
unsigned int nr_chans;
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 17/20] stm class: Fix unbalanced module/device refcounting
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (15 preceding siblings ...)
2016-02-15 17:12 ` [PATCH 16/20] stm class: Guard output assignment against concurrency Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 18/20] stm class: Fix a race in unlinking Alexander Shishkin
` (2 subsequent siblings)
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
STM code takes references to the stm device and its module for the
duration of the character device's existence or the stm_source link.
Dropping these references is not well balanced everywhere, which may
lead to leaks.
This patch balances the acquisition and releasing of these two
references and annotates each site so that it's easier to verify
correctness by reading the code.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/core.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index f6ade21729..f86f56d853 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -113,6 +113,7 @@ struct stm_device *stm_find_device(const char *buf)
stm = to_stm_device(dev);
if (!try_module_get(stm->owner)) {
+ /* matches class_find_device() above */
put_device(dev);
return NULL;
}
@@ -125,7 +126,7 @@ struct stm_device *stm_find_device(const char *buf)
* @stm: stm device, previously acquired by stm_find_device()
*
* This drops the module reference and device reference taken by
- * stm_find_device().
+ * stm_find_device() or stm_char_open().
*/
void stm_put_device(struct stm_device *stm)
{
@@ -365,6 +366,8 @@ static int stm_char_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
err_free:
+ /* matches class_find_device() above */
+ put_device(dev);
kfree(stmf);
return err;
@@ -375,6 +378,11 @@ static int stm_char_release(struct inode *inode, struct file *file)
struct stm_file *stmf = file->private_data;
stm_output_free(stmf->stm, &stmf->output);
+
+ /*
+ * matches the stm_char_open()'s
+ * class_find_device() + try_module_get()
+ */
stm_put_device(stmf->stm);
kfree(stmf);
@@ -539,10 +547,8 @@ static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg)
ret = stm->data->link(stm->data, stmf->output.master,
stmf->output.channel);
- if (ret) {
+ if (ret)
stm_output_free(stmf->stm, &stmf->output);
- stm_put_device(stmf->stm);
- }
err_free:
kfree(id);
@@ -679,6 +685,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data,
return 0;
err_device:
+ /* matches device_initialize() above */
put_device(&stm->dev);
err_free:
kfree(stm);
@@ -791,7 +798,6 @@ static int stm_source_link_add(struct stm_source_device *src,
fail_free_output:
stm_output_free(stm, &src->output);
- stm_put_device(stm);
fail_detach:
mutex_lock(&stm->link_mutex);
@@ -905,8 +911,10 @@ static ssize_t stm_source_link_store(struct device *dev,
return -EINVAL;
err = stm_source_link_add(src, link);
- if (err)
+ if (err) {
+ /* matches the stm_find_device() above */
stm_put_device(link);
+ }
return err ? : count;
}
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 18/20] stm class: Fix a race in unlinking
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (16 preceding siblings ...)
2016-02-15 17:12 ` [PATCH 17/20] stm class: Fix unbalanced module/device refcounting Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 19/20] stm class: Plug stm device's unlink callback Alexander Shishkin
2016-02-15 17:12 ` [PATCH 20/20] stm class: dummy_stm: Add link callback for fault injection Alexander Shishkin
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
There is a window in stm_source_link_drop(), during which the source's
link may change before locks are acquired. When this happens, it throws
a warning, since this is not an expected scenario.
This patch handles the race in such a way that if the link appears to
have changed by the time we took the locks, it will release them and
repeat the whole unlinking procedure from the beginning, unless the
other contender beat us to it.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/core.c | 54 ++++++++++++++++++++++++++++++++++----------
1 file changed, 42 insertions(+), 12 deletions(-)
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index f86f56d853..30181821d9 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -694,18 +694,26 @@ err_free:
}
EXPORT_SYMBOL_GPL(stm_register_device);
-static void __stm_source_link_drop(struct stm_source_device *src,
- struct stm_device *stm);
+static int __stm_source_link_drop(struct stm_source_device *src,
+ struct stm_device *stm);
void stm_unregister_device(struct stm_data *stm_data)
{
struct stm_device *stm = stm_data->stm;
struct stm_source_device *src, *iter;
- int i;
+ int i, ret;
mutex_lock(&stm->link_mutex);
list_for_each_entry_safe(src, iter, &stm->link_list, link_entry) {
- __stm_source_link_drop(src, stm);
+ ret = __stm_source_link_drop(src, stm);
+ /*
+ * src <-> stm link must not change under the same
+ * stm::link_mutex, so complain loudly if it has;
+ * also in this situation ret!=0 means this src is
+ * not connected to this stm and it should be otherwise
+ * safe to proceed with the tear-down of stm.
+ */
+ WARN_ON_ONCE(ret);
}
mutex_unlock(&stm->link_mutex);
@@ -824,22 +832,28 @@ fail_detach:
*
* Caller must hold stm::link_mutex.
*/
-static void __stm_source_link_drop(struct stm_source_device *src,
- struct stm_device *stm)
+static int __stm_source_link_drop(struct stm_source_device *src,
+ struct stm_device *stm)
{
struct stm_device *link;
+ int ret = 0;
lockdep_assert_held(&stm->link_mutex);
- if (src->data->unlink)
- src->data->unlink(src->data);
-
/* for stm::link_list modification, we hold both mutex and spinlock */
spin_lock(&stm->link_lock);
spin_lock(&src->link_lock);
link = srcu_dereference_check(src->link, &stm_source_srcu, 1);
- if (WARN_ON_ONCE(link != stm))
+
+ /*
+ * The linked device may have changed since we last looked, because
+ * we weren't holding the src::link_lock back then; if this is the
+ * case, tell the caller to retry.
+ */
+ if (link != stm) {
+ ret = -EAGAIN;
goto unlock;
+ }
stm_output_free(link, &src->output);
list_del_init(&src->link_entry);
@@ -850,6 +864,11 @@ static void __stm_source_link_drop(struct stm_source_device *src,
unlock:
spin_unlock(&src->link_lock);
spin_unlock(&stm->link_lock);
+
+ if (!ret && src->data->unlink)
+ src->data->unlink(src->data);
+
+ return ret;
}
/**
@@ -865,18 +884,29 @@ unlock:
static void stm_source_link_drop(struct stm_source_device *src)
{
struct stm_device *stm;
- int idx;
+ int idx, ret;
+retry:
idx = srcu_read_lock(&stm_source_srcu);
+ /*
+ * The stm device will be valid for the duration of this
+ * read section, but the link may change before we grab
+ * the src::link_lock in __stm_source_link_drop().
+ */
stm = srcu_dereference(src->link, &stm_source_srcu);
+ ret = 0;
if (stm) {
mutex_lock(&stm->link_mutex);
- __stm_source_link_drop(src, stm);
+ ret = __stm_source_link_drop(src, stm);
mutex_unlock(&stm->link_mutex);
}
srcu_read_unlock(&stm_source_srcu, idx);
+
+ /* if it did change, retry */
+ if (ret == -EAGAIN)
+ goto retry;
}
static ssize_t stm_source_link_show(struct device *dev,
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 19/20] stm class: Plug stm device's unlink callback
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (17 preceding siblings ...)
2016-02-15 17:12 ` [PATCH 18/20] stm class: Fix a race in unlinking Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
2016-02-15 17:12 ` [PATCH 20/20] stm class: dummy_stm: Add link callback for fault injection Alexander Shishkin
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
STM device's unlink callback is never actually called from anywhere in
the stm class code.
This patch adds calls to stm driver's unlink method after the unlinking
has succeeded.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/core.c | 23 +++++++++++++++++++----
include/linux/stm.h | 3 +++
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index 30181821d9..de80d45d8d 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -376,14 +376,19 @@ err_free:
static int stm_char_release(struct inode *inode, struct file *file)
{
struct stm_file *stmf = file->private_data;
+ struct stm_device *stm = stmf->stm;
+
+ if (stm->data->unlink)
+ stm->data->unlink(stm->data, stmf->output.master,
+ stmf->output.channel);
- stm_output_free(stmf->stm, &stmf->output);
+ stm_output_free(stm, &stmf->output);
/*
* matches the stm_char_open()'s
* class_find_device() + try_module_get()
*/
- stm_put_device(stmf->stm);
+ stm_put_device(stm);
kfree(stmf);
return 0;
@@ -865,8 +870,18 @@ unlock:
spin_unlock(&src->link_lock);
spin_unlock(&stm->link_lock);
- if (!ret && src->data->unlink)
- src->data->unlink(src->data);
+ /*
+ * Call the unlink callbacks for both source and stm, when we know
+ * that we have actually performed the unlinking.
+ */
+ if (!ret) {
+ if (src->data->unlink)
+ src->data->unlink(src->data);
+
+ if (stm->data->unlink)
+ stm->data->unlink(stm->data, src->output.master,
+ src->output.channel);
+ }
return ret;
}
diff --git a/include/linux/stm.h b/include/linux/stm.h
index ab8ceca4f5..1a79ed8e43 100644
--- a/include/linux/stm.h
+++ b/include/linux/stm.h
@@ -74,6 +74,9 @@ struct stm_device;
* it must return zero;
* 3) if it does not support the requested packet type/flag combination,
* it must return -ENOTSUPP.
+ *
+ * The @unlink callback is called when there are no more active writers so
+ * that the master/channel can be quiesced.
*/
struct stm_data {
const char *name;
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 20/20] stm class: dummy_stm: Add link callback for fault injection
2016-02-15 17:11 ` [PATCH 00/20] " Alexander Shishkin
` (18 preceding siblings ...)
2016-02-15 17:12 ` [PATCH 19/20] stm class: Plug stm device's unlink callback Alexander Shishkin
@ 2016-02-15 17:12 ` Alexander Shishkin
19 siblings, 0 replies; 33+ messages in thread
From: Alexander Shishkin @ 2016-02-15 17:12 UTC (permalink / raw)
To: Greg KH
Cc: Mathieu Poirier, Chunyan Zhang, laurent.fert, yann.fouassier,
linux-kernel, Alexander Shishkin
STM device's link callback has the power to abort master/channel
assignment by returning a negative error code. Use this in dummy
stm device to optionally abort assigning certain channel IDs.
This is useful as fault injection into the stm class core, for
testing purposes.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
drivers/hwtracing/stm/dummy_stm.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/hwtracing/stm/dummy_stm.c b/drivers/hwtracing/stm/dummy_stm.c
index 4ff5961cd3..310adf57e7 100644
--- a/drivers/hwtracing/stm/dummy_stm.c
+++ b/drivers/hwtracing/stm/dummy_stm.c
@@ -50,6 +50,19 @@ module_param(nr_dummies, int, 0600);
static unsigned int dummy_stm_nr;
+static unsigned int fail_mode;
+
+module_param(fail_mode, int, 0600);
+
+static int dummy_stm_link(struct stm_data *data, unsigned int master,
+ unsigned int channel)
+{
+ if (fail_mode && (channel & fail_mode))
+ return -EINVAL;
+
+ return 0;
+}
+
static int dummy_stm_init(void)
{
int i, ret = -ENOMEM, __nr_dummies = ACCESS_ONCE(nr_dummies);
@@ -66,6 +79,7 @@ static int dummy_stm_init(void)
dummy_stm[i].sw_end = 0xffff;
dummy_stm[i].sw_nchannels = 0xffff;
dummy_stm[i].packet = dummy_stm_packet;
+ dummy_stm[i].link = dummy_stm_link;
ret = stm_register_device(NULL, &dummy_stm[i], THIS_MODULE);
if (ret)
--
2.7.0
^ permalink raw reply related [flat|nested] 33+ messages in thread