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

Commit 26b0332e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull dmaengine update from Dan Williams:
 "Collection of random updates to the core and some end-driver fixups
  for ioatdma and mv_xor:
   - NUMA aware channel allocation
   - Cleanup dmatest debugfs interface
   - ioat: make raid-support Atom only
   - mv_xor: big endian

  Aside from the top three commits these have all had some soak time in
  -next.  The top commit fixes a recent build breakage.

  It has been a long while since my last pull request, hopefully it does
  not show.  Thanks to Vinod for keeping an eye on drivers/dma/ this
  past year"

* tag 'dmaengine-3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/dmaengine:
  dmaengine: dma_sync_wait and dma_find_channel undefined
  MAINTAINERS: update email for Dan Williams
  dma: mv_xor: Fix incorrect error path
  ioatdma: silence GCC warnings
  dmaengine: make dma_channel_rebalance() NUMA aware
  dmaengine: make dma_submit_error() return an error code
  ioatdma: disable RAID on non-Atom platforms and reenable unaligned copies
  mv_xor: support big endian systems using descriptor swap feature
  mv_xor: use {readl, writel}_relaxed instead of __raw_{readl, writel}
  dmatest: print message on debug level in case of no error
  dmatest: remove IS_ERR_OR_NULL checks of debugfs calls
  dmatest: make module parameters writable
parents 64041417 4a43f394
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -16,15 +16,16 @@ be built as module or inside kernel. Let's consider those cases.
	Part 2 - When dmatest is built as a module...

After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest
folder with nodes will be created. They are the same as module parameters with
addition of the 'run' node that controls run and stop phases of the test.
folder with nodes will be created. There are two important files located. First
is the 'run' node that controls run and stop phases of the test, and the second
one, 'results', is used to get the test case results.

Note that in this case test will not run on load automatically.

Example of usage:
	% echo dma0chan0 > /sys/kernel/debug/dmatest/channel
	% echo 2000 > /sys/kernel/debug/dmatest/timeout
	% echo 1 > /sys/kernel/debug/dmatest/iterations
	% echo dma0chan0 > /sys/module/dmatest/parameters/channel
	% echo 2000 > /sys/module/dmatest/parameters/timeout
	% echo 1 > /sys/module/dmatest/parameters/iterations
	% echo 1 > /sys/kernel/debug/dmatest/run

Hint: available channel list could be extracted by running the following
@@ -55,8 +56,8 @@ for the first performed test. After user gets a control, the test could be
re-run with the same or different parameters. For the details see the above
section "Part 2 - When dmatest is built as a module..."

