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 Original line Diff line number Diff line
@@ -9754,6 +9754,7 @@ F: drivers/mmc/host/dw_mmc*
SYSTEM TRACE MODULE CLASS
SYSTEM TRACE MODULE CLASS
M:	Alexander Shishkin <alexander.shishkin@linux.intel.com>
M:	Alexander Shishkin <alexander.shishkin@linux.intel.com>
S:	Maintained
S:	Maintained
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/ash/stm.git
F:	Documentation/trace/stm.txt
F:	Documentation/trace/stm.txt
F:	drivers/hwtracing/stm/
F:	drivers/hwtracing/stm/
F:	include/linux/stm.h
F:	include/linux/stm.h
+27 −2
Original line number Original line Diff line number Diff line
@@ -71,6 +71,15 @@ static int intel_th_probe(struct device *dev)
	if (ret)
	if (ret)
		return 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 &&
	if (thdev->type == INTEL_TH_OUTPUT &&
	    !intel_th_output_assigned(thdev))
	    !intel_th_output_assigned(thdev))
		ret = hubdrv->assign(hub, thdev);
		ret = hubdrv->assign(hub, thdev);
@@ -91,6 +100,9 @@ static int intel_th_remove(struct device *dev)
			return err;
			return err;
	}
	}


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

	thdrv->remove(thdev);
	thdrv->remove(thdev);


	if (intel_th_output_assigned(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)
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)
	if (thdrv->activate)
		return thdrv->activate(thdev);
		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)
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)
	if (thdrv->deactivate)
		thdrv->deactivate(thdev);
		thdrv->deactivate(thdev);
	else
	else
		intel_th_trace_disable(thdev);
		intel_th_trace_disable(thdev);

	module_put(thdrv->driver.owner);
}
}


static ssize_t active_show(struct device *dev, struct device_attribute *attr,
static ssize_t active_show(struct device *dev, struct device_attribute *attr,
+6 −0
Original line number Original line 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
 * @enable:	enable tracing for a given output device
 * @disable:	disable tracing for a given output device
 * @disable:	disable tracing for a given output device
 * @fops:	file operations for device nodes
 * @fops:	file operations for device nodes
 * @attr_group:	attributes provided by the driver
 *
 *
 * Callbacks @probe and @remove are required for all device types.
 * Callbacks @probe and @remove are required for all device types.
 * Switch device driver needs to fill in @assign, @enable and @disable
 * 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);
	void			(*deactivate)(struct intel_th_device *thdev);
	/* file_operations for those who want a device node */
	/* file_operations for those who want a device node */
	const struct file_operations *fops;
	const struct file_operations *fops;
	/* optional attributes */
	struct attribute_group	*attr_group;


	/* source ops */
	/* source ops */
	int			(*set_output)(struct intel_th_device *thdev,
	int			(*set_output)(struct intel_th_device *thdev,
@@ -148,6 +151,9 @@ struct intel_th_driver {
#define to_intel_th_driver(_d)					\
#define to_intel_th_driver(_d)					\
	container_of((_d), struct intel_th_driver, driver)
	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 *
static inline struct intel_th_device *
to_intel_th_hub(struct intel_th_device *thdev)
to_intel_th_hub(struct intel_th_device *thdev)
{
{
+68 −48
Original line number Original line Diff line number Diff line
@@ -122,7 +122,6 @@ struct msc {
	atomic_t		mmap_count;
	atomic_t		mmap_count;
	struct mutex		buf_mutex;
	struct mutex		buf_mutex;


	struct mutex		iter_mutex;
	struct list_head	iter_list;
	struct list_head	iter_list;


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


	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
	if (!iter)
	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);
	msc_iter_init(iter);
	iter->msc = msc;
	iter->msc = msc;


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


	return iter;
	return iter;
}
}


static void msc_iter_remove(struct msc_iter *iter, struct msc *msc)
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);
	list_del(&iter->entry);
	mutex_unlock(&msc->iter_mutex);
	mutex_unlock(&msc->buf_mutex);


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


	mutex_lock(&msc->buf_mutex);
	list_for_each_entry(win, &msc->win_list, entry) {
	list_for_each_entry(win, &msc->win_list, entry) {
		unsigned int blk;
		unsigned int blk;
		size_t hw_sz = sizeof(struct msc_block_desc) -
		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);
			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
 * @msc:	the MSC device to configure
 *
 *
 * Program storage mode, wrapping, burst length and trace buffer address
 * 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)
static int msc_configure(struct msc *msc)
{
{
	u32 reg;
	u32 reg;


	lockdep_assert_held(&msc->buf_mutex);

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


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


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

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


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


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



	return 0;
	return 0;
}
}
@@ -521,15 +533,14 @@ static int msc_configure(struct msc *msc)
 * @msc:	MSC device to disable
 * @msc:	MSC device to disable
 *
 *
 * If @msc is enabled, disable tracing on the switch and then disable MSC
 * 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)
static void msc_disable(struct msc *msc)
{
{
	unsigned long count;
	unsigned long count;
	u32 reg;
	u32 reg;


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


	intel_th_trace_disable(msc->thdev);
	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)
static int intel_th_msc_activate(struct intel_th_device *thdev)
{
{
	struct msc *msc = dev_get_drvdata(&thdev->dev);
	struct msc *msc = dev_get_drvdata(&thdev->dev);
	int ret = 0;
	int ret = -EBUSY;


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


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


	if (ret) {
	/* if there are readers, refuse */
		atomic_dec(&msc->user_count);
	if (list_empty(&msc->iter_list))
		return ret;
		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)
static void intel_th_msc_deactivate(struct intel_th_device *thdev)
{
{
	struct msc *msc = dev_get_drvdata(&thdev->dev);
	struct msc *msc = dev_get_drvdata(&thdev->dev);


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

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


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


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


	file->private_data = 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))
	if (!atomic_inc_unless_negative(&msc->user_count))
		return 0;
		return 0;


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

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


static int intel_th_msc_init(struct msc *msc)
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;
	msc->mode = MSC_MODE_MULTI;
	mutex_init(&msc->buf_mutex);
	mutex_init(&msc->buf_mutex);
	INIT_LIST_HEAD(&msc->win_list);
	INIT_LIST_HEAD(&msc->win_list);

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


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

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


@@ -1473,10 +1485,6 @@ static int intel_th_msc_probe(struct intel_th_device *thdev)
	if (err)
	if (err)
		return err;
		return err;


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

	dev_set_drvdata(dev, msc);
	dev_set_drvdata(dev, msc);


	return 0;
	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)
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 = {
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,
	.activate	= intel_th_msc_activate,
	.deactivate	= intel_th_msc_deactivate,
	.deactivate	= intel_th_msc_deactivate,
	.fops	= &intel_th_msc_fops,
	.fops	= &intel_th_msc_fops,
	.attr_group	= &msc_output_group,
	.driver	= {
	.driver	= {
		.name	= "msc",
		.name	= "msc",
		.owner	= THIS_MODULE,
		.owner	= THIS_MODULE,
+5 −0
Original line number Original line 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),
		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0a80),
		.driver_data = (kernel_ulong_t)0,
		.driver_data = (kernel_ulong_t)0,
	},
	},
	{
		/* Broxton B-step */
		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1a8e),
		.driver_data = (kernel_ulong_t)0,
	},
	{ 0 },
	{ 0 },
};
};


Loading