lkml.org 
[lkml]   [2015]   [Sep]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v4 10/11] intel_th: Add PTI output driver
    Date
    Parallel Trace Interface (PTI) unit is a trace output device that sends
    data over a PTI port.

    The driver provides interfaces to configure bus width, bus clock divider
    and mode. Tracing is enabled via output device's "active" attribute.

    Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
    ---
    .../ABI/testing/sysfs-bus-intel_th-devices-pti | 24 ++
    drivers/hwtracing/intel_th/Kconfig | 9 +
    drivers/hwtracing/intel_th/Makefile | 3 +
    drivers/hwtracing/intel_th/pti.c | 252 +++++++++++++++++++++
    drivers/hwtracing/intel_th/pti.h | 29 +++
    5 files changed, 317 insertions(+)
    create mode 100644 Documentation/ABI/testing/sysfs-bus-intel_th-devices-pti
    create mode 100644 drivers/hwtracing/intel_th/pti.c
    create mode 100644 drivers/hwtracing/intel_th/pti.h

    diff --git a/Documentation/ABI/testing/sysfs-bus-intel_th-devices-pti b/Documentation/ABI/testing/sysfs-bus-intel_th-devices-pti
    new file mode 100644
    index 0000000000..df0b24fd02
    --- /dev/null
    +++ b/Documentation/ABI/testing/sysfs-bus-intel_th-devices-pti
    @@ -0,0 +1,24 @@
    +What: /sys/bus/intel_th/devices/<intel_th_id>-pti/mode
    +Date: June 2015
    +KernelVersion: 4.3
    +Contact: Alexander Shishkin <alexander.shishkin@linux.intel.com>
    +Description: (RW) Configure PTI output width. Currently supported values
    + are 4, 8, 12, 16.
    +
    +What: /sys/bus/intel_th/devices/<intel_th_id>-pti/freerunning_clock
    +Date: June 2015
    +KernelVersion: 4.3
    +Contact: Alexander Shishkin <alexander.shishkin@linux.intel.com>
    +Description: (RW) 0: PTI trace clock acts as a strobe which only toggles
    + when there is trace data to send. 1: PTI trace clock is a
    + free-running clock.
    +
    +What: /sys/bus/intel_th/devices/<intel_th_id>-pti/clock_divider
    +Date: June 2015
    +KernelVersion: 4.3
    +Contact: Alexander Shishkin <alexander.shishkin@linux.intel.com>
    +Description: (RW) Configure PTI port clock divider:
    + - 0: Intel TH clock rate,
    + - 1: 1/2 Intel TH clock rate,
    + - 2: 1/4 Intel TH clock rate,
    + - 3: 1/8 Intel TH clock rate.
    diff --git a/drivers/hwtracing/intel_th/Kconfig b/drivers/hwtracing/intel_th/Kconfig
    index d9a1217e27..b7a9073d96 100644
    --- a/drivers/hwtracing/intel_th/Kconfig
    +++ b/drivers/hwtracing/intel_th/Kconfig
    @@ -54,6 +54,15 @@ config INTEL_TH_MSU

    Say Y here to enable MSU output device for Intel TH.

    +config INTEL_TH_PTI
    + tristate "Intel(R) Trace Hub PTI output"
    + help
    + Parallel Trace Interface unit (PTI) is a trace output device
    + of Intel TH architecture that facilitates STP trace output via
    + a PTI port.
    +
    + Say Y to enable PTI output of Intel TH data.
    +
    config INTEL_TH_DEBUG
    bool "Intel(R) Trace Hub debugging"
    depends on DEBUG_FS
    diff --git a/drivers/hwtracing/intel_th/Makefile b/drivers/hwtracing/intel_th/Makefile
    index 4636757df2..81d42fe918 100644
    --- a/drivers/hwtracing/intel_th/Makefile
    +++ b/drivers/hwtracing/intel_th/Makefile
    @@ -13,3 +13,6 @@ intel_th_sth-y := sth.o

    obj-$(CONFIG_INTEL_TH_MSU) += intel_th_msu.o
    intel_th_msu-y := msu.o
    +
    +obj-$(CONFIG_INTEL_TH_PTI) += intel_th_pti.o
    +intel_th_pti-y := pti.o
    diff --git a/drivers/hwtracing/intel_th/pti.c b/drivers/hwtracing/intel_th/pti.c
    new file mode 100644
    index 0000000000..1e3bbc8982
    --- /dev/null
    +++ b/drivers/hwtracing/intel_th/pti.c
    @@ -0,0 +1,252 @@
    +/*
    + * Intel(R) Trace Hub PTI output driver
    + *
    + * Copyright (C) 2014-2015 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.
    + */
    +
    +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
    +
    +#include <linux/types.h>
    +#include <linux/module.h>
    +#include <linux/device.h>
    +#include <linux/sizes.h>
    +#include <linux/printk.h>
    +#include <linux/slab.h>
    +#include <linux/mm.h>
    +#include <linux/io.h>
    +
    +#include "intel_th.h"
    +#include "pti.h"
    +
    +struct pti_device {
    + void __iomem *base;
    + struct intel_th_device *thdev;
    + unsigned int mode;
    + unsigned int freeclk;
    + unsigned int clkdiv;
    + unsigned int patgen;
    +};
    +
    +/* map PTI widths to MODE settings of PTI_CTL register */
    +static const unsigned int pti_mode[] = {
    + 0, 4, 8, 0, 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,
    +};
    +
    +static int pti_width_mode(unsigned int width)
    +{
    + int i;
    +
    + for (i = 0; i < ARRAY_SIZE(pti_mode); i++)
    + if (pti_mode[i] == width)
    + return i;
    +
    + return -EINVAL;
    +}
    +
    +static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
    + char *buf)
    +{
    + struct pti_device *pti = dev_get_drvdata(dev);
    +
    + return scnprintf(buf, PAGE_SIZE, "%d\n", pti_mode[pti->mode]);
    +}
    +
    +static ssize_t mode_store(struct device *dev, struct device_attribute *attr,
    + const char *buf, size_t size)
    +{
    + struct pti_device *pti = dev_get_drvdata(dev);
    + unsigned long val;
    + int ret;
    +
    + ret = kstrtoul(buf, 10, &val);
    + if (ret)
    + return ret;
    +
    + ret = pti_width_mode(val);
    + if (ret < 0)
    + return ret;
    +
    + pti->mode = ret;
    +
    + return size;
    +}
    +
    +static DEVICE_ATTR_RW(mode);
    +
    +static ssize_t
    +freerunning_clock_show(struct device *dev, struct device_attribute *attr,
    + char *buf)
    +{
    + struct pti_device *pti = dev_get_drvdata(dev);
    +
    + return scnprintf(buf, PAGE_SIZE, "%d\n", pti->freeclk);
    +}
    +
    +static ssize_t
    +freerunning_clock_store(struct device *dev, struct device_attribute *attr,
    + const char *buf, size_t size)
    +{
    + struct pti_device *pti = dev_get_drvdata(dev);
    + unsigned long val;
    + int ret;
    +
    + ret = kstrtoul(buf, 10, &val);
    + if (ret)
    + return ret;
    +
    + pti->freeclk = !!val;
    +
    + return size;
    +}
    +
    +static DEVICE_ATTR_RW(freerunning_clock);
    +
    +static ssize_t
    +clock_divider_show(struct device *dev, struct device_attribute *attr,
    + char *buf)
    +{
    + struct pti_device *pti = dev_get_drvdata(dev);
    +
    + return scnprintf(buf, PAGE_SIZE, "%d\n", 1u << pti->clkdiv);
    +}
    +
    +static ssize_t
    +clock_divider_store(struct device *dev, struct device_attribute *attr,
    + const char *buf, size_t size)
    +{
    + struct pti_device *pti = dev_get_drvdata(dev);
    + unsigned long val;
    + int ret;
    +
    + ret = kstrtoul(buf, 10, &val);
    + if (ret)
    + return ret;
    +
    + if (!is_power_of_2(val) || val > 8 || !val)
    + return -EINVAL;
    +
    + pti->clkdiv = val;
    +
    + return size;
    +}
    +
    +static DEVICE_ATTR_RW(clock_divider);
    +
    +static struct attribute *pti_output_attrs[] = {
    + &dev_attr_mode.attr,
    + &dev_attr_freerunning_clock.attr,
    + &dev_attr_clock_divider.attr,
    + NULL,
    +};
    +
    +static struct attribute_group pti_output_group = {
    + .attrs = pti_output_attrs,
    +};
    +
    +static int intel_th_pti_activate(struct intel_th_device *thdev)
    +{
    + struct pti_device *pti = dev_get_drvdata(&thdev->dev);
    + u32 ctl = PTI_EN;
    +
    + if (pti->patgen)
    + ctl |= pti->patgen << __ffs(PTI_PATGENMODE);
    + if (pti->freeclk)
    + ctl |= PTI_FCEN;
    + ctl |= pti->mode << __ffs(PTI_MODE);
    + ctl |= pti->clkdiv << __ffs(PTI_CLKDIV);
    +
    + iowrite32(ctl, pti->base + REG_PTI_CTL);
    +
    + intel_th_trace_enable(thdev);
    +
    + return 0;
    +}
    +
    +static void intel_th_pti_deactivate(struct intel_th_device *thdev)
    +{
    + struct pti_device *pti = dev_get_drvdata(&thdev->dev);
    +
    + intel_th_trace_disable(thdev);
    +
    + iowrite32(0, pti->base + REG_PTI_CTL);
    +}
    +
    +static void read_hw_config(struct pti_device *pti)
    +{
    + u32 ctl = ioread32(pti->base + REG_PTI_CTL);
    +
    + pti->mode = (ctl & PTI_MODE) >> __ffs(PTI_MODE);
    + pti->clkdiv = (ctl & PTI_CLKDIV) >> __ffs(PTI_CLKDIV);
    + pti->freeclk = !!(ctl & PTI_FCEN);
    +
    + if (!pti_mode[pti->mode])
    + pti->mode = pti_width_mode(4);
    + if (!pti->clkdiv)
    + pti->clkdiv = 1;
    +}
    +
    +static int intel_th_pti_probe(struct intel_th_device *thdev)
    +{
    + struct device *dev = &thdev->dev;
    + struct resource *res;
    + struct pti_device *pti;
    + void __iomem *base;
    + int ret;
    +
    + res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
    + if (!res)
    + return -ENODEV;
    +
    + base = devm_ioremap(dev, res->start, resource_size(res));
    + if (IS_ERR(base))
    + return PTR_ERR(base);
    +
    + pti = devm_kzalloc(dev, sizeof(*pti), GFP_KERNEL);
    + if (!pti)
    + return -ENOMEM;
    +
    + pti->thdev = thdev;
    + pti->base = base;
    +
    + read_hw_config(pti);
    +
    + ret = sysfs_create_group(&dev->kobj, &pti_output_group);
    + if (ret)
    + return ret;
    +
    + dev_set_drvdata(dev, pti);
    +
    + return 0;
    +}
    +
    +static void intel_th_pti_remove(struct intel_th_device *thdev)
    +{
    +}
    +
    +static struct intel_th_driver intel_th_pti_driver = {
    + .probe = intel_th_pti_probe,
    + .remove = intel_th_pti_remove,
    + .activate = intel_th_pti_activate,
    + .deactivate = intel_th_pti_deactivate,
    + .driver = {
    + .name = "pti",
    + .owner = THIS_MODULE,
    + },
    +};
    +
    +module_driver(intel_th_pti_driver,
    + intel_th_driver_register,
    + intel_th_driver_unregister);
    +
    +MODULE_LICENSE("GPL v2");
    +MODULE_DESCRIPTION("Intel(R) Trace Hub PTI output driver");
    +MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
    diff --git a/drivers/hwtracing/intel_th/pti.h b/drivers/hwtracing/intel_th/pti.h
    new file mode 100644
    index 0000000000..20883f5628
    --- /dev/null
    +++ b/drivers/hwtracing/intel_th/pti.h
    @@ -0,0 +1,29 @@
    +/*
    + * Intel(R) Trace Hub PTI output data structures
    + *
    + * Copyright (C) 2014-2015 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.
    + */
    +
    +#ifndef __INTEL_TH_STH_H__
    +#define __INTEL_TH_STH_H__
    +
    +enum {
    + REG_PTI_CTL = 0x1c00,
    +};
    +
    +#define PTI_EN BIT(0)
    +#define PTI_FCEN BIT(1)
    +#define PTI_MODE 0xf0
    +#define PTI_CLKDIV 0x000f0000
    +#define PTI_PATGENMODE 0x00f00000
    +
    +#endif /* __INTEL_TH_STH_H__ */
    --
    2.5.1


    \
     
     \ /
      Last update: 2015-09-22 15:21    [W:5.221 / U:0.108 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site