Skip to content

Commit

Permalink
Merge tag 'stm-for-greg-20160420' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/ash/stm into char-misc-next

Alexander writes:

stm class/intel_th: Updates for 4.7

These are:
 * Intel TH/MSU: improved resource handling and releasing
 * Intel TH/MSU: rehashed locking around buffer accesses
 * Intel TH/outputs: better sysfs group handling
 * Intel TH, STM: various bugfixes and smaller improvements
 * Intel TH: added a PCI ID for Broxton-M SOC
  • Loading branch information
Greg Kroah-Hartman committed Apr 27, 2016
2 parents 7553c7e + aaa3ca8 commit 2fc5dda
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 86 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -9754,6 +9754,7 @@ F: drivers/mmc/host/dw_mmc*
SYSTEM TRACE MODULE CLASS
M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ash/stm.git
F: Documentation/trace/stm.txt
F: drivers/hwtracing/stm/
F: include/linux/stm.h
Expand Down
29 changes: 27 additions & 2 deletions drivers/hwtracing/intel_th/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ static int intel_th_probe(struct device *dev)
if (ret)
return ret;

if (thdrv->attr_group) {
ret = sysfs_create_group(&thdev->dev.kobj, thdrv->attr_group);
if (ret) {
thdrv->remove(thdev);

return ret;
}
}

if (thdev->type == INTEL_TH_OUTPUT &&
!intel_th_output_assigned(thdev))
ret = hubdrv->assign(hub, thdev);
Expand All @@ -91,6 +100,9 @@ static int intel_th_remove(struct device *dev)
return err;
}

if (thdrv->attr_group)
sysfs_remove_group(&thdev->dev.kobj, thdrv->attr_group);

thdrv->remove(thdev);

