aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/ahci.c24
-rw-r--r--drivers/ata/libata-core.c14
-rw-r--r--drivers/ata/libata-eh.c7
-rw-r--r--drivers/ata/sata_nv.c2
-rw-r--r--drivers/block/cciss.c8
-rw-r--r--drivers/block/loop.c3
-rw-r--r--drivers/block/xen-blkfront.c2
-rw-r--r--drivers/dca/dca-core.c2
-rw-r--r--drivers/dma/dmatest.c6
-rw-r--r--drivers/dma/fsldma.c8
-rw-r--r--drivers/dma/ioat.c2
-rw-r--r--drivers/dma/ioat_dca.c26
-rw-r--r--drivers/dma/ioat_dma.c39
-rw-r--r--drivers/dma/ioatdma.h8
-rw-r--r--drivers/dma/ioatdma_hw.h2
-rw-r--r--drivers/dma/ioatdma_registers.h2
-rw-r--r--drivers/dma/iop-adma.c16
-rw-r--r--drivers/dma/ipu/ipu_idmac.c2
-rw-r--r--drivers/dma/mv_xor.c16
-rw-r--r--drivers/ide/Kconfig5
-rw-r--r--drivers/ide/Makefile1
-rw-r--r--drivers/ide/at91_ide.c467
-rw-r--r--drivers/ide/ide-disk_proc.c2
-rw-r--r--drivers/ide/ide-floppy_proc.c2
-rw-r--r--drivers/ide/ide-io.c3
-rw-r--r--drivers/ide/ide-iops.c2
-rw-r--r--drivers/ide/ide-probe.c7
-rw-r--r--drivers/ide/ide-proc.c2
-rw-r--r--drivers/ide/ide-tape.c2
-rw-r--r--drivers/mmc/core/mmc_ops.c15
-rw-r--r--drivers/watchdog/gef_wdt.c2
-rw-r--r--drivers/watchdog/ks8695_wdt.c1
-rw-r--r--drivers/watchdog/orion5x_wdt.c1
-rw-r--r--drivers/watchdog/rc32434_wdt.c168
34 files changed, 685 insertions, 184 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index a603bbf9b1b..66e012cd327 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -582,18 +582,18 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */
{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */
{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci }, /* MCP89 */
/* SiS */
{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 9fbf0595f3d..060bcd601f5 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1322,14 +1322,16 @@ static u64 ata_id_n_sectors(const u16 *id)
{
if (ata_id_has_lba(id)) {
if (ata_id_has_lba48(id))
- return ata_id_u64(id, 100);
+ return ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
else
- return ata_id_u32(id, 60);
+ return ata_id_u32(id, ATA_ID_LBA_CAPACITY);
} else {
if (ata_id_current_chs_valid(id))
- return ata_id_u32(id, 57);
+ return id[ATA_ID_CUR_CYLS] * id[ATA_ID_CUR_HEADS] *
+ id[ATA_ID_CUR_SECTORS];
else
- return id[1] * id[3] * id[6];
+ return id[ATA_ID_CYLS] * id[ATA_ID_HEADS] *
+ id[ATA_ID_SECTORS];
}
}
@@ -4612,7 +4614,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
VPRINTK("unmapping %u sg elements\n", qc->n_elem);
if (qc->n_elem)
- dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
+ dma_unmap_sg(ap->dev, sg, qc->orig_n_elem, dir);
qc->flags &= ~ATA_QCFLAG_DMAMAP;
qc->sg = NULL;
@@ -4727,7 +4729,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
return -1;
DPRINTK("%d sg elements mapped\n", n_elem);
-
+ qc->orig_n_elem = qc->n_elem;
qc->n_elem = n_elem;
qc->flags |= ATA_QCFLAG_DMAMAP;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index ce2ef047533..ea890911d4f 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2423,11 +2423,14 @@ int ata_eh_reset(struct ata_link *link, int classify,
}
/* prereset() might have cleared ATA_EH_RESET. If so,
- * bang classes and return.
+ * bang classes, thaw and return.
*/
if (reset && !(ehc->i.action & ATA_EH_RESET)) {
ata_for_each_dev(dev, link, ALL)
classes[dev->devno] = ATA_DEV_NONE;
+ if ((ap->pflags & ATA_PFLAG_FROZEN) &&
+ ata_is_host_link(link))
+ ata_eh_thaw_port(ap);
rc = 0;
goto out;
}
@@ -2901,7 +2904,7 @@ static int atapi_eh_clear_ua(struct ata_device *dev)
int i;
for (i = 0; i < ATA_EH_UA_TRIES; i++) {
- u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
+ u8 *sense_buffer = dev->link->ap->sector_buf;
u8 sense_key = 0;
unsigned int err_mask;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 55a8eed3f3a..f65b53785a8 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -2523,7 +2523,7 @@ static void __exit nv_exit(void)
module_init(nv_init);
module_exit(nv_exit);
module_param_named(adma, adma_enabled, bool, 0444);
-MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)");
+MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: false)");
module_param_named(swncq, swncq_enabled, bool, 0444);
MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: true)");
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index b5a06111463..4f9b6d79201 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -3606,11 +3606,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
if (cciss_hard_reset_controller(pdev) || cciss_reset_msi(pdev))
return -ENODEV;
- /* Some devices (notably the HP Smart Array 5i Controller)
- need a little pause here */
- schedule_timeout_uninterruptible(30*HZ);
-
- /* Now try to get the controller to respond to a no-op */
+ /* Now try to get the controller to respond to a no-op. Some
+ devices (notably the HP Smart Array 5i Controller) need
+ up to 30 seconds to respond. */
for (i=0; i<30; i++) {
if (cciss_noop(pdev) == 0)
break;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index edbaac6c057..bf034557767 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -392,8 +392,7 @@ lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
struct loop_device *lo = p->lo;
struct page *page = buf->page;
sector_t IV;
- size_t size;
- int ret;
+ int size, ret;
ret = buf->ops->confirm(pipe, buf);
if (unlikely(ret))
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index b6c8ce25435..8f905089b72 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -977,6 +977,8 @@ static void backend_changed(struct xenbus_device *dev,
break;
case XenbusStateClosing:
+ if (info->gd == NULL)
+ xenbus_dev_fatal(dev, -ENODEV, "gd is NULL");
bd = bdget_disk(info->gd, 0);
if (bd == NULL)
xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c
index 33bd7534751..25b743abfb5 100644
--- a/drivers/dca/dca-core.c
+++ b/drivers/dca/dca-core.c
@@ -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
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 732fa1ec36a..e190d8b3070 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -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);
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 70126a60623..86d6da47f55 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -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");
}
diff --git a/drivers/dma/ioat.c b/drivers/dma/ioat.c
index 4105d6575b6..ed83dd9df19 100644
--- a/drivers/dma/ioat.c
+++ b/drivers/dma/ioat.c
@@ -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,
diff --git a/drivers/dma/ioat_dca.c b/drivers/dma/ioat_dca.c
index 6cf622da028..c012a1e1504 100644
--- a/drivers/dma/ioat_dca.c
+++ b/drivers/dma/ioat_dca.c
@@ -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);
diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c
index b3759c4b653..5905cd36bcd 100644
--- a/drivers/dma/ioat_dma.c
+++ b/drivers/dma/ioat_dma.c
@@ -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);
diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h
index a3306d0e137..a52ff4bd460 100644
--- a/drivers/dma/ioatdma.h
+++ b/drivers/dma/ioatdma.h
@@ -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
}
diff --git a/drivers/dma/ioatdma_hw.h b/drivers/dma/ioatdma_hw.h
index f1ae2c776f7..afa57eef86c 100644
--- a/drivers/dma/ioatdma_hw.h
+++ b/drivers/dma/ioatdma_hw.h
@@ -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
diff --git a/drivers/dma/ioatdma_registers.h b/drivers/dma/ioatdma_registers.h
index 827cb503cac..49bc277424f 100644
--- a/drivers/dma/ioatdma_registers.h
+++ b/drivers/dma/ioatdma_registers.h
@@ -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
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index 647374acba9..16adbe61cfb 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -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++) {
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c
index 1f154d08e98..ae50a9d1a4e 100644
--- a/drivers/dma/ipu/ipu_idmac.c
+++ b/drivers/dma/ipu/ipu_idmac.c
@@ -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;
}
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 5d5d5b31867..cb7f26fb9f1 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -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++) {
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index e072903b12f..5ea3bfad172 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -721,6 +721,11 @@ config BLK_DEV_IDE_TX4939
depends on SOC_TX4939
select BLK_DEV_IDEDMA_SFF
+config BLK_DEV_IDE_AT91
+ tristate "Atmel AT91 (SAM9, CAP9, AT572D940HF) IDE support"
+ depends on ARM && ARCH_AT91 && !ARCH_AT91RM9200 && !ARCH_AT91X40
+ select IDE_TIMINGS
+
config IDE_ARM
tristate "ARM IDE support"
depends on ARM && (ARCH_RPC || ARCH_SHARK)
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index d0e3d7d5b46..1c326d94aa6 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -116,3 +116,4 @@ obj-$(CONFIG_BLK_DEV_IDE_AU1XXX) += au1xxx-ide.o
obj-$(CONFIG_BLK_DEV_IDE_TX4938) += tx4938ide.o
obj-$(CONFIG_BLK_DEV_IDE_TX4939) += tx4939ide.o
+obj-$(CONFIG_BLK_DEV_IDE_AT91) += at91_ide.o
diff --git a/drivers/ide/at91_ide.c b/drivers/ide/at91_ide.c
new file mode 100644
index 00000000000..1bb50f46388
--- /dev/null
+++ b/drivers/ide/at91_ide.c
@@ -0,0 +1,467 @@
+/*
+ * IDE host driver for AT91 (SAM9, CAP9, AT572D940HF) Static Memory Controller
+ * with Compact Flash True IDE logic
+ *
+ * Copyright (c) 2008, 2009 Kelvatek Ltd.
+ *
+ * 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 Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/ide.h>
+#include <linux/platform_device.h>
+
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91sam9263.h>
+#include <mach/at91sam9_smc.h>
+#include <mach/at91sam9263_matrix.h>
+
+#define DRV_NAME "at91_ide"
+
+#define perr(fmt, args...) pr_err(DRV_NAME ": " fmt, ##args)
+#define pdbg(fmt, args...) pr_debug("%s " fmt, __func__, ##args)
+
+/*
+ * Access to IDE device is possible through EBI Static Memory Controller
+ * with Compact Flash logic. For details see EBI and SMC datasheet sections
+ * of any microcontroller from AT91SAM9 family.
+ *
+ * Within SMC chip select address space, lines A[23:21] distinguish Compact
+ * Flash modes (I/O, common memory, attribute memory, True IDE). IDE modes are:
+ * 0x00c0000 - True IDE
+ * 0x00e0000 - Alternate True IDE (Alt Status Register)
+ *
+ * On True IDE mode Task File and Data Register are mapped at the same address.
+ * To distinguish access between these two different bus data width is used:
+ * 8Bit for Task File, 16Bit for Data I/O.
+ *
+ * After initialization we do 8/16 bit flipping (changes in SMC MODE register)
+ * only inside IDE callback routines which are serialized by IDE layer,
+ * so no additional locking needed.
+ */
+
+#define TASK_FILE 0x00c00000
+#define ALT_MODE 0x00e00000
+#define REGS_SIZE 8
+
+#define enter_16bit(cs, mode) do { \
+ mode = at91_sys_read(AT91_SMC_MODE(cs)); \
+ at91_sys_write(AT91_SMC_MODE(cs), mode | AT91_SMC_DBW_16); \
+} while (0)
+
+#define leave_16bit(cs, mode) at91_sys_write(AT91_SMC_MODE(cs), mode);
+
+static void set_smc_timings(const u8 chipselect, const u16 cycle,
+ const u16 setup, const u16 pulse,
+ const u16 data_float, int use_iordy)
+{
+ unsigned long mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
+ AT91_SMC_BAT_SELECT;
+
+ /* disable or enable waiting for IORDY signal */
+ if (use_iordy)
+ mode |= AT91_SMC_EXNWMODE_READY;
+
+ /* add data float cycles if needed */
+ if (data_float)
+ mode |= AT91_SMC_TDF_(data_float);
+
+ at91_sys_write(AT91_SMC_MODE(chipselect), mode);
+
+ /* setup timings in SMC */
+ at91_sys_write(AT91_SMC_SETUP(chipselect), AT91_SMC_NWESETUP_(setup) |
+ AT91_SMC_NCS_WRSETUP_(0) |
+ AT91_SMC_NRDSETUP_(setup) |
+ AT91_SMC_NCS_RDSETUP_(0));
+ at91_sys_write(AT91_SMC_PULSE(chipselect), AT91_SMC_NWEPULSE_(pulse) |
+ AT91_SMC_NCS_WRPULSE_(cycle) |
+ AT91_SMC_NRDPULSE_(pulse) |
+ AT91_SMC_NCS_RDPULSE_(cycle));
+ at91_sys_write(AT91_SMC_CYCLE(chipselect), AT91_SMC_NWECYCLE_(cycle) |
+ AT91_SMC_NRDCYCLE_(cycle));
+}
+
+static unsigned int calc_mck_cycles(unsigned int ns, unsigned int mck_hz)
+{
+ u64 tmp = ns;
+
+ tmp *= mck_hz;
+ tmp += 1000*1000*1000 - 1; /* round up */
+ do_div(tmp, 1000*1000*1000);
+ return (unsigned int) tmp;
+}
+
+static void apply_timings(const u8 chipselect, const u8 pio,
+ const struct ide_timing *timing, int use_iordy)
+{
+ unsigned int t0, t1, t2, t6z;
+ unsigned int cycle, setup, pulse, data_float;
+ unsigned int mck_hz;
+ struct clk *mck;
+
+ /* see table 22 of Compact Flash standard 4.1 for the meaning,
+ * we do not stretch active (t2) time, so setup (t1) + hold time (th)
+ * assure at least minimal recovery (t2i) time */
+ t0 = timing->cyc8b;
+ t1 = timing->setup;
+ t2 = timing->act8b;
+ t6z = (pio < 5) ? 30 : 20;
+
+ pdbg("t0=%u t1=%u t2=%u t6z=%u\n", t0, t1, t2, t6z);
+
+ mck = clk_get(NULL, "mck");
+ BUG_ON(IS_ERR(mck));
+ mck_hz = clk_get_rate(mck);
+ pdbg("mck_hz=%u\n", mck_hz);
+
+ cycle = calc_mck_cycles(t0, mck_hz);
+ setup = calc_mck_cycles(t1, mck_hz);
+ pulse = calc_mck_cycles(t2, mck_hz);
+ data_float = calc_mck_cycles(t6z, mck_hz);
+
+ pdbg("cycle=%u setup=%u pulse=%u data_float=%u\n",
+ cycle, setup, pulse, data_float);
+
+ set_smc_timings(chipselect, cycle, setup, pulse, data_float, use_iordy);
+}
+
+static void at91_ide_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ u8 chipselect = hwif->select_data;
+ unsigned long mode;
+
+ pdbg("cs %u buf %p len %d\n", chipselect, buf, len);
+
+ len++;
+
+ enter_16bit(chipselect, mode);
+ __ide_mm_insw((void __iomem *) io_ports->data_addr, buf, len / 2);
+ leave_16bit(chipselect, mode);
+}
+
+static void at91_ide_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ u8 chipselect = hwif->select_data;
+ unsigned long mode;
+
+ pdbg("cs %u buf %p len %d\n", chipselect, buf, len);
+
+ enter_16bit(chipselect, mode);
+ __ide_mm_outsw((void __iomem *) io_ports->data_addr, buf, len / 2);
+ leave_16bit(chipselect, mode);
+}
+
+static u8 ide_mm_inb(unsigned long port)
+{
+ return readb((void __iomem *) port);
+}
+
+static void ide_mm_outb(u8 value, unsigned long port)
+{
+ writeb(value, (void __iomem *) port);
+}
+
+static void at91_ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ HIHI = 0xFF;
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
+ u16 data = (tf->hob_data << 8) | tf->data;
+
+ at91_ide_output_data(drive, NULL, &data, 2);
+ }
+
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+ ide_mm_outb(tf->hob_feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+ ide_mm_outb(tf->hob_nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+ ide_mm_outb(tf->hob_lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+ ide_mm_outb(tf->hob_lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+ ide_mm_outb(tf->hob_lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+ ide_mm_outb(tf->feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+ ide_mm_outb(tf->nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+ ide_mm_outb(tf->lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+ ide_mm_outb(tf->lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+ ide_mm_outb(tf->lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+ ide_mm_outb((tf->device & HIHI) | drive->select, io_ports->device_addr);
+}
+
+static void at91_ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data;
+
+ at91_ide_input_data(drive, NULL, &data, 2);
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ ide_mm_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
+ tf->feature = ide_mm_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = ide_mm_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = ide_mm_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = ide_mm_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = ide_mm_inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = ide_mm_inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ ide_mm_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature = ide_mm_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = ide_mm_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = ide_mm_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = ide_mm_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = ide_mm_inb(io_ports->lbah_addr);
+ }
+}
+
+static void at91_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ struct ide_timing *timing;
+ u8 chipselect = drive->hwif->select_data;
+ int use_iordy = 0;
+
+ pdbg("chipselect %u pio %u\n", chipselect, pio);
+
+ timing = ide_timing_find_mode(XFER_PIO_0 + pio);
+ BUG_ON(!timing);
+
+ if ((pio > 2 || ata_id_has_iordy(drive->id)) &&
+ !(ata_id_is_cfa(drive->id) && pio > 4))
+ use_iordy = 1;
+
+ apply_timings(chipselect, pio, timing, use_iordy);
+}
+
+static const struct ide_tp_ops at91_ide_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .set_irq = ide_set_irq,
+
+ .tf_load = at91_ide_tf_load,
+ .tf_read = at91_ide_tf_read,
+
+ .input_data = at91_ide_input_data,
+ .output_data = at91_ide_output_data,
+};
+
+static const struct ide_port_ops at91_ide_port_ops = {
+ .set_pio_mode = at91_ide_set_pio_mode,
+};
+
+static const struct ide_port_info at91_ide_port_info __initdata = {
+ .port_ops = &at91_ide_port_ops,
+ .tp_ops = &at91_ide_tp_ops,
+ .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA | IDE_HFLAG_SINGLE |
+ IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_UNMASK_IRQS,
+ .pio_mask = ATA_PIO5,
+};
+
+/*
+ * If interrupt is delivered through GPIO, IRQ are triggered on falling
+ * and rising edge of signal. Whereas IDE device request interrupt on high
+ * level (rising edge in our case). This mean we have fake interrupts, so
+ * we need to check interrupt pin and exit instantly from ISR when line
+ * is on low level.
+ */
+
+irqreturn_t at91_irq_handler(int irq, void *dev_id)
+{
+ int ntries = 8;
+ int pin_val1, pin_val2;
+
+ /* additional deglitch, line can be noisy in badly designed PCB */
+ do {
+ pin_val1 = at91_get_gpio_value(irq);
+ pin_val2 = at91_get_gpio_value(irq);
+ } while (pin_val1 != pin_val2 && --ntries > 0);
+
+ if (pin_val1 == 0 || ntries <= 0)
+ return IRQ_HANDLED;
+
+ return ide_intr(irq, dev_id);
+}
+
+static int __init at91_ide_probe(struct platform_device *pdev)
+{
+ int ret;
+ hw_regs_t hw;
+ hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
+ struct ide_host *host;
+ struct resource *res;
+ unsigned long tf_base = 0, ctl_base = 0;
+ struct at91_cf_data *board = pdev->dev.platform_data;
+
+ if (!board)
+ return -ENODEV;
+
+ if (board->det_pin && at91_get_gpio_value(board->det_pin) != 0) {
+ perr("no device detected\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ perr("can't get memory resource\n");
+ return -ENODEV;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, res->start + TASK_FILE,
+ REGS_SIZE, "ide") ||
+ !devm_request_mem_region(&pdev->dev, res->start + ALT_MODE,
+ REGS_SIZE, "alt")) {
+ perr("memory resources in use\n");
+ return -EBUSY;
+ }
+
+ pdbg("chipselect %u irq %u res %08lx\n", board->chipselect,
+ board->irq_pin, (unsigned long) res->start);
+
+ tf_base = (unsigned long) devm_ioremap(&pdev->dev, res->start + TASK_FILE,
+ REGS_SIZE);
+ ctl_base = (unsigned long) devm_ioremap(&pdev->dev, res->start + ALT_MODE,
+ REGS_SIZE);
+ if (!tf_base || !ctl_base) {
+ perr("can't map memory regions\n");
+ return -EBUSY;
+ }
+
+ memset(&hw, 0, sizeof(hw));
+
+ if (board->flags & AT91_IDE_SWAP_A0_A2) {
+ /* workaround for stupid hardware bug */
+ hw.io_ports.data_addr = tf_base + 0;
+ hw.io_ports.error_addr = tf_base + 4;
+ hw.io_ports.nsect_addr = tf_base + 2;
+ hw.io_ports.lbal_addr = tf_base + 6;
+ hw.io_ports.lbam_addr = tf_base + 1;
+ hw.io_ports.lbah_addr = tf_base + 5;
+ hw.io_ports.device_addr = tf_base + 3;
+ hw.io_ports.command_addr = tf_base + 7;
+ hw.io_ports.ctl_addr = ctl_base + 3;
+ } else
+ ide_std_init_ports(&hw, tf_base, ctl_base + 6);
+
+ hw.irq = board->irq_pin;
+ hw.chipset = ide_generic;
+ hw.dev = &pdev->dev;
+
+ host = ide_host_alloc(&at91_ide_port_info, hws);
+ if (!host) {
+ perr("failed to allocate ide host\n");
+ return -ENOMEM;
+ }
+
+ /* setup Static Memory Controller - PIO 0 as default */
+ apply_timings(board->chipselect, 0, ide_timing_find_mode(XFER_PIO_0), 0);
+
+ /* with GPIO interrupt we have to do quirks in handler */
+ if (board->irq_pin >= PIN_BASE)
+ host->irq_handler = at91_irq_handler;
+
+ host->ports[0]->select_data = board->chipselect;
+
+ ret = ide_host_register(host, &at91_ide_port_info, hws);
+ if (ret) {
+ perr("failed to register ide host\n");
+ goto err_free_host;
+ }
+ platform_set_drvdata(pdev, host);
+ return 0;
+
+err_free_host:
+ ide_host_free(host);
+ return ret;
+}
+
+static int __exit at91_ide_remove(struct platform_device *pdev)
+{
+ struct ide_host *host = platform_get_drvdata(pdev);
+
+ ide_host_remove(host);
+ return 0;
+}
+
+static struct platform_driver at91_ide_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(at91_ide_remove),
+};
+
+static int __init at91_ide_init(void)
+{
+ return platform_driver_probe(&at91_ide_driver, at91_ide_probe);
+}
+
+static void __exit at91_ide_exit(void)
+{
+ platform_driver_unregister(&at91_ide_driver);
+}
+
+module_init(at91_ide_init);
+module_exit(at91_ide_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stanislaw Gruszka <stf_xl@wp.pl>");
+
diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c
index 1146f4204c6..1f86dcbd2b1 100644
--- a/drivers/ide/ide-disk_proc.c
+++ b/drivers/ide/ide-disk_proc.c
@@ -125,5 +125,5 @@ const struct ide_proc_devset ide_disk_settings[] = {
IDE_PROC_DEVSET(multcount, 0, 16),
IDE_PROC_DEVSET(nowerr, 0, 1),
IDE_PROC_DEVSET(wcache, 0, 1),
- { 0 },
+ { NULL },
};
diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c
index 3ec762cb60a..fcd4d8153df 100644
--- a/drivers/ide/ide-floppy_proc.c
+++ b/drivers/ide/ide-floppy_proc.c
@@ -29,5 +29,5 @@ const struct ide_proc_devset ide_floppy_settings[] = {
IDE_PROC_DEVSET(bios_head, 0, 255),
IDE_PROC_DEVSET(bios_sect, 0, 63),
IDE_PROC_DEVSET(ticks, 0, 255),
- { 0 },
+ { NULL },
};
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 9ee51adf567..a9a6c208288 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -908,7 +908,7 @@ void ide_timer_expiry (unsigned long data)
ide_drive_t *uninitialized_var(drive);
ide_handler_t *handler;
unsigned long flags;
- unsigned long wait = -1;
+ int wait = -1;
int plug_device = 0;
spin_lock_irqsave(&hwif->lock, flags);
@@ -1162,6 +1162,7 @@ out_early:
return irq_ret;
}
+EXPORT_SYMBOL_GPL(ide_intr);
/**
* ide_do_drive_cmd - issue IDE special command
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 753b92ebe0a..b1892bd95c6 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -315,6 +315,8 @@ void ide_output_data(ide_drive_t *drive, struct request *rq, void *buf,
u8 io_32bit = drive->io_32bit;
u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+ len++;
+
if (io_32bit) {
unsigned long uninitialized_var(flags);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index ce0818a993f..ee8e3e7cad5 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -950,6 +950,7 @@ static int ide_port_setup_devices(ide_hwif_t *hwif)
static int init_irq (ide_hwif_t *hwif)
{
struct ide_io_ports *io_ports = &hwif->io_ports;
+ irq_handler_t irq_handler;
int sa = 0;
mutex_lock(&ide_cfg_mtx);
@@ -959,6 +960,10 @@ static int init_irq (ide_hwif_t *hwif)
hwif->timer.function = &ide_timer_expiry;
hwif->timer.data = (unsigned long)hwif;
+ irq_handler = hwif->host->irq_handler;
+ if (irq_handler == NULL)
+ irq_handler = ide_intr;
+
#if defined(__mc68000__)
sa = IRQF_SHARED;
#endif /* __mc68000__ */
@@ -969,7 +974,7 @@ static int init_irq (ide_hwif_t *hwif)
if (io_ports->ctl_addr)
hwif->tp_ops->set_irq(hwif, 1);
- if (request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwif))
+ if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
goto out_up;
if (!hwif->rqsize) {
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 1d8978b3314..a7b9287ee0d 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -231,7 +231,7 @@ static const struct ide_proc_devset ide_generic_settings[] = {
IDE_PROC_DEVSET(pio_mode, 0, 255),
IDE_PROC_DEVSET(unmaskirq, 0, 1),
IDE_PROC_DEVSET(using_dma, 0, 1),
- { 0 },
+ { NULL },
};
static void proc_ide_settings_warn(void)
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index bb450a7608c..4e6181c7bbd 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -2166,7 +2166,7 @@ static const struct ide_proc_devset idetape_settings[] = {
__IDE_PROC_DEVSET(speed, 0, 0xffff, NULL, NULL),
__IDE_PROC_DEVSET(tdsc, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX,
mulf_tdsc, divf_tdsc),
- { 0 },
+ { NULL },
};
#endif
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 9c50e6f1c23..34ce2703d29 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -248,12 +248,15 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
sg_init_one(&sg, data_buf, len);
- /*
- * The spec states that CSR and CID accesses have a timeout
- * of 64 clock cycles.
- */
- data.timeout_ns = 0;
- data.timeout_clks = 64;
+ if (opcode == MMC_SEND_CSD || opcode == MMC_SEND_CID) {
+ /*
+ * The spec states that CSR and CID accesses have a timeout
+ * of 64 clock cycles.
+ */
+ data.timeout_ns = 0;
+ data.timeout_clks = 64;
+ } else
+ mmc_set_data_timeout(&data, card);
mmc_wait_for_req(host, &mrq);
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c
index f0c2b7a1a17..734d9806a87 100644
--- a/drivers/watchdog/gef_wdt.c
+++ b/drivers/watchdog/gef_wdt.c
@@ -269,7 +269,7 @@ static int __devinit gef_wdt_probe(struct of_device *dev,
bus_clk = 133; /* in MHz */
freq = fsl_get_sys_freq();
- if (freq > 0)
+ if (freq != -1)
bus_clk = freq;
/* Map devices registers into memory */
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index 0b798fdaa37..74c92d38411 100644
--- a/drivers/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -21,6 +21,7 @@
#include <linux/watchdog.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <mach/timex.h>
#include <mach/regs-timer.h>
#define WDT_DEFAULT_TIME 5 /* seconds */
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c
index 14a339f58b6..b64ae1a1783 100644
--- a/drivers/watchdog/orion5x_wdt.c
+++ b/drivers/watchdog/orion5x_wdt.c
@@ -29,6 +29,7 @@
#define WDT_EN 0x0010
#define WDT_VAL (TIMER_VIRT_BASE + 0x0024)
+#define ORION5X_TCLK 166666667
#define WDT_MAX_DURATION (0xffffffff / ORION5X_TCLK)
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c
index 57027f4653c..f3553fa40b1 100644
--- a/drivers/watchdog/rc32434_wdt.c
+++ b/drivers/watchdog/rc32434_wdt.c
@@ -34,104 +34,89 @@
#include <asm/time.h>
#include <asm/mach-rc32434/integ.h>
-#define MAX_TIMEOUT 20
-#define RC32434_WDT_INTERVAL (15 * HZ)
-
-#define VERSION "0.2"
+#define VERSION "0.4"
static struct {
- struct completion stop;
- int running;
- struct timer_list timer;
- int queue;
- int default_ticks;
unsigned long inuse;
} rc32434_wdt_device;
static struct integ __iomem *wdt_reg;
-static int ticks = 100 * HZ;
static int expect_close;
-static int timeout;
+
+/* Board internal clock speed in Hz,
+ * the watchdog timer ticks at. */
+extern unsigned int idt_cpu_freq;
+
+/* translate wtcompare value to seconds and vice versa */
+#define WTCOMP2SEC(x) (x / idt_cpu_freq)
+#define SEC2WTCOMP(x) (x * idt_cpu_freq)
+
+/* Use a default timeout of 20s. This should be
+ * safe for CPU clock speeds up to 400MHz, as
+ * ((2 ^ 32) - 1) / (400MHz / 2) = 21s. */
+#define WATCHDOG_TIMEOUT 20
+
+static int timeout = WATCHDOG_TIMEOUT;
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+/* apply or and nand masks to data read from addr and write back */
+#define SET_BITS(addr, or, nand) \
+ writel((readl(&addr) | or) & ~nand, &addr)
static void rc32434_wdt_start(void)
{
- u32 val;
-
- if (!rc32434_wdt_device.inuse) {
- writel(0, &wdt_reg->wtcount);
+ u32 or, nand;
- val = RC32434_ERR_WRE;
- writel(readl(&wdt_reg->errcs) | val, &wdt_reg->errcs);
+ /* zero the counter before enabling */
+ writel(0, &wdt_reg->wtcount);
- val = RC32434_WTC_EN;
- writel(readl(&wdt_reg->wtc) | val, &wdt_reg->wtc);
- }
- rc32434_wdt_device.running++;
-}
+ /* don't generate a non-maskable interrupt,
+ * do a warm reset instead */
+ nand = 1 << RC32434_ERR_WNE;
+ or = 1 << RC32434_ERR_WRE;
-static void rc32434_wdt_stop(void)
-{
- u32 val;
+ /* reset the ERRCS timeout bit in case it's set */
+ nand |= 1 << RC32434_ERR_WTO;
- if (rc32434_wdt_device.running) {
+ SET_BITS(wdt_reg->errcs, or, nand);
- val = ~RC32434_WTC_EN;
- writel(readl(&wdt_reg->wtc) & val, &wdt_reg->wtc);
+ /* reset WTC timeout bit and enable WDT */
+ nand = 1 << RC32434_WTC_TO;
+ or = 1 << RC32434_WTC_EN;
- val = ~RC32434_ERR_WRE;
- writel(readl(&wdt_reg->errcs) & val, &wdt_reg->errcs);
+ SET_BITS(wdt_reg->wtc, or, nand);
+}
- rc32434_wdt_device.running = 0;
- }
+static void rc32434_wdt_stop(void)
+{
+ /* Disable WDT */
+ SET_BITS(wdt_reg->wtc, 0, 1 << RC32434_WTC_EN);
}
-static void rc32434_wdt_set(int new_timeout)
+static int rc32434_wdt_set(int new_timeout)
{
- u32 cmp = new_timeout * HZ;
- u32 state, val;
+ int max_to = WTCOMP2SEC((u32)-1);
+ if (new_timeout < 0 || new_timeout > max_to) {
+ printk(KERN_ERR KBUILD_MODNAME
+ ": timeout value must be between 0 and %d",
+ max_to);
+ return -EINVAL;
+ }
timeout = new_timeout;
- /*
- * store and disable WTC
- */
- state = (u32)(readl(&wdt_reg->wtc) & RC32434_WTC_EN);
- val = ~RC32434_WTC_EN;
- writel(readl(&wdt_reg->wtc) & val, &wdt_reg->wtc);
-
- writel(0, &wdt_reg->wtcount);
- writel(cmp, &wdt_reg->wtcompare);
-
- /*
- * restore WTC
- */
-
- writel(readl(&wdt_reg->wtc) | state, &wdt_reg);
-}
+ writel(SEC2WTCOMP(timeout), &wdt_reg->wtcompare);
-static void rc32434_wdt_reset(void)
-{
- ticks = rc32434_wdt_device.default_ticks;
+ return 0;
}
-static void rc32434_wdt_update(unsigned long unused)
+static void rc32434_wdt_ping(void)
{
- if (rc32434_wdt_device.running)
- ticks--;
-
writel(0, &wdt_reg->wtcount);
-
- if (rc32434_wdt_device.queue && ticks)
- mod_timer(&rc32434_wdt_device.timer,
- jiffies + RC32434_WDT_INTERVAL);
- else
- complete(&rc32434_wdt_device.stop);
}
static int rc32434_wdt_open(struct inode *inode, struct file *file)
@@ -142,19 +127,23 @@ static int rc32434_wdt_open(struct inode *inode, struct file *file)
if (nowayout)
__module_get(THIS_MODULE);
+ rc32434_wdt_start();
+ rc32434_wdt_ping();
+
return nonseekable_open(inode, file);
}
static int rc32434_wdt_release(struct inode *inode, struct file *file)
{
- if (expect_close && nowayout == 0) {
+ if (expect_close == 42) {
rc32434_wdt_stop();
printk(KERN_INFO KBUILD_MODNAME ": disabling watchdog timer\n");
module_put(THIS_MODULE);
- } else
+ } else {
printk(KERN_CRIT KBUILD_MODNAME
": device closed unexpectedly. WDT will not stop !\n");
-
+ rc32434_wdt_ping();
+ }
clear_bit(0, &rc32434_wdt_device.inuse);
return 0;
}
@@ -174,10 +163,10 @@ static ssize_t rc32434_wdt_write(struct file *file, const char *data,
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
- expect_close = 1;
+ expect_close = 42;
}
}
- rc32434_wdt_update(0);
+ rc32434_wdt_ping();
return len;
}
return 0;
@@ -197,11 +186,11 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
};
switch (cmd) {
case WDIOC_KEEPALIVE:
- rc32434_wdt_reset();
+ rc32434_wdt_ping();
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
- value = readl(&wdt_reg->wtcount);
+ value = 0;
if (copy_to_user(argp, &value, sizeof(int)))
return -EFAULT;
break;
@@ -218,6 +207,7 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
break;
case WDIOS_DISABLECARD:
rc32434_wdt_stop();
+ break;
default:
return -EINVAL;
}
@@ -225,11 +215,9 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
case WDIOC_SETTIMEOUT:
if (copy_from_user(&new_timeout, argp, sizeof(int)))
return -EFAULT;
- if (new_timeout < 1)
+ if (rc32434_wdt_set(new_timeout))
return -EINVAL;
- if (new_timeout > MAX_TIMEOUT)
- return -EINVAL;
- rc32434_wdt_set(new_timeout);
+ /* Fall through */
case WDIOC_GETTIMEOUT:
return copy_to_user(argp, &timeout, sizeof(int));
default:
@@ -254,15 +242,15 @@ static struct miscdevice rc32434_wdt_miscdev = {
.fops = &rc32434_wdt_fops,
};
-static char banner[] = KERN_INFO KBUILD_MODNAME
+static char banner[] __devinitdata = KERN_INFO KBUILD_MODNAME
": Watchdog Timer version " VERSION ", timer margin: %d sec\n";
-static int rc32434_wdt_probe(struct platform_device *pdev)
+static int __devinit rc32434_wdt_probe(struct platform_device *pdev)
{
int ret;
struct resource *r;
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb500_wdt_res");
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb532_wdt_res");
if (!r) {
printk(KERN_ERR KBUILD_MODNAME
"failed to retrieve resources\n");
@@ -277,24 +265,12 @@ static int rc32434_wdt_probe(struct platform_device *pdev)
}
ret = misc_register(&rc32434_wdt_miscdev);
-
if (ret < 0) {
printk(KERN_ERR KBUILD_MODNAME
"failed to register watchdog device\n");
goto unmap;
}
- init_completion(&rc32434_wdt_device.stop);
- rc32434_wdt_device.queue = 0;
-
- clear_bit(0, &rc32434_wdt_device.inuse);
-
- setup_timer(&rc32434_wdt_device.timer, rc32434_wdt_update, 0L);
-
- rc32434_wdt_device.default_ticks = ticks;
-
- rc32434_wdt_start();
-
printk(banner, timeout);
return 0;
@@ -304,23 +280,17 @@ unmap:
return ret;
}
-static int rc32434_wdt_remove(struct platform_device *pdev)
+static int __devexit rc32434_wdt_remove(struct platform_device *pdev)
{
- if (rc32434_wdt_device.queue) {
- rc32434_wdt_device.queue = 0;
- wait_for_completion(&rc32434_wdt_device.stop);
- }
misc_deregister(&rc32434_wdt_miscdev);
-
iounmap(wdt_reg);
-
return 0;
}
static struct platform_driver rc32434_wdt = {
.probe = rc32434_wdt_probe,
- .remove = rc32434_wdt_remove,
- .driver = {
+ .remove = __devexit_p(rc32434_wdt_remove),
+ .driver = {
.name = "rc32434_wdt",
}
};