In both cases the module parameters are used as initial values for the test case.
You always could check them at run-time by running
In both cases the module parameters are used as the actual values for the test
case. You always could check them at run-time by running
	% grep -H . /sys/module/dmatest/parameters/*

	Part 4 - Gathering the test results
+9 −9
Original line number Diff line number Diff line
@@ -933,24 +933,24 @@ F: arch/arm/mach-pxa/colibri-pxa270-income.c

ARM/INTEL IOP32X ARM ARCHITECTURE
M:	Lennert Buytenhek <kernel@wantstofly.org>
M:	Dan Williams <djbw@fb.com>
M:	Dan Williams <dan.j.williams@intel.com>
L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S:	Maintained

ARM/INTEL IOP33X ARM ARCHITECTURE
M:	Dan Williams <djbw@fb.com>
M:	Dan Williams <dan.j.williams@intel.com>
L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S:	Maintained

ARM/INTEL IOP13XX ARM ARCHITECTURE
M:	Lennert Buytenhek <kernel@wantstofly.org>
M:	Dan Williams <djbw@fb.com>
M:	Dan Williams <dan.j.williams@intel.com>
L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S:	Maintained

ARM/INTEL IQ81342EX MACHINE SUPPORT
M:	Lennert Buytenhek <kernel@wantstofly.org>
M:	Dan Williams <djbw@fb.com>
M:	Dan Williams <dan.j.williams@intel.com>
L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S:	Maintained

@@ -975,7 +975,7 @@ F: drivers/pcmcia/pxa2xx_stargate2.c

ARM/INTEL XSC3 (MANZANO) ARM CORE
M:	Lennert Buytenhek <kernel@wantstofly.org>
M:	Dan Williams <djbw@fb.com>
M:	Dan Williams <dan.j.williams@intel.com>
L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S:	Maintained

@@ -1386,7 +1386,7 @@ F: drivers/platform/x86/asus*.c
F:	drivers/platform/x86/eeepc*.c

ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
M:	Dan Williams <djbw@fb.com>
M:	Dan Williams <dan.j.williams@intel.com>
W:	http://sourceforge.net/projects/xscaleiop
S:	Maintained
F:	Documentation/crypto/async-tx-api.txt
@@ -2691,7 +2691,7 @@ T: git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git

DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
M:	Vinod Koul <vinod.koul@intel.com>
M:	Dan Williams <djbw@fb.com>
M:	Dan Williams <dan.j.williams@intel.com>
S:	Supported
F:	drivers/dma/
F:	include/linux/dma*
@@ -4323,7 +4323,7 @@ F: arch/x86/kernel/microcode_core.c
F:	arch/x86/kernel/microcode_intel.c

INTEL I/OAT DMA DRIVER
M:	Dan Williams <djbw@fb.com>
M:	Dan Williams <dan.j.williams@intel.com>
S:	Maintained
F:	drivers/dma/ioat*

@@ -4336,7 +4336,7 @@ F: drivers/iommu/intel-iommu.c
F:	include/linux/intel-iommu.h

INTEL IOP-ADMA DMA DRIVER
M:	Dan Williams <djbw@fb.com>
M:	Dan Williams <dan.j.williams@intel.com>
S:	Odd fixes
F:	drivers/dma/iop-adma.c

+27 −28
Original line number Diff line number Diff line
@@ -382,20 +382,30 @@ void dma_issue_pending_all(void)
EXPORT_SYMBOL(dma_issue_pending_all);

/**
 * nth_chan - returns the nth channel of the given capability
 * dma_chan_is_local - returns true if the channel is in the same numa-node as the cpu
 */
static bool dma_chan_is_local(struct dma_chan *chan, int cpu)
{
	int node = dev_to_node(chan->device->dev);
	return node == -1 || cpumask_test_cpu(cpu, cpumask_of_node(node));
}

/**
 * min_chan - returns the channel with min count and in the same numa-node as the cpu
 * @cap: capability to match
 * @n: nth channel desired
 * @cpu: cpu index which the channel should be close to
 *
 * Defaults to returning the channel with the desired capability and the
 * lowest reference count when 'n' cannot be satisfied.  Must be called
 * under dma_list_mutex.
 * If some channels are close to the given cpu, the one with the lowest
 * reference count is returned. Otherwise, cpu is ignored and only the
 * reference count is taken into account.
 * Must be called under dma_list_mutex.
 */
static struct dma_chan *nth_chan(enum dma_transaction_type cap, int n)
static struct dma_chan *min_chan(enum dma_transaction_type cap, int cpu)
{
	struct dma_device *device;
	struct dma_chan *chan;
	struct dma_chan *ret = NULL;
	struct dma_chan *min = NULL;
	struct dma_chan *localmin = NULL;

	list_for_each_entry(device, &dma_device_list, global_node) {
		if (!dma_has_cap(cap, device->cap_mask) ||
@@ -404,27 +414,22 @@ static struct dma_chan *nth_chan(enum dma_transaction_type cap, int n)
		list_for_each_entry(chan, &device->channels, device_node) {
			if (!chan->client_count)
				continue;
			if (!min)
				min = chan;
			else if (chan->table_count < min->table_count)
			if (!min || chan->table_count < min->table_count)
				min = chan;

			if (n-- == 0) {
				ret = chan;
				break; /* done */
			if (dma_chan_is_local(chan, cpu))
				if (!localmin ||
				    chan->table_count < localmin->table_count)
					localmin = chan;
		}
	}
		if (ret)
			break; /* done */
	}

	if (!ret)
		ret = min;
	chan = localmin ? localmin : min;

	if (ret)
		ret->table_count++;
	if (chan)
		chan->table_count++;

	return ret;
	return chan;
}

/**
@@ -441,7 +446,6 @@ static void dma_channel_rebalance(void)
	struct dma_device *device;
	int cpu;
	int cap;
	int n;

	/* undo the last distribution */
	for_each_dma_cap_mask(cap, dma_cap_mask_all)
@@ -460,14 +464,9 @@ static void dma_channel_rebalance(void)
		return;

