Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2fc5ddaa authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'stm-for-greg-20160420' of...

Merge tag 'stm-for-greg-20160420' 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.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
parents 7553c7e6 aaa3ca82
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+27 −2
Original line number Diff line number Diff line
@@ -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);
@@ -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)) {
@@ -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);
@@ -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,
+6 −0
Original line number Diff line number Diff line
@@ -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
@@ -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,
@@ -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)
{
+68 −48
Original line number Diff line number Diff line
@@ -122,7 +122,6 @@ struct msc {
	atomic_t		mmap_count;
	struct mutex		buf_mutex;

	struct mutex		iter_mutex;
	struct list_head	iter_list;

	/* config */
@@ -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);
}
@@ -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) -
@@ -466,7 +478,6 @@ static void msc_buffer_clear_hw_header(struct msc *msc)
			memset(&bdesc->hw_tag, 0, hw_sz);
		}
	}
	mutex_unlock(&msc->buf_mutex);
}

/**
@@ -474,12 +485,15 @@ static void msc_buffer_clear_hw_header(struct msc *msc)
 * @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;

@@ -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->enabled = 1;


	return 0;
}
@@ -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);

@@ -569,34 +580,36 @@ 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);

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

	return ret;
}

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

	mutex_lock(&msc->buf_mutex);
	if (msc->enabled) {
		msc_disable(msc);

		atomic_dec(&msc->user_count);
	}
	mutex_unlock(&msc->buf_mutex);
}

/**
 * msc_buffer_contig_alloc() - allocate a contiguous buffer for SINGLE mode
@@ -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;

@@ -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
@@ -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)
@@ -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 =
@@ -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);

@@ -1473,10 +1485,6 @@ 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;
@@ -1484,7 +1492,18 @@ static int intel_th_msc_probe(struct intel_th_device *thdev)

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 = {
@@ -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,
+5 −0
Original line number Diff line number Diff line
@@ -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 },
};

Loading