mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
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 -----BEGIN PGP SIGNATURE----- iIIEABEIACoFAlgvHY8jHGFsZXhhbmRlci5zaGlzaGtpbkBsaW51eC5pbnRlbC5j b20ACgkQ68X2JGMFV/8SEAD/aBk+2zVndY2qSmLg5rZtqKQj/xjAXHhdEB86JT6W DvUA/RrWFQ1K4s9aOjpjHXDi91w8AoBqCBxXt56r45xxeuKc =VhIw -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
38d1790644
@ -97,3 +97,25 @@ $ echo 0 > /sys/bus/intel_th/devices/0-msc0/active
|
||||
# and now you can collect the trace from the device node:
|
||||
|
||||
$ cat /dev/intel_th0/msc0 > my_stp_trace
|
||||
|
||||
Host Debugger Mode
|
||||
==================
|
||||
|
||||
It is possible to configure the Trace Hub and control its trace
|
||||
capture from a remote debug host, which should be connected via one of
|
||||
the hardware debugging interfaces, which will then be used to both
|
||||
control Intel Trace Hub and transfer its trace data to the debug host.
|
||||
|
||||
The driver needs to be told that such an arrangement is taking place
|
||||
so that it does not touch any capture/port configuration and avoids
|
||||
conflicting with the debug host's configuration accesses. The only
|
||||
activity that the driver will perform in this mode is collecting
|
||||
software traces to the Software Trace Hub (an stm class device). The
|
||||
user is still responsible for setting up adequate master/channel
|
||||
mappings that the decoder on the receiving end would recognize.
|
||||
|
||||
In order to enable the host mode, set the 'host_mode' parameter of the
|
||||
'intel_th' kernel module to 'y'. None of the virtual output devices
|
||||
will show up on the intel_th bus. Also, trace configuration and
|
||||
capture controlling attribute groups of the 'gth' device will not be
|
||||
exposed. The 'sth' device will operate as usual.
|
||||
|
@ -69,12 +69,43 @@ stm device's channel mmio region is 64 bytes and hardware page size is
|
||||
width==64, you should be able to mmap() one page on this file
|
||||
descriptor and obtain direct access to an mmio region for 64 channels.
|
||||
|
||||
For kernel-based trace sources, there is "stm_source" device
|
||||
class. Devices of this class can be connected and disconnected to/from
|
||||
stm devices at runtime via a sysfs attribute.
|
||||
|
||||
Examples of STM devices are Intel(R) Trace Hub [1] and Coresight STM
|
||||
[2].
|
||||
|
||||
stm_source
|
||||
==========
|
||||
|
||||
For kernel-based trace sources, there is "stm_source" device
|
||||
class. Devices of this class can be connected and disconnected to/from
|
||||
stm devices at runtime via a sysfs attribute called "stm_source_link"
|
||||
by writing the name of the desired stm device there, for example:
|
||||
|
||||
$ echo dummy_stm.0 > /sys/class/stm_source/console/stm_source_link
|
||||
|
||||
For examples on how to use stm_source interface in the kernel, refer
|
||||
to stm_console or stm_heartbeat drivers.
|
||||
|
||||
Each stm_source device will need to assume a master and a range of
|
||||
channels, depending on how many channels it requires. These are
|
||||
allocated for the device according to the policy configuration. If
|
||||
there's a node in the root of the policy directory that matches the
|
||||
stm_source device's name (for example, "console"), this node will be
|
||||
used to allocate master and channel numbers. If there's no such policy
|
||||
node, the stm core will pick the first contiguous chunk of channels
|
||||
within the first available master. Note that the node must exist
|
||||
before the stm_source device is connected to its stm device.
|
||||
|
||||
stm_console
|
||||
===========
|
||||
|
||||
One implementation of this interface also used in the example above is
|
||||
the "stm_console" driver, which basically provides a one-way console
|
||||
for kernel messages over an stm device.
|
||||
|
||||
To configure the master/channel pair that will be assigned to this
|
||||
console in the STP stream, create a "console" policy entry (see the
|
||||
beginning of this text on how to do that). When initialized, it will
|
||||
consume one channel.
|
||||
|
||||
[1] https://software.intel.com/sites/default/files/managed/d3/3c/intel-th-developer-manual.pdf
|
||||
[2] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0444b/index.html
|
||||
|
@ -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);
|
||||
|
@ -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(>h->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(>h->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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user