Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx
* 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx: dmatest: fix use after free in dmatest_exit ipu_idmac: fix spinlock type iop-adma, mv_xor: fix mem leak on self-test setup failure fsldma: fix off by one in dma_halt I/OAT: fail self-test if callback test reaches timeout I/OAT: update driver version and copyright dates I/OAT: list usage cleanup I/OAT: set tcp_dma_copybreak to 256k for I/OAT ver.3 I/OAT: cancel watchdog before dma remove I/OAT: fail initialization on zero channels detection I/OAT: do not set DCACTRL_CMPL_WRITE_ENABLE for I/OAT ver.3 I/OAT: add verification for proper APICID_TAG_MAP setting by BIOS dmaengine: update kerneldoc
This commit is contained in:
commit
5dc18f51a2
13 changed files with 86 additions and 50 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright(c) 2007 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
|
|
|
@ -430,13 +430,15 @@ late_initcall(dmatest_init);
|
|||
static void __exit dmatest_exit(void)
|
||||
{
|
||||
struct dmatest_chan *dtc, *_dtc;
|
||||
struct dma_chan *chan;
|
||||
|
||||
list_for_each_entry_safe(dtc, _dtc, &dmatest_channels, node) {
|
||||
list_del(&dtc->node);
|
||||
chan = dtc->chan;
|
||||
dmatest_cleanup_channel(dtc);
|
||||
pr_debug("dmatest: dropped channel %s\n",
|
||||
dma_chan_name(dtc->chan));
|
||||
dma_release_channel(dtc->chan);
|
||||
dma_chan_name(chan));
|
||||
dma_release_channel(chan);
|
||||
}
|
||||
}
|
||||
module_exit(dmatest_exit);
|
||||
|
|
|
@ -158,7 +158,8 @@ static void dma_start(struct fsl_dma_chan *fsl_chan)
|
|||
|
||||
static void dma_halt(struct fsl_dma_chan *fsl_chan)
|
||||
{
|
||||
int i = 0;
|
||||
int i;
|
||||
|
||||
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
|
||||
DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) | FSL_DMA_MR_CA,
|
||||
32);
|
||||
|
@ -166,8 +167,11 @@ static void dma_halt(struct fsl_dma_chan *fsl_chan)
|
|||
DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) & ~(FSL_DMA_MR_CS
|
||||
| FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA), 32);
|
||||
|
||||
while (!dma_is_idle(fsl_chan) && (i++ < 100))
|
||||
for (i = 0; i < 100; i++) {
|
||||
if (dma_is_idle(fsl_chan))
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
if (i >= 100 && !dma_is_idle(fsl_chan))
|
||||
dev_err(fsl_chan->dev, "DMA halt timeout!\n");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Intel I/OAT DMA Linux driver
|
||||
* Copyright(c) 2007 Intel Corporation.
|
||||
* Copyright(c) 2007 - 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Intel I/OAT DMA Linux driver
|
||||
* Copyright(c) 2007 Intel Corporation.
|
||||
* Copyright(c) 2007 - 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -49,6 +49,23 @@
|
|||
|
||||
#define DCA_TAG_MAP_MASK 0xDF
|
||||
|
||||
/* expected tag map bytes for I/OAT ver.2 */
|
||||
#define DCA2_TAG_MAP_BYTE0 0x80
|
||||
#define DCA2_TAG_MAP_BYTE1 0x0
|
||||
#define DCA2_TAG_MAP_BYTE2 0x81
|
||||
#define DCA2_TAG_MAP_BYTE3 0x82
|
||||
#define DCA2_TAG_MAP_BYTE4 0x82
|
||||
|
||||
/* verify if tag map matches expected values */
|
||||
static inline int dca2_tag_map_valid(u8 *tag_map)
|
||||
{
|
||||
return ((tag_map[0] == DCA2_TAG_MAP_BYTE0) &&
|
||||
(tag_map[1] == DCA2_TAG_MAP_BYTE1) &&
|
||||
(tag_map[2] == DCA2_TAG_MAP_BYTE2) &&
|
||||
(tag_map[3] == DCA2_TAG_MAP_BYTE3) &&
|
||||
(tag_map[4] == DCA2_TAG_MAP_BYTE4));
|
||||
}
|
||||
|
||||
/*
|
||||
* "Legacy" DCA systems do not implement the DCA register set in the
|
||||
* I/OAT device. Software needs direct support for their tag mappings.
|
||||
|
@ -452,6 +469,13 @@ struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase)
|
|||
ioatdca->tag_map[i] = 0;
|
||||
}
|
||||
|
||||
if (!dca2_tag_map_valid(ioatdca->tag_map)) {
|
||||
dev_err(&pdev->dev, "APICID_TAG_MAP set incorrectly by BIOS, "
|
||||
"disabling DCA\n");
|
||||
free_dca_provider(dca);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = register_dca_provider(dca, &pdev->dev);
|
||||
if (err) {
|
||||
free_dca_provider(dca);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Intel I/OAT DMA Linux driver
|
||||
* Copyright(c) 2004 - 2007 Intel Corporation.
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -189,11 +189,13 @@ static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
|
|||
ioat_chan->xfercap = xfercap;
|
||||
ioat_chan->desccount = 0;
|
||||
INIT_DELAYED_WORK(&ioat_chan->work, ioat_dma_chan_reset_part2);
|
||||
if (ioat_chan->device->version != IOAT_VER_1_2) {
|
||||
writel(IOAT_DCACTRL_CMPL_WRITE_ENABLE
|
||||
| IOAT_DMA_DCA_ANY_CPU,
|
||||
ioat_chan->reg_base + IOAT_DCACTRL_OFFSET);
|
||||
}
|
||||
if (ioat_chan->device->version == IOAT_VER_2_0)
|
||||
writel(IOAT_DCACTRL_CMPL_WRITE_ENABLE |
|
||||
IOAT_DMA_DCA_ANY_CPU,
|
||||
ioat_chan->reg_base + IOAT_DCACTRL_OFFSET);
|
||||
else if (ioat_chan->device->version == IOAT_VER_3_0)
|
||||
writel(IOAT_DMA_DCA_ANY_CPU,
|
||||
ioat_chan->reg_base + IOAT_DCACTRL_OFFSET);
|
||||
spin_lock_init(&ioat_chan->cleanup_lock);
|
||||
spin_lock_init(&ioat_chan->desc_lock);
|
||||
INIT_LIST_HEAD(&ioat_chan->free_desc);
|
||||
|
@ -1169,9 +1171,8 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan)
|
|||
* up if the client is done with the descriptor
|
||||
*/
|
||||
if (async_tx_test_ack(&desc->async_tx)) {
|
||||
list_del(&desc->node);
|
||||
list_add_tail(&desc->node,
|
||||
&ioat_chan->free_desc);
|
||||
list_move_tail(&desc->node,
|
||||
&ioat_chan->free_desc);
|
||||
} else
|
||||
desc->async_tx.cookie = 0;
|
||||
} else {
|
||||
|
@ -1362,6 +1363,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
|
|||
dma_cookie_t cookie;
|
||||
int err = 0;
|
||||
struct completion cmp;
|
||||
unsigned long tmo;
|
||||
|
||||
src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL);
|
||||
if (!src)
|
||||
|
@ -1413,9 +1415,10 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
|
|||
}
|
||||
device->common.device_issue_pending(dma_chan);
|
||||
|
||||
wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
|
||||
tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
|
||||
|
||||
if (device->common.device_is_tx_complete(dma_chan, cookie, NULL, NULL)
|
||||
if (tmo == 0 ||
|
||||
device->common.device_is_tx_complete(dma_chan, cookie, NULL, NULL)
|
||||
!= DMA_SUCCESS) {
|
||||
dev_err(&device->pdev->dev,
|
||||
"Self-test copy timed out, disabling\n");
|
||||
|
@ -1657,6 +1660,13 @@ struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev,
|
|||
" %d channels, device version 0x%02x, driver version %s\n",
|
||||
device->common.chancnt, device->version, IOAT_DMA_VERSION);
|
||||
|
||||
if (!device->common.chancnt) {
|
||||
dev_err(&device->pdev->dev,
|
||||
"Intel(R) I/OAT DMA Engine problem found: "
|
||||
"zero channels detected\n");
|
||||
goto err_setup_interrupts;
|
||||
}
|
||||
|
||||
err = ioat_dma_setup_interrupts(device);
|
||||
if (err)
|
||||
goto err_setup_interrupts;
|
||||
|
@ -1696,6 +1706,9 @@ void ioat_dma_remove(struct ioatdma_device *device)
|
|||
struct dma_chan *chan, *_chan;
|
||||
struct ioat_dma_chan *ioat_chan;
|
||||
|
||||
if (device->version != IOAT_VER_3_0)
|
||||
cancel_delayed_work(&device->work);
|
||||
|
||||
ioat_dma_remove_interrupts(device);
|
||||
|
||||
dma_async_device_unregister(&device->common);
|
||||
|
@ -1707,10 +1720,6 @@ void ioat_dma_remove(struct ioatdma_device *device)
|
|||
pci_release_regions(device->pdev);
|
||||
pci_disable_device(device->pdev);
|
||||
|
||||
if (device->version != IOAT_VER_3_0) {
|
||||
cancel_delayed_work(&device->work);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(chan, _chan,
|
||||
&device->common.channels, device_node) {
|
||||
ioat_chan = to_ioat_chan(chan);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
|
@ -29,7 +29,7 @@
|
|||
#include <linux/pci_ids.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#define IOAT_DMA_VERSION "3.30"
|
||||
#define IOAT_DMA_VERSION "3.64"
|
||||
|
||||
enum ioat_interrupt {
|
||||
none = 0,
|
||||
|
@ -135,12 +135,14 @@ static inline void ioat_set_tcp_copy_break(struct ioatdma_device *dev)
|
|||
#ifdef CONFIG_NET_DMA
|
||||
switch (dev->version) {
|
||||
case IOAT_VER_1_2:
|
||||
case IOAT_VER_3_0:
|
||||
sysctl_tcp_dma_copybreak = 4096;
|
||||
break;
|
||||
case IOAT_VER_2_0:
|
||||
sysctl_tcp_dma_copybreak = 2048;
|
||||
break;
|
||||
case IOAT_VER_3_0:
|
||||
sysctl_tcp_dma_copybreak = 262144;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
|
|
|
@ -928,19 +928,19 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
|
|||
|
||||
for (src_idx = 0; src_idx < IOP_ADMA_NUM_SRC_TEST; src_idx++) {
|
||||
xor_srcs[src_idx] = alloc_page(GFP_KERNEL);
|
||||
if (!xor_srcs[src_idx])
|
||||
while (src_idx--) {
|
||||
if (!xor_srcs[src_idx]) {
|
||||
while (src_idx--)
|
||||
__free_page(xor_srcs[src_idx]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
dest = alloc_page(GFP_KERNEL);
|
||||
if (!dest)
|
||||
while (src_idx--) {
|
||||
if (!dest) {
|
||||
while (src_idx--)
|
||||
__free_page(xor_srcs[src_idx]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Fill in src buffers */
|
||||
for (src_idx = 0; src_idx < IOP_ADMA_NUM_SRC_TEST; src_idx++) {
|
||||
|
|
|
@ -729,7 +729,7 @@ static int ipu_init_channel_buffer(struct idmac_channel *ichan,
|
|||
|
||||
ichan->status = IPU_CHANNEL_READY;
|
||||
|
||||
spin_unlock_irqrestore(ipu->lock, flags);
|
||||
spin_unlock_irqrestore(&ipu->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1019,19 +1019,19 @@ mv_xor_xor_self_test(struct mv_xor_device *device)
|
|||
|
||||
for (src_idx = 0; src_idx < MV_XOR_NUM_SRC_TEST; src_idx++) {
|
||||
xor_srcs[src_idx] = alloc_page(GFP_KERNEL);
|
||||
if (!xor_srcs[src_idx])
|
||||
while (src_idx--) {
|
||||
if (!xor_srcs[src_idx]) {
|
||||
while (src_idx--)
|
||||
__free_page(xor_srcs[src_idx]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
dest = alloc_page(GFP_KERNEL);
|
||||
if (!dest)
|
||||
while (src_idx--) {
|
||||
if (!dest) {
|
||||
while (src_idx--)
|
||||
__free_page(xor_srcs[src_idx]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Fill in src buffers */
|
||||
for (src_idx = 0; src_idx < MV_XOR_NUM_SRC_TEST; src_idx++) {
|
||||
|
|
|
@ -97,7 +97,6 @@ typedef struct { DECLARE_BITMAP(bits, DMA_TX_TYPE_END); } dma_cap_mask_t;
|
|||
|
||||
/**
|
||||
* struct dma_chan_percpu - the per-CPU part of struct dma_chan
|
||||
* @refcount: local_t used for open-coded "bigref" counting
|
||||
* @memcpy_count: transaction counter
|
||||
* @bytes_transferred: byte counter
|
||||
*/
|
||||
|
@ -114,9 +113,6 @@ struct dma_chan_percpu {
|
|||
* @cookie: last cookie value returned to client
|
||||
* @chan_id: channel ID for sysfs
|
||||
* @dev: class device for sysfs
|
||||
* @refcount: kref, used in "bigref" slow-mode
|
||||
* @slow_ref: indicates that the DMA channel is free
|
||||
* @rcu: the DMA channel's RCU head
|
||||
* @device_node: used to add this to the device chan list
|
||||
* @local: per-cpu pointer to a struct dma_chan_percpu
|
||||
* @client-count: how many clients are using this channel
|
||||
|
@ -213,8 +209,6 @@ struct dma_async_tx_descriptor {
|
|||
* @global_node: list_head for global dma_device_list
|
||||
* @cap_mask: one or more dma_capability flags
|
||||
* @max_xor: maximum number of xor sources, 0 if no capability
|
||||
* @refcount: reference count
|
||||
* @done: IO completion struct
|
||||
* @dev_id: unique device ID
|
||||
* @dev: struct device reference for dma mapping api
|
||||
* @device_alloc_chan_resources: allocate resources and return the
|
||||
|
@ -227,6 +221,7 @@ struct dma_async_tx_descriptor {
|
|||
* @device_prep_dma_interrupt: prepares an end of chain interrupt operation
|
||||
* @device_prep_slave_sg: prepares a slave dma operation
|
||||
* @device_terminate_all: terminate all pending operations
|
||||
* @device_is_tx_complete: poll for transaction completion
|
||||
* @device_issue_pending: push pending transactions to hardware
|
||||
*/
|
||||
struct dma_device {
|
||||
|
|
Loading…
Reference in a new issue