summaryrefslogtreecommitdiff
path: root/drivers/hwtracing
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-11-28 08:49:30 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-11-28 08:49:30 +0100
commit38d1790644ef781c2b883dea68c8f6ba4e60e2f2 (patch)
tree0352052a9f81381232a92722c9c6515387595a88 /drivers/hwtracing
parent7c7a6077f5c7a35fc03a7f452875d8440dd1bc8d (diff)
parentee01aebbe2c4c196142bdb8074812dfe44830725 (diff)
Merge tag 'stm-for-greg-20161118' of git://git.kernel.org/pub/scm/linux/kernel/git/ash/stm into char-misc-next
Alexander writes: stm class/intel_th: Updates for 4.10 These are: * Fix for an error-path leak in stm * Host-driven mode in intel_th * Documentation and other small updates
Diffstat (limited to 'drivers/hwtracing')
-rw-r--r--drivers/hwtracing/intel_th/core.c28
-rw-r--r--drivers/hwtracing/intel_th/gth.c26
-rw-r--r--drivers/hwtracing/intel_th/intel_th.h4
-rw-r--r--drivers/hwtracing/stm/core.c8
4 files changed, 52 insertions, 14 deletions
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 6f0a51a2c6ec..cdd9b3b26195 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -29,6 +29,9 @@
#include "intel_th.h"
#include "debug.h"
+static bool host_mode __read_mostly;
+module_param(host_mode, bool, 0444);
+
static DEFINE_IDA(intel_th_ida);
static int intel_th_match(struct device *dev, struct device_driver *driver)
@@ -380,7 +383,7 @@ static void intel_th_device_free(struct intel_th_device *thdev)
/*
* Intel(R) Trace Hub subdevices
*/
-static struct intel_th_subdevice {
+static const struct intel_th_subdevice {
const char *name;
struct resource res[3];
unsigned nres;
@@ -527,14 +530,19 @@ static int intel_th_populate(struct intel_th *th, struct resource *devres,
{
struct resource res[3];
unsigned int req = 0;
- int i, err;
+ int src, dst, err;
/* create devices for each intel_th_subdevice */
- for (i = 0; i < ARRAY_SIZE(intel_th_subdevices); i++) {
- struct intel_th_subdevice *subdev = &intel_th_subdevices[i];
+ for (src = 0, dst = 0; src < ARRAY_SIZE(intel_th_subdevices); src++) {
+ const struct intel_th_subdevice *subdev =
+ &intel_th_subdevices[src];
struct intel_th_device *thdev;
int r;
+ /* only allow SOURCE and SWITCH devices in host mode */
+ if (host_mode && subdev->type == INTEL_TH_OUTPUT)
+ continue;
+
thdev = intel_th_device_alloc(th, subdev->type, subdev->name,
subdev->id);
if (!thdev) {
@@ -577,10 +585,12 @@ static int intel_th_populate(struct intel_th *th, struct resource *devres,
}
if (subdev->type == INTEL_TH_OUTPUT) {
- thdev->dev.devt = MKDEV(th->major, i);
+ thdev->dev.devt = MKDEV(th->major, dst);
thdev->output.type = subdev->otype;
thdev->output.port = -1;
thdev->output.scratchpad = subdev->scrpd;
+ } else if (subdev->type == INTEL_TH_SWITCH) {
+ thdev->host_mode = host_mode;
}
err = device_add(&thdev->dev);
@@ -597,14 +607,14 @@ static int intel_th_populate(struct intel_th *th, struct resource *devres,
req++;
}
- th->thdev[i] = thdev;
+ th->thdev[dst++] = thdev;
}
return 0;
kill_subdevs:
- for (i-- ; i >= 0; i--)
- intel_th_device_remove(th->thdev[i]);
+ for (; dst >= 0; dst--)
+ intel_th_device_remove(th->thdev[dst]);
return err;
}
@@ -717,7 +727,7 @@ void intel_th_free(struct intel_th *th)
intel_th_request_hub_module_flush(th);
for (i = 0; i < TH_SUBDEVICE_MAX; i++)
- if (th->thdev[i] != th->hub)
+ if (th->thdev[i] && th->thdev[i] != th->hub)
intel_th_device_remove(th->thdev[i]);
intel_th_device_remove(th->hub);
diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c
index 33e09369a491..dd32d0bad687 100644
--- a/drivers/hwtracing/intel_th/gth.c
+++ b/drivers/hwtracing/intel_th/gth.c
@@ -564,6 +564,9 @@ static int intel_th_gth_assign(struct intel_th_device *thdev,
struct gth_device *gth = dev_get_drvdata(&thdev->dev);
int i, id;
+ if (thdev->host_mode)
+ return -EBUSY;
+
if (othdev->type != INTEL_TH_OUTPUT)
return -EINVAL;
@@ -600,6 +603,9 @@ static void intel_th_gth_unassign(struct intel_th_device *thdev,
struct gth_device *gth = dev_get_drvdata(&thdev->dev);
int port = othdev->output.port;
+ if (thdev->host_mode)
+ return;
+
spin_lock(&gth->gth_lock);
othdev->output.port = -1;
othdev->output.active = false;
@@ -654,9 +660,24 @@ static int intel_th_gth_probe(struct intel_th_device *thdev)
gth->base = base;
spin_lock_init(&gth->gth_lock);
+ /*
+ * Host mode can be signalled via SW means or via SCRPD_DEBUGGER_IN_USE
+ * bit. Either way, don't reset HW in this case, and don't export any
+ * capture configuration attributes. Also, refuse to assign output
+ * drivers to ports, see intel_th_gth_assign().
+ */
+ if (thdev->host_mode)
+ goto done;
+
ret = intel_th_gth_reset(gth);
- if (ret)
- return ret;
+ if (ret) {
+ if (ret != -EBUSY)
+ return ret;
+
+ thdev->host_mode = true;
+
+ goto done;
+ }
for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++)
gth->master[i] = -1;
@@ -677,6 +698,7 @@ static int intel_th_gth_probe(struct intel_th_device *thdev)
return -ENOMEM;
}
+done:
dev_set_drvdata(dev, gth);
return 0;
diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h
index 4c195786bf1f..3096e7054f6d 100644
--- a/drivers/hwtracing/intel_th/intel_th.h
+++ b/drivers/hwtracing/intel_th/intel_th.h
@@ -54,6 +54,7 @@ struct intel_th_output {
* @num_resources: number of resources in @resource array
* @type: INTEL_TH_{SOURCE,OUTPUT,SWITCH}
* @id: device instance or -1
+ * @host_mode: Intel TH is controlled by an external debug host
* @output: output descriptor for INTEL_TH_OUTPUT devices
* @name: device name to match the driver
*/
@@ -64,6 +65,9 @@ struct intel_th_device {
unsigned int type;
int id;
+ /* INTEL_TH_SWITCH specific */
+ bool host_mode;
+
/* INTEL_TH_OUTPUT specific */
struct intel_th_output output;
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index 51f81d64ca37..a6ea387b5b00 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -361,7 +361,7 @@ static int stm_char_open(struct inode *inode, struct file *file)
struct stm_file *stmf;
struct device *dev;
unsigned int major = imajor(inode);
- int err = -ENODEV;
+ int err = -ENOMEM;
dev = class_find_device(&stm_class, NULL, &major, major_match);
if (!dev)
@@ -369,8 +369,9 @@ static int stm_char_open(struct inode *inode, struct file *file)
stmf = kzalloc(sizeof(*stmf), GFP_KERNEL);
if (!stmf)
- return -ENOMEM;
+ goto err_put_device;
+ err = -ENODEV;
stm_output_init(&stmf->output);
stmf->stm = to_stm_device(dev);
@@ -382,9 +383,10 @@ static int stm_char_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
err_free:
+ kfree(stmf);
+err_put_device:
/* matches class_find_device() above */
put_device(dev);
- kfree(stmf);
return err;
}