if (intel_th_output_assigned(thdev)) {
Expand Down Expand Up @@ -171,7 +183,14 @@ static DEVICE_ATTR_RO(port);

static int intel_th_output_activate(struct intel_th_device *thdev)
{
struct intel_th_driver *thdrv = to_intel_th_driver(thdev->dev.driver);
struct intel_th_driver *thdrv =
to_intel_th_driver_or_null(thdev->dev.driver);

if (!thdrv)
return -ENODEV;

if (!try_module_get(thdrv->driver.owner))
return -ENODEV;

if (thdrv->activate)
return thdrv->activate(thdev);
Expand All @@ -183,12 +202,18 @@ static int intel_th_output_activate(struct intel_th_device *thdev)

static void intel_th_output_deactivate(struct intel_th_device *thdev)
{
struct intel_th_driver *thdrv = to_intel_th_driver(thdev->dev.driver);
struct intel_th_driver *thdrv =
to_intel_th_driver_or_null(thdev->dev.driver);

if (!thdrv)
return;

if (thdrv->deactivate)
thdrv->deactivate(thdev);
else
intel_th_trace_disable(thdev);

module_put(thdrv->driver.owner);
}

static ssize_t active_show(struct device *dev, struct device_attribute *attr,
Expand Down
6 changes: 6 additions & 0 deletions drivers/hwtracing/intel_th/intel_th.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ intel_th_output_assigned(struct intel_th_device *thdev)
* @enable: enable tracing for a given output device
* @disable: disable tracing for a given output device
* @fops: file operations for device nodes
* @attr_group: attributes provided by the driver
*
* Callbacks @probe and @remove are required for all device types.
* Switch device driver needs to fill in @assign, @enable and @disable
Expand All @@ -139,6 +140,8 @@ struct intel_th_driver {
void (*deactivate)(struct intel_th_device *thdev);
/* file_operations for those who want a device node */
const struct file_operations *fops;
/* optional attributes */
struct attribute_group *attr_group;

/* source ops */
int (*set_output)(struct intel_th_device *thdev,
Expand All @@ -148,6 +151,9 @@ struct intel_th_driver {
#define to_intel_th_driver(_d) \
container_of((_d), struct intel_th_driver, driver)

#define to_intel_th_driver_or_null(_d) \
((_d) ? to_intel_th_driver(_d) : NULL)

static inline struct intel_th_device *
to_intel_th_hub(struct intel_th_device *thdev)
{
Expand Down
116 changes: 68 additions & 48 deletions drivers/hwtracing/intel_th/msu.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ struct msc {
atomic_t mmap_count;
struct mutex buf_mutex;

struct mutex iter_mutex;
struct list_head iter_list;

/* config */
Expand Down Expand Up @@ -257,23 +256,37 @@ static struct msc_iter *msc_iter_install(struct msc *msc)

iter = kzalloc(sizeof(*iter), GFP_KERNEL);
if (!iter)
return NULL;
return ERR_PTR(-ENOMEM);

mutex_lock(&msc->buf_mutex);

/*
* Reading and tracing are mutually exclusive; if msc is
* enabled, open() will fail; otherwise existing readers
* will prevent enabling the msc and the rest of fops don't
* need to worry about it.
*/
if (msc->enabled) {
kfree(iter);
iter = ERR_PTR(-EBUSY);
goto unlock;
}

msc_iter_init(iter);
iter->msc = msc;

mutex_lock(&msc->iter_mutex);
list_add_tail(&iter->entry, &msc->iter_list);
mutex_unlock(&msc->iter_mutex);
unlock:
mutex_unlock(&msc->buf_mutex);

return iter;
}

static void msc_iter_remove(struct msc_iter *iter, struct msc *msc)
{
mutex_lock(&msc->iter_mutex);
mutex_lock(&msc->buf_mutex);
list_del(&iter->entry);
mutex_unlock(&msc->iter_mutex);
mutex_unlock(&msc->buf_mutex);

kfree(iter);
}
Expand Down Expand Up @@ -454,7 +467,6 @@ static void msc_buffer_clear_hw_header(struct msc *msc)
{
struct msc_window *win;

mutex_lock(&msc->buf_mutex);
list_for_each_entry(win, &msc->win_list, entry) {
unsigned int blk;
size_t hw_sz = sizeof(struct msc_block_desc) -
Expand All @@ -466,20 +478,22 @@ static void msc_buffer_clear_hw_header(struct msc *msc)
memset(&bdesc->hw_tag, 0, hw_sz);
}
}
mutex_unlock(&msc->buf_mutex);
}

/**
* msc_configure() - set up MSC hardware
* @msc: the MSC device to configure
*
* Program storage mode, wrapping, burst length and trace buffer address
* into a given MSC. If msc::enabled is set, enable the trace, too.
* into a given MSC. Then, enable tracing and set msc::enabled.
* The latter is serialized on msc::buf_mutex, so make sure to hold it.
*/
static int msc_configure(struct msc *msc)
{
u32 reg;

lockdep_assert_held(&msc->buf_mutex);

if (msc->mode > MSC_MODE_MULTI)
return -ENOTSUPP;

Expand All @@ -497,21 +511,19 @@ static int msc_configure(struct msc *msc)
reg = ioread32(msc->reg_base + REG_MSU_MSC0CTL);
reg &= ~(MSC_MODE | MSC_WRAPEN | MSC_EN | MSC_RD_HDR_OVRD);

reg |= MSC_EN;
reg |= msc->mode << __ffs(MSC_MODE);
reg |= msc->burst_len << __ffs(MSC_LEN);
/*if (msc->mode == MSC_MODE_MULTI)
reg |= MSC_RD_HDR_OVRD; */

if (msc->wrap)
reg |= MSC_WRAPEN;
if (msc->enabled)
reg |= MSC_EN;

iowrite32(reg, msc->reg_base + REG_MSU_MSC0CTL);

if (msc->enabled) {
msc->thdev->output.multiblock = msc->mode == MSC_MODE_MULTI;
intel_th_trace_enable(msc->thdev);
}
msc->thdev->output.multiblock = msc->mode == MSC_MODE_MULTI;
intel_th_trace_enable(msc->thdev);
msc->enabled = 1;


return 0;
}
Expand All @@ -521,15 +533,14 @@ static int msc_configure(struct msc *msc)
* @msc: MSC device to disable
*
* If @msc is enabled, disable tracing on the switch and then disable MSC
* storage.
* storage. Caller must hold msc::buf_mutex.
*/
static void msc_disable(struct msc *msc)
{
unsigned long count;
u32 reg;

if (!msc->enabled)
return;
lockdep_assert_held(&msc->buf_mutex);

intel_th_trace_disable(msc->thdev);

Expand Down Expand Up @@ -569,33 +580,35 @@ static void msc_disable(struct msc *msc)
static int intel_th_msc_activate(struct intel_th_device *thdev)
{
struct msc *msc = dev_get_drvdata(&thdev->dev);
int ret = 0;
int ret = -EBUSY;

if (!atomic_inc_unless_negative(&msc->user_count))
return -ENODEV;

mutex_lock(&msc->iter_mutex);
if (!list_empty(&msc->iter_list))
ret = -EBUSY;
mutex_unlock(&msc->iter_mutex);
mutex_lock(&msc->buf_mutex);

if (ret) {
atomic_dec(&msc->user_count);
return ret;
}
/* if there are readers, refuse */
if (list_empty(&msc->iter_list))
ret = msc_configure(msc);

msc->enabled = 1;
mutex_unlock(&msc->buf_mutex);

if (ret)
atomic_dec(&msc->user_count);

return msc_configure(msc);
return ret;
}

static void intel_th_msc_deactivate(struct intel_th_device *thdev)
{
struct msc *msc = dev_get_drvdata(&thdev->dev);

msc_disable(msc);

atomic_dec(&msc->user_count);
mutex_lock(&msc->buf_mutex);
if (msc->enabled) {
msc_disable(msc);
atomic_dec(&msc->user_count);
}
mutex_unlock(&msc->buf_mutex);
}

/**
Expand Down Expand Up @@ -1035,8 +1048,8 @@ static int intel_th_msc_open(struct inode *inode, struct file *file)
return -EPERM;

iter = msc_iter_install(msc);
if (!iter)
return -ENOMEM;
if (IS_ERR(iter))
return PTR_ERR(iter);

file->private_data = iter;

Expand Down Expand Up @@ -1101,11 +1114,6 @@ static ssize_t intel_th_msc_read(struct file *file, char __user *buf,
if (!atomic_inc_unless_negative(&msc->user_count))
return 0;

if (msc->enabled) {
ret = -EBUSY;
goto put_count;
}

if (msc->mode == MSC_MODE_SINGLE && !msc->single_wrap)
size = msc->single_sz;
else
Expand Down Expand Up @@ -1245,6 +1253,7 @@ static const struct file_operations intel_th_msc_fops = {
.read = intel_th_msc_read,
.mmap = intel_th_msc_mmap,
.llseek = no_llseek,
.owner = THIS_MODULE,
};

static int intel_th_msc_init(struct msc *msc)
Expand All @@ -1254,8 +1263,6 @@ static int intel_th_msc_init(struct msc *msc)
msc->mode = MSC_MODE_MULTI;
mutex_init(&msc->buf_mutex);
INIT_LIST_HEAD(&msc->win_list);

mutex_init(&msc->iter_mutex);
INIT_LIST_HEAD(&msc->iter_list);

msc->burst_len =
Expand Down Expand Up @@ -1393,6 +1400,11 @@ nr_pages_store(struct device *dev, struct device_attribute *attr,
do {
end = memchr(p, ',', len);
s = kstrndup(p, end ? end - p : len, GFP_KERNEL);
if (!s) {
ret = -ENOMEM;
goto free_win;
}

ret = kstrtoul(s, 10, &val);
kfree(s);

Expand Down Expand Up @@ -1473,18 +1485,25 @@ static int intel_th_msc_probe(struct intel_th_device *thdev)
if (err)
return err;

err = sysfs_create_group(&dev->kobj, &msc_output_group);
if (err)
return err;

dev_set_drvdata(dev, msc);

return 0;
}

static void intel_th_msc_remove(struct intel_th_device *thdev)
{
sysfs_remove_group(&thdev->dev.kobj, &msc_output_group);
struct msc *msc = dev_get_drvdata(&thdev->dev);
int ret;

intel_th_msc_deactivate(thdev);

/*
* Buffers should not be used at this point except if the
* output character device is still open and the parent
* device gets detached from its bus, which is a FIXME.
*/
ret = msc_buffer_free_unless_used(msc);
WARN_ON_ONCE(ret);
}

static struct intel_th_driver intel_th_msc_driver = {
Expand All @@ -1493,6 +1512,7 @@ static struct intel_th_driver intel_th_msc_driver = {
.activate = intel_th_msc_activate,
.deactivate = intel_th_msc_deactivate,
.fops = &intel_th_msc_fops,
.attr_group = &msc_output_group,
.driver = {
.name = "msc",
.owner = THIS_MODULE,
Expand Down
5 changes: 5 additions & 0 deletions drivers/hwtracing/intel_th/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0a80),
.driver_data = (kernel_ulong_t)0,
},
{
/* Broxton B-step */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1a8e),
.driver_data = (kernel_ulong_t)0,
},
{ 0 },
};

Expand Down
Loading

0 comments on commit 2fc5dda

Please sign in to comment.