From a6c268d033b1f363e0d76c0483a0f99266542820 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Jul 2013 18:36:46 +0300 Subject: dmatest: make module parameters writable The debugfs interface brought a copy of the test case parameters. This makes different set of values under /sys/module/dmatest/parameters/ and /sys/kernel/debug/dmatest/. The user might be confused by the divergence of values. The proposed solution in this patch is to make module parameters writable and remove them from the debugfs. Though we're still using debugfs to control test runner and getting results. Documentation part is updated accordingly. Signed-off-by: Andy Shevchenko Suggested-by: Dan Williams Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 159 +++++++------------------------------------------- 1 file changed, 20 insertions(+), 139 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index e88ded2c8d2f..91716f404c03 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -25,44 +25,46 @@ #include 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; @@ -1007,7 +1008,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 +1038,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,7 +1131,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); @@ -1198,56 +1141,6 @@ 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 *)¶ms->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 *)¶ms->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 *)¶ms->max_channels); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_u32("iterations", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->iterations); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_u32("xor_sources", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->xor_sources); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_u32("pq_sources", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->pq_sources); - if (IS_ERR_OR_NULL(d)) - goto err_node; - - d = debugfs_create_u32("timeout", S_IWUSR | S_IRUGO, info->root, - (u32 *)¶ms->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); @@ -1272,7 +1165,6 @@ err_root: 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 +1175,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; -- cgit v1.2.3 From e24775e41ffc59d9ae8c1f2a9a4ff9f79db0e573 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Jul 2013 18:36:47 +0300 Subject: dmatest: remove IS_ERR_OR_NULL checks of debugfs calls There is a really little chance when we are able to create a directory and are not able to create nodes under it. So, this patch just removes those checks. Signed-off-by: Andy Shevchenko Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 91716f404c03..eae598986b81 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -1131,7 +1131,6 @@ static const struct file_operations dtf_results_fops = { static int dmatest_register_dbgfs(struct dmatest_info *info) { struct dentry *d; - int ret = -ENOMEM; d = debugfs_create_dir("dmatest", NULL); if (IS_ERR(d)) @@ -1142,24 +1141,18 @@ static int dmatest_register_dbgfs(struct dmatest_info *info) info->root = d; /* 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, - &dtf_results_fops); - if (IS_ERR_OR_NULL(d)) - goto err_node; + debugfs_create_file("results", S_IRUGO, info->root, info, + &dtf_results_fops); 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) -- cgit v1.2.3 From ad5278cd8d4b12e14a9a00fa7443a7a239ae2219 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Jul 2013 18:36:48 +0300 Subject: dmatest: print message on debug level in case of no error Let's move the behaviour of printing no error message back to the pre v3.10 times. It means we will use debug level in the described case, and a warning level otherwise. Signed-off-by: Andy Shevchenko Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index eae598986b81..92f796cdc6ab 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -407,7 +407,11 @@ static int thread_result_add(struct dmatest_info *info, list_add_tail(&tr->node, &r->results); mutex_unlock(&info->results_lock); - pr_warn("%s\n", thread_result_get(r->name, tr)); + 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; } -- cgit v1.2.3 From 5733c38ae3473115ac7df3fe19bd2502149d8c51 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Mon, 29 Jul 2013 17:42:13 +0200 Subject: mv_xor: use {readl, writel}_relaxed instead of __raw_{readl, writel} In order to support big-endian execution, the mv_xor driver is changed to use the readl_relaxed() and writel_relaxed() accessors that properly convert from the CPU endianess to the device endianess (which in the case of Marvell XOR hardware is always little-endian). Signed-off-by: Thomas Petazzoni Signed-off-by: Dan Williams --- drivers/dma/mv_xor.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 200f1a3c9a44..c026b27f76e1 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -114,25 +114,25 @@ static void mv_desc_set_src_addr(struct mv_xor_desc_slot *desc, static u32 mv_chan_get_current_desc(struct mv_xor_chan *chan) { - return __raw_readl(XOR_CURR_DESC(chan)); + return readl_relaxed(XOR_CURR_DESC(chan)); } static void mv_chan_set_next_descriptor(struct mv_xor_chan *chan, u32 next_desc_addr) { - __raw_writel(next_desc_addr, XOR_NEXT_DESC(chan)); + writel_relaxed(next_desc_addr, XOR_NEXT_DESC(chan)); } static void mv_chan_unmask_interrupts(struct mv_xor_chan *chan) { - u32 val = __raw_readl(XOR_INTR_MASK(chan)); + u32 val = readl_relaxed(XOR_INTR_MASK(chan)); val |= XOR_INTR_MASK_VALUE << (chan->idx * 16); - __raw_writel(val, XOR_INTR_MASK(chan)); + writel_relaxed(val, XOR_INTR_MASK(chan)); } static u32 mv_chan_get_intr_cause(struct mv_xor_chan *chan) { - u32 intr_cause = __raw_readl(XOR_INTR_CAUSE(chan)); + u32 intr_cause = readl_relaxed(XOR_INTR_CAUSE(chan)); intr_cause = (intr_cause >> (chan->idx * 16)) & 0xFFFF; return intr_cause; } @@ -149,13 +149,13 @@ static void mv_xor_device_clear_eoc_cause(struct mv_xor_chan *chan) { u32 val = ~(1 << (chan->idx * 16)); dev_dbg(mv_chan_to_devp(chan), "%s, val 0x%08x\n", __func__, val); - __raw_writel(val, XOR_INTR_CAUSE(chan)); + writel_relaxed(val, XOR_INTR_CAUSE(chan)); } static void mv_xor_device_clear_err_status(struct mv_xor_chan *chan) { u32 val = 0xFFFF0000 >> (chan->idx * 16); - __raw_writel(val, XOR_INTR_CAUSE(chan)); + writel_relaxed(val, XOR_INTR_CAUSE(chan)); } static int mv_can_chain(struct mv_xor_desc_slot *desc) @@ -173,7 +173,7 @@ static void mv_set_mode(struct mv_xor_chan *chan, enum dma_transaction_type type) { u32 op_mode; - u32 config = __raw_readl(XOR_CONFIG(chan)); + u32 config = readl_relaxed(XOR_CONFIG(chan)); switch (type) { case DMA_XOR: @@ -192,7 +192,7 @@ static void mv_set_mode(struct mv_xor_chan *chan, config &= ~0x7; config |= op_mode; - __raw_writel(config, XOR_CONFIG(chan)); + writel_relaxed(config, XOR_CONFIG(chan)); chan->current_type = type; } @@ -201,14 +201,14 @@ static void mv_chan_activate(struct mv_xor_chan *chan) u32 activation; dev_dbg(mv_chan_to_devp(chan), " activate chan.\n"); - activation = __raw_readl(XOR_ACTIVATION(chan)); + activation = readl_relaxed(XOR_ACTIVATION(chan)); activation |= 0x1; - __raw_writel(activation, XOR_ACTIVATION(chan)); + writel_relaxed(activation, XOR_ACTIVATION(chan)); } static char mv_chan_is_busy(struct mv_xor_chan *chan) { - u32 state = __raw_readl(XOR_ACTIVATION(chan)); + u32 state = readl_relaxed(XOR_ACTIVATION(chan)); state = (state >> 4) & 0x3; @@ -755,22 +755,22 @@ static void mv_dump_xor_regs(struct mv_xor_chan *chan) { u32 val; - val = __raw_readl(XOR_CONFIG(chan)); + val = readl_relaxed(XOR_CONFIG(chan)); dev_err(mv_chan_to_devp(chan), "config 0x%08x\n", val); - val = __raw_readl(XOR_ACTIVATION(chan)); + val = readl_relaxed(XOR_ACTIVATION(chan)); dev_err(mv_chan_to_devp(chan), "activation 0x%08x\n", val); - val = __raw_readl(XOR_INTR_CAUSE(chan)); + val = readl_relaxed(XOR_INTR_CAUSE(chan)); dev_err(mv_chan_to_devp(chan), "intr cause 0x%08x\n", val); - val = __raw_readl(XOR_INTR_MASK(chan)); + val = readl_relaxed(XOR_INTR_MASK(chan)); dev_err(mv_chan_to_devp(chan), "intr mask 0x%08x\n", val); - val = __raw_readl(XOR_ERROR_CAUSE(chan)); + val = readl_relaxed(XOR_ERROR_CAUSE(chan)); dev_err(mv_chan_to_devp(chan), "error cause 0x%08x\n", val); - val = __raw_readl(XOR_ERROR_ADDR(chan)); + val = readl_relaxed(XOR_ERROR_ADDR(chan)); dev_err(mv_chan_to_devp(chan), "error addr 0x%08x\n", val); } -- cgit v1.2.3 From e03bc654f85604bcd5304debb597f398d1d03778 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Mon, 29 Jul 2013 17:42:14 +0200 Subject: mv_xor: support big endian systems using descriptor swap feature The mv_xor driver had never been used in a big-endian context, and therefore was not using the hardware features to support such an execution environment. The hardware provides a "descriptor swap" bit that automatically swaps the bytes of the DMA descriptors, within blocks of 8 bytes. This requires a different DMA descriptor layout on big-endian systems, as well as enabling this "descriptor swap" bit. This mechanism is exactly identical to the one already used in the mv643xx_eth network driver and the mvneta network driver. Signed-off-by: Thomas Petazzoni Signed-off-by: Dan Williams --- drivers/dma/mv_xor.c | 11 +++++++++-- drivers/dma/mv_xor.h | 28 +++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index c026b27f76e1..d332b9e3f9ce 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -64,7 +64,7 @@ static u32 mv_desc_get_src_addr(struct mv_xor_desc_slot *desc, int src_idx) { struct mv_xor_desc *hw_desc = desc->hw_desc; - return hw_desc->phy_src_addr[src_idx]; + return hw_desc->phy_src_addr[mv_phy_src_idx(src_idx)]; } @@ -107,7 +107,7 @@ static void mv_desc_set_src_addr(struct mv_xor_desc_slot *desc, int index, dma_addr_t addr) { struct mv_xor_desc *hw_desc = desc->hw_desc; - hw_desc->phy_src_addr[index] = addr; + hw_desc->phy_src_addr[mv_phy_src_idx(index)] = addr; if (desc->type == DMA_XOR) hw_desc->desc_command |= (1 << index); } @@ -192,6 +192,13 @@ static void mv_set_mode(struct mv_xor_chan *chan, config &= ~0x7; config |= op_mode; + +#if defined(__BIG_ENDIAN) + config |= XOR_DESCRIPTOR_SWAP; +#else + config &= ~XOR_DESCRIPTOR_SWAP; +#endif + writel_relaxed(config, XOR_CONFIG(chan)); chan->current_type = type; } diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index c619359cb7fe..06b067f24c9b 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -29,8 +29,10 @@ #define MV_XOR_THRESHOLD 1 #define MV_XOR_MAX_CHANNELS 2 +/* Values for the XOR_CONFIG register */ #define XOR_OPERATION_MODE_XOR 0 #define XOR_OPERATION_MODE_MEMCPY 2 +#define XOR_DESCRIPTOR_SWAP BIT(14) #define XOR_CURR_DESC(chan) (chan->mmr_base + 0x210 + (chan->idx * 4)) #define XOR_NEXT_DESC(chan) (chan->mmr_base + 0x200 + (chan->idx * 4)) @@ -143,7 +145,16 @@ struct mv_xor_desc_slot { #endif }; -/* This structure describes XOR descriptor size 64bytes */ +/* + * This structure describes XOR descriptor size 64bytes. The + * mv_phy_src_idx() macro must be used when indexing the values of the + * phy_src_addr[] array. This is due to the fact that the 'descriptor + * swap' feature, used on big endian systems, swaps descriptors data + * within blocks of 8 bytes. So two consecutive values of the + * phy_src_addr[] array are actually swapped in big-endian, which + * explains the different mv_phy_src_idx() implementation. + */ +#if defined(__LITTLE_ENDIAN) struct mv_xor_desc { u32 status; /* descriptor execution status */ u32 crc32_result; /* result of CRC-32 calculation */ @@ -155,6 +166,21 @@ struct mv_xor_desc { u32 reserved0; u32 reserved1; }; +#define mv_phy_src_idx(src_idx) (src_idx) +#else +struct mv_xor_desc { + u32 crc32_result; /* result of CRC-32 calculation */ + u32 status; /* descriptor execution status */ + u32 phy_next_desc; /* next descriptor address pointer */ + u32 desc_command; /* type of operation to be carried out */ + u32 phy_dest_addr; /* destination block address */ + u32 byte_count; /* size of src/dst blocks in bytes */ + u32 phy_src_addr[8]; /* source block addresses */ + u32 reserved1; + u32 reserved0; +}; +#define mv_phy_src_idx(src_idx) (src_idx ^ 1) +#endif #define to_mv_sw_desc(addr_hw_desc) \ container_of(addr_hw_desc, struct mv_xor_desc_slot, hw_desc) -- cgit v1.2.3 From c4dcf0e2dd7e06db0c5c3f396b2e2b9ce1f6d19f Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Fri, 2 Aug 2013 21:18:03 +0200 Subject: ioatdma: disable RAID on non-Atom platforms and reenable unaligned copies Disable RAID on non-Atom platform and remove related fixups such as the 64-byte alignement restriction on legacy DMA operations (introduced in commit f26df1a1 as a workaround for silicon errata). Signed-off-by: Brice Goglin Acked-by: Dave Jiang Acked-by: Jon Mason Signed-off-by: Dan Williams --- drivers/dma/ioat/dma_v3.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index b642e035579b..c94e0d210667 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -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]; -- cgit v1.2.3 From c4d27c4d024f5440497106bb2ae15e9e60f7099c Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Mon, 19 Aug 2013 11:43:35 +0200 Subject: dmaengine: make dma_channel_rebalance() NUMA aware dma_channel_rebalance() currently distributes channels by processor ID. These IDs often change with the BIOS, and the order isn't related to the DMA channel list (related to PCI bus ids). * On my SuperMicro dual E5 machine, first socket has processor IDs [0-7] (and [16-23] for hyperthreads), second socket has [8-15]+[24-31] => channels are properly allocated to local CPUs. * On Dells R720 with same processors, first socket has even processor IDs, second socket has odd numbers => half the processors get channels on the remote socket, causing cross-NUMA traffic and lower DMA performance. Change nth_chan() to return the channel with min table_count and in the NUMA node of the given CPU, if any. If none, the (non-local) channel with min table_count is returned. nth_chan() is therefore renamed into min_chan() since we don't iterate until the nth channel anymore. In practice, the behavior is the same because first channels are taken first and are then ignored because they got an additional reference. The new code has a slightly higher complexity since we always scan the entire list of channels for finding the minimal table_count (instead of stopping after N chans), and because we check whether the CPU is in the DMA device locality mask. Overall we still have time complexity = number of chans x number of processors. This rebalance is rarely used, so this won't hurt. On the above SuperMicro machine, channels are still allocated the same. On the Dells, there are no locality issue anymore (MEMCPY channel X goes to processor X and to its hyperthread sibling). Signed-off-by: Brice Goglin Signed-off-by: Dan Williams --- drivers/dma/dmaengine.c | 55 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 9e56745f87bf..e428cf2a458b 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -376,20 +376,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) || @@ -398,27 +408,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; } /** @@ -435,7 +440,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) @@ -454,14 +458,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; } } -- cgit v1.2.3 From e6a5fa63407bfc5b7b13e850a0a67e4db8c00ce7 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sat, 20 Jul 2013 20:05:05 +0200 Subject: ioatdma: silence GCC warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building dma_v3.o triggers a GCC warning: drivers/dma/ioat/dma_v3.c: In function ‘__ioat3_prep_pq16_lock’: drivers/dma/ioat/dma_v3.c:264:11: warning: array subscript is below array bounds [-Warray-bounds] drivers/dma/ioat/dma_v3.c:264:11: warning: array subscript is below array bounds [-Warray-bounds] This warning is caused by pq16_set_src(). It uses "int idx" as an index to an eight element array. Changing "idx" to "unsigned" silences this warning. Apparently GCC can then determine that "idx" will never be negative. Signed-off-by: Paul Bolle Acked-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/dma/ioat/dma_v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index c94e0d210667..d8ececaf1b57 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -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 = -- cgit v1.2.3 From a577659f42f745b71cbc56c80fb1e801ec7e6348 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 2 Sep 2013 13:54:20 +0530 Subject: dma: mv_xor: Fix incorrect error path Return directly if memory allocation fails. There is no need of dma_free_coherent(). Signed-off-by: Sachin Kamat Cc: Saeed Bishara Signed-off-by: Dan Williams --- drivers/dma/mv_xor.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index d332b9e3f9ce..0ec086d2b6a0 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1036,10 +1036,8 @@ mv_xor_channel_add(struct mv_xor_device *xordev, struct dma_device *dma_dev; mv_chan = devm_kzalloc(&pdev->dev, sizeof(*mv_chan), GFP_KERNEL); - if (!mv_chan) { - ret = -ENOMEM; - goto err_free_dma; - } + if (!mv_chan) + return ERR_PTR(-ENOMEM); mv_chan->idx = idx; mv_chan->irq = irq; -- cgit v1.2.3