summaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-core.c
diff options
context:
space:
mode:
authorTejun Heo2007-02-02 08:22:30 +0100
committerJeff Garzik2007-02-21 10:58:16 +0100
commit458337dbb120d33f326e2b19d54eca8cf179b5c0 (patch)
tree91bc5284430b5a8856ec1b2fd4c277c4eb3f8827 /drivers/ata/libata-core.c
parentlibata: PATA driver for Celleb (diff)
downloadkernel-qcow2-linux-458337dbb120d33f326e2b19d54eca8cf179b5c0.tar.gz
kernel-qcow2-linux-458337dbb120d33f326e2b19d54eca8cf179b5c0.tar.xz
kernel-qcow2-linux-458337dbb120d33f326e2b19d54eca8cf179b5c0.zip
libata: improve ata_down_xfermask_limit()
Make ata_down_xfermask_limit() accept @sel instead of @force_pio0. @sel selects how the xfermask limit will be adjusted. The following selectors are defined. * ATA_DNXFER_PIO : only speed down PIO * ATA_DNXFER_DMA : only speed down DMA, don't cause transfer mode change * ATA_DNXFER_40C : apply 40c cable limit * ATA_DNXFER_FORCE_PIO : force PIO * ATA_DNXFER_FORCE_PIO0 : force PIO0 (same as original with @force_pio0 == 1) * ATA_DNXFER_ANY : same as original with @force_pio0 == 0 Currently, only ANY and FORCE_PIO0 are used to maintain the original behavior. Other selectors will be used later to improve EH speed down sequence. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r--drivers/ata/libata-core.c105
1 files changed, 79 insertions, 26 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 9c54de5addff..249d487c091e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1780,6 +1780,7 @@ int ata_bus_probe(struct ata_port *ap)
int tries[ATA_MAX_DEVICES];
int i, rc, down_xfermask;
struct ata_device *dev;
+ int dnxfer_sel;
ata_port_probe(ap);
@@ -1861,13 +1862,15 @@ int ata_bus_probe(struct ata_port *ap)
/* fall through */
default:
tries[dev->devno]--;
- if (down_xfermask &&
- ata_down_xfermask_limit(dev, tries[dev->devno] == 1))
+ dnxfer_sel = ATA_DNXFER_ANY;
+ if (tries[dev->devno] == 1)
+ dnxfer_sel = ATA_DNXFER_FORCE_PIO0;
+ if (down_xfermask && ata_down_xfermask_limit(dev, dnxfer_sel))
tries[dev->devno] = 0;
}
if (!tries[dev->devno]) {
- ata_down_xfermask_limit(dev, 1);
+ ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0);
ata_dev_disable(dev);
}
@@ -2300,7 +2303,7 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
/**
* ata_down_xfermask_limit - adjust dev xfer masks downward
* @dev: Device to adjust xfer masks
- * @force_pio0: Force PIO0
+ * @sel: ATA_DNXFER_* selector
*
* Adjust xfer masks of @dev downward. Note that this function
* does not apply the change. Invoking ata_set_mode() afterwards
@@ -2312,37 +2315,87 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
* RETURNS:
* 0 on success, negative errno on failure
*/
-int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0)
+int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
{
- unsigned long xfer_mask;
- int highbit;
+ char buf[32];
+ unsigned int orig_mask, xfer_mask;
+ unsigned int pio_mask, mwdma_mask, udma_mask;
+ int quiet, highbit;
- xfer_mask = ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask,
- dev->udma_mask);
+ quiet = !!(sel & ATA_DNXFER_QUIET);
+ sel &= ~ATA_DNXFER_QUIET;
- if (!xfer_mask)
- goto fail;
- /* don't gear down to MWDMA from UDMA, go directly to PIO */
- if (xfer_mask & ATA_MASK_UDMA)
- xfer_mask &= ~ATA_MASK_MWDMA;
+ xfer_mask = orig_mask = ata_pack_xfermask(dev->pio_mask,
+ dev->mwdma_mask,
+ dev->udma_mask);
+ ata_unpack_xfermask(xfer_mask, &pio_mask, &mwdma_mask, &udma_mask);
- highbit = fls(xfer_mask) - 1;
- xfer_mask &= ~(1 << highbit);
- if (force_pio0)
- xfer_mask &= 1 << ATA_SHIFT_PIO;
- if (!xfer_mask)
- goto fail;
+ switch (sel) {
+ case ATA_DNXFER_PIO:
+ highbit = fls(pio_mask) - 1;
+ pio_mask &= ~(1 << highbit);
+ break;
+
+ case ATA_DNXFER_DMA:
+ if (udma_mask) {
+ highbit = fls(udma_mask) - 1;
+ udma_mask &= ~(1 << highbit);
+ if (!udma_mask)
+ return -ENOENT;
+ } else if (mwdma_mask) {
+ highbit = fls(mwdma_mask) - 1;
+ mwdma_mask &= ~(1 << highbit);
+ if (!mwdma_mask)
+ return -ENOENT;
+ }
+ break;
+
+ case ATA_DNXFER_40C:
+ udma_mask &= ATA_UDMA_MASK_40C;
+ break;
+
+ case ATA_DNXFER_FORCE_PIO0:
+ pio_mask &= 1;
+ case ATA_DNXFER_FORCE_PIO:
+ mwdma_mask = 0;
+ udma_mask = 0;
+ break;
+
+ case ATA_DNXFER_ANY:
+ /* don't gear down to MWDMA from UDMA, go directly to PIO */
+ if (xfer_mask & ATA_MASK_UDMA)
+ xfer_mask &= ~ATA_MASK_MWDMA;
+
+ highbit = fls(xfer_mask) - 1;
+ xfer_mask &= ~(1 << highbit);
+ break;
+
+ default:
+ BUG();
+ }
+
+ xfer_mask &= ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
+
+ if (!(xfer_mask & ATA_MASK_PIO) || xfer_mask == orig_mask)
+ return -ENOENT;
+
+ if (!quiet) {
+ if (xfer_mask & (ATA_MASK_MWDMA | ATA_MASK_UDMA))
+ snprintf(buf, sizeof(buf), "%s:%s",
+ ata_mode_string(xfer_mask),
+ ata_mode_string(xfer_mask & ATA_MASK_PIO));
+ else
+ snprintf(buf, sizeof(buf), "%s",
+ ata_mode_string(xfer_mask));
+
+ ata_dev_printk(dev, KERN_WARNING,
+ "limiting speed to %s\n", buf);
+ }
ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask,
&dev->udma_mask);
- ata_dev_printk(dev, KERN_WARNING, "limiting speed to %s\n",
- ata_mode_string(xfer_mask));
-
return 0;
-
- fail:
- return -EINVAL;
}
static int ata_dev_set_mode(struct ata_device *dev)