	/* redistribute available channels */
	n = 0;
	for_each_dma_cap_mask(cap, dma_cap_mask_all)
		for_each_online_cpu(cpu) {
			if (num_possible_cpus() > 1)
				chan = nth_chan(cap, n++);
			else
				chan = nth_chan(cap, -1);

			chan = min_chan(cap, cpu);
			per_cpu_ptr(channel_table[cap], cpu)->chan = chan;
		}
}
+30 −152
Original line number Diff line number Diff line
@@ -25,44 +25,46 @@
#include <linux/seq_file.h>

static unsigned int test_buf_size = 16384;
module_param(test_buf_size, uint, S_IRUGO);
module_param(test_buf_size, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer");

static char test_channel[20];
module_param_string(channel, test_channel, sizeof(test_channel), S_IRUGO);
module_param_string(channel, test_channel, sizeof(test_channel),
		S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)");

static char test_device[20];
module_param_string(device, test_device, sizeof(test_device), S_IRUGO);
module_param_string(device, test_device, sizeof(test_device),
		S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)");

static unsigned int threads_per_chan = 1;
module_param(threads_per_chan, uint, S_IRUGO);
module_param(threads_per_chan, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(threads_per_chan,
		"Number of threads to start per channel (default: 1)");

static unsigned int max_channels;
module_param(max_channels, uint, S_IRUGO);
module_param(max_channels, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(max_channels,
		"Maximum number of channels to use (default: all)");

static unsigned int iterations;
module_param(iterations, uint, S_IRUGO);
module_param(iterations, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(iterations,
		"Iterations before stopping test (default: infinite)");

static unsigned int xor_sources = 3;
module_param(xor_sources, uint, S_IRUGO);
module_param(xor_sources, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(xor_sources,
		"Number of xor source buffers (default: 3)");

static unsigned int pq_sources = 3;
module_param(pq_sources, uint, S_IRUGO);
module_param(pq_sources, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(pq_sources,
		"Number of p+q source buffers (default: 3)");

static int timeout = 3000;
module_param(timeout, uint, S_IRUGO);
module_param(timeout, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
		 "Pass -1 for infinite timeout");

@@ -193,7 +195,6 @@ struct dmatest_info {

	/* debugfs related stuff */
	struct dentry		*root;
	struct dmatest_params	dbgfs_params;

	/* Test results */
	struct list_head	results;
@@ -406,7 +407,11 @@ static int thread_result_add(struct dmatest_info *info,
	list_add_tail(&tr->node, &r->results);
	mutex_unlock(&info->results_lock);

	if (tr->type == DMATEST_ET_OK)
		pr_debug("%s\n", thread_result_get(r->name, tr));
	else
		pr_warn("%s\n", thread_result_get(r->name, tr));

	return 0;
}

@@ -1007,7 +1012,15 @@ static int __restart_threaded_test(struct dmatest_info *info, bool run)
	result_free(info, NULL);

	/* Copy test parameters */
	memcpy(params, &info->dbgfs_params, sizeof(*params));
	params->buf_size = test_buf_size;
	strlcpy(params->channel, strim(test_channel), sizeof(params->channel));
	strlcpy(params->device, strim(test_device), sizeof(params->device));
	params->threads_per_chan = threads_per_chan;
	params->max_channels = max_channels;
	params->iterations = iterations;
	params->xor_sources = xor_sources;
	params->pq_sources = pq_sources;
	params->timeout = timeout;

	/* Run test with new parameters */
	return __run_threaded_test(info);
@@ -1029,71 +1042,6 @@ static bool __is_threaded_test_run(struct dmatest_info *info)
	return false;
}

static ssize_t dtf_write_string(void *to, size_t available, loff_t *ppos,
		const void __user *from, size_t count)
{
	char tmp[20];
	ssize_t len;

	len = simple_write_to_buffer(tmp, sizeof(tmp) - 1, ppos, from, count);
	if (len >= 0) {
		tmp[len] = '\0';
		strlcpy(to, strim(tmp), available);
	}

	return len;
}

static ssize_t dtf_read_channel(struct file *file, char __user *buf,
		size_t count, loff_t *ppos)
{
	struct dmatest_info *info = file->private_data;
	return simple_read_from_buffer(buf, count, ppos,
			info->dbgfs_params.channel,
			strlen(info->dbgfs_params.channel));
}

static ssize_t dtf_write_channel(struct file *file, const char __user *buf,
		size_t size, loff_t *ppos)
{
	struct dmatest_info *info = file->private_data;
	return dtf_write_string(info->dbgfs_params.channel,
				sizeof(info->dbgfs_params.channel),
				ppos, buf, size);
}

static const struct file_operations dtf_channel_fops = {
	.read	= dtf_read_channel,
	.write	= dtf_write_channel,
	.open	= simple_open,
	.llseek	= default_llseek,
};

static ssize_t dtf_read_device(struct file *file, char __user *buf,
		size_t count, loff_t *ppos)
{
	struct dmatest_info *info = file->private_data;
	return simple_read_from_buffer(buf, count, ppos,
			info->dbgfs_params.device,
			strlen(info->dbgfs_params.device));
}

static ssize_t dtf_write_device(struct file *file, const char __user *buf,
		size_t size, loff_t *ppos)
{
	struct dmatest_info *info = file->private_data;
	return dtf_write_string(info->dbgfs_params.device,
				sizeof(info->dbgfs_params.device),
				ppos, buf, size);
}

static const struct file_operations dtf_device_fops = {
	.read	= dtf_read_device,
	.write	= dtf_write_device,
	.open	= simple_open,
	.llseek	= default_llseek,
};

static ssize_t dtf_read_run(struct file *file, char __user *user_buf,
		size_t count, loff_t *ppos)
{
@@ -1187,8 +1135,6 @@ static const struct file_operations dtf_results_fops = {
static int dmatest_register_dbgfs(struct dmatest_info *info)
{
	struct dentry *d;
	struct dmatest_params *params = &info->dbgfs_params;
	int ret = -ENOMEM;

	d = debugfs_create_dir("dmatest", NULL);
	if (IS_ERR(d))
@@ -1198,81 +1144,24 @@ static int dmatest_register_dbgfs(struct dmatest_info *info)

	info->root = d;

	/* Copy initial values */
	memcpy(params, &info->params, sizeof(*params));

	/* Test parameters */

	d = debugfs_create_u32("test_buf_size", S_IWUSR | S_IRUGO, info->root,
			       (u32 *)&params->buf_size);
	if (IS_ERR_OR_NULL(d))
		goto err_node;

	d = debugfs_create_file("channel", S_IRUGO | S_IWUSR, info->root,
				info, &dtf_channel_fops);
	if (IS_ERR_OR_NULL(d))
		goto err_node;

	d = debugfs_create_file("device", S_IRUGO | S_IWUSR, info->root,
				info, &dtf_device_fops);
	if (IS_ERR_OR_NULL(d))
		goto err_node;

	d = debugfs_create_u32("threads_per_chan", S_IWUSR | S_IRUGO, info->root,
			       (u32 *)&params->threads_per_chan);
	if (IS_ERR_OR_NULL(d))
		goto err_node;

	d = debugfs_create_u32("max_channels", S_IWUSR | S_IRUGO, info->root,
			       (u32 *)&params->max_channels);
	if (IS_ERR_OR_NULL(d))
		goto err_node;

	d = debugfs_create_u32("iterations", S_IWUSR | S_IRUGO, info->root,
			       (u32 *)&params->iterations);
	if (IS_ERR_OR_NULL(d))
		goto err_node;

	d = debugfs_create_u32("xor_sources", S_IWUSR | S_IRUGO, info->root,
			       (u32 *)&params->xor_sources);
	if (IS_ERR_OR_NULL(d))
		goto err_node;

	d = debugfs_create_u32("pq_sources", S_IWUSR | S_IRUGO, info->root,
			       (u32 *)&params->pq_sources);
	if (IS_ERR_OR_NULL(d))
		goto err_node;

	d = debugfs_create_u32("timeout", S_IWUSR | S_IRUGO, info->root,
			       (u32 *)&params->timeout);
	if (IS_ERR_OR_NULL(d))
		goto err_node;

	/* Run or stop threaded test */
	d = debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root,
				info, &dtf_run_fops);
	if (IS_ERR_OR_NULL(d))
		goto err_node;
	debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root, info,
			    &dtf_run_fops);

	/* Results of test in progress */
	d = debugfs_create_file("results", S_IRUGO, info->root, info,
	debugfs_create_file("results", S_IRUGO, info->root, info,
			    &dtf_results_fops);
	if (IS_ERR_OR_NULL(d))
		goto err_node;

	return 0;

err_node:
	debugfs_remove_recursive(info->root);
err_root:
	pr_err("dmatest: Failed to initialize debugfs\n");
	return ret;
	return -ENOMEM;
}

static int __init dmatest_init(void)
{
	struct dmatest_info *info = &test_info;
	struct dmatest_params *params = &info->params;
	int ret;

	memset(info, 0, sizeof(*info));
@@ -1283,17 +1172,6 @@ static int __init dmatest_init(void)
	mutex_init(&info->results_lock);
	INIT_LIST_HEAD(&info->results);

	/* Set default parameters */
	params->buf_size = test_buf_size;
	strlcpy(params->channel, test_channel, sizeof(params->channel));
	strlcpy(params->device, test_device, sizeof(params->device));
	params->threads_per_chan = threads_per_chan;
	params->max_channels = max_channels;
	params->iterations = iterations;
	params->xor_sources = xor_sources;
	params->pq_sources = pq_sources;
	params->timeout = timeout;

	ret = dmatest_register_dbgfs(info);
	if (ret)
		return ret;
+2 −24
Original line number Diff line number Diff line
@@ -251,7 +251,7 @@ static bool is_bwd_noraid(struct pci_dev *pdev)
}

static void pq16_set_src(struct ioat_raw_descriptor *desc[3],
			dma_addr_t addr, u32 offset, u8 coef, int idx)
			dma_addr_t addr, u32 offset, u8 coef, unsigned idx)
{
	struct ioat_pq_descriptor *pq = (struct ioat_pq_descriptor *)desc[0];
	struct ioat_pq16a_descriptor *pq16 =
@@ -1775,15 +1775,12 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)
	dma->device_alloc_chan_resources = ioat2_alloc_chan_resources;
	dma->device_free_chan_resources = ioat2_free_chan_resources;

	if (is_xeon_cb32(pdev))
		dma->copy_align = 6;

	dma_cap_set(DMA_INTERRUPT, dma->cap_mask);
	dma->device_prep_dma_interrupt = ioat3_prep_interrupt_lock;

	device->cap = readl(device->reg_base + IOAT_DMA_CAP_OFFSET);

	if (is_bwd_noraid(pdev))
	if (is_xeon_cb32(pdev) || is_bwd_noraid(pdev))
		device->cap &= ~(IOAT_CAP_XOR | IOAT_CAP_PQ | IOAT_CAP_RAID16SS);

	/* dca is incompatible with raid operations */
@@ -1793,7 +1790,6 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)
	if (device->cap & IOAT_CAP_XOR) {
		is_raid_device = true;
		dma->max_xor = 8;
		dma->xor_align = 6;

		dma_cap_set(DMA_XOR, dma->cap_mask);
		dma->device_prep_dma_xor = ioat3_prep_xor;
@@ -1812,13 +1808,8 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)

		if (device->cap & IOAT_CAP_RAID16SS) {
			dma_set_maxpq(dma, 16, 0);
			dma->pq_align = 0;
		} else {
			dma_set_maxpq(dma, 8, 0);
			if (is_xeon_cb32(pdev))
				dma->pq_align = 6;
			else
				dma->pq_align = 0;
		}

		if (!(device->cap & IOAT_CAP_XOR)) {
@@ -1829,13 +1820,8 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)

			if (device->cap & IOAT_CAP_RAID16SS) {
				dma->max_xor = 16;
				dma->xor_align = 0;
			} else {
				dma->max_xor = 8;
				if (is_xeon_cb32(pdev))
					dma->xor_align = 6;
				else
					dma->xor_align = 0;
			}
		}
	}
@@ -1844,14 +1830,6 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)
	device->cleanup_fn = ioat3_cleanup_event;
	device->timer_fn = ioat3_timer_event;

	if (is_xeon_cb32(pdev)) {
		dma_cap_clear(DMA_XOR_VAL, dma->cap_mask);
		dma->device_prep_dma_xor_val = NULL;

		dma_cap_clear(DMA_PQ_VAL, dma->cap_mask);
		dma->device_prep_dma_pq_val = NULL;
	}

	/* starting with CB3.3 super extended descriptors are supported */
	if (device->cap & IOAT_CAP_RAID16SS) {
		char pool_name[14];
Loading