summaryrefslogtreecommitdiffstats
path: root/drivers/ata/pata_cmd64x.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-22 20:22:30 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-22 20:22:30 -0700
commit90597b6cfc1fc9926a4d54f09bbf5b3254b1b028 (patch)
tree36e4f213e15dcc85620c7e0ccca42883d412fb8e /drivers/ata/pata_cmd64x.c
parent7bfe0e66d5da32961f0060fc5d96b739b1ed64b9 (diff)
parentb8cec3c253a2a001e463c43260fb75fb3223a04d (diff)
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev
Pull libata updates from Jeff Garzik: 1) AHCI regression fix. A recent "make driver conform to spec" change broke on deployed hardware. Make new behavior optional, rather than default, turning it on only for specific embedded platforms that need this. Everybody else runs in the famous "non conformant but working" mode. 2) pata_cmd64x, pata_legacy cleanups 3) new Intel SATA PCI IDs 4) misc minor vendor feature additions * tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev: pata_cmd64x: implement sff_irq_check() method pata_cmd64x: implement sff_irq_clear() method pata_cmd64x: use interrupt status from MRDMODE register pata_cmd64x: turn string of *if* statements into *switch* drivers/ata/pata_mpc52xx.c: clean up error handling code ahci_platform: add STRICT_AHCI platform type ahci: move AHCI_HFLAGS() macro to ahci.h ahci: add AHCI_HFLAG_DELAY_ENGINE host flag sata_fsl: add support for interrupt coalsecing feature ata/pata_arasan_cf: Add Hibernation support pata_legacy: correctly mask recovery field for HT6560B ata_piix: IDE-mode SATA patch for Intel Lynx Point DeviceIDs ahci: AHCI-mode SATA patch for Intel Lynx Point DeviceIDs
Diffstat (limited to 'drivers/ata/pata_cmd64x.c')
-rw-r--r--drivers/ata/pata_cmd64x.c147
1 files changed, 116 insertions, 31 deletions
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index e1fb39a74ce1..1c17cd1e8b2d 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -3,6 +3,7 @@
* (C) 2005 Red Hat Inc
* Alan Cox <alan@lxorguk.ukuu.org.uk>
* (C) 2009-2010 Bartlomiej Zolnierkiewicz
+ * (C) 2012 MontaVista Software, LLC <source@mvista.com>
*
* Based upon
* linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002
@@ -32,7 +33,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_cmd64x"
-#define DRV_VERSION "0.2.5"
+#define DRV_VERSION "0.2.18"
/*
* CMD64x specific registers definition.
@@ -229,28 +230,85 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
}
/**
- * cmd648_dma_stop - DMA stop callback
- * @qc: Command in progress
+ * cmd64x_sff_irq_check - check IDE interrupt
+ * @ap: ATA interface
*
- * DMA has completed.
+ * Check IDE interrupt in CFR/ARTTIM23 registers.
*/
-static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
+static bool cmd64x_sff_irq_check(struct ata_port *ap)
{
- struct ata_port *ap = qc->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 dma_intr;
- int dma_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
- int dma_reg = ap->port_no ? ARTTIM23 : CFR;
+ int irq_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+ int irq_reg = ap->port_no ? ARTTIM23 : CFR;
+ u8 irq_stat;
- ata_bmdma_stop(qc);
+ /* NOTE: reading the register should clear the interrupt */
+ pci_read_config_byte(pdev, irq_reg, &irq_stat);
+
+ return irq_stat & irq_mask;
+}
+
+/**
+ * cmd64x_sff_irq_clear - clear IDE interrupt
+ * @ap: ATA interface
+ *
+ * Clear IDE interrupt in CFR/ARTTIM23 and DMA status registers.
+ */
+
+static void cmd64x_sff_irq_clear(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int irq_reg = ap->port_no ? ARTTIM23 : CFR;
+ u8 irq_stat;
+
+ ata_bmdma_irq_clear(ap);
- pci_read_config_byte(pdev, dma_reg, &dma_intr);
- pci_write_config_byte(pdev, dma_reg, dma_intr | dma_mask);
+ /* Reading the register should be enough to clear the interrupt */
+ pci_read_config_byte(pdev, irq_reg, &irq_stat);
}
/**
- * cmd646r1_dma_stop - DMA stop callback
+ * cmd648_sff_irq_check - check IDE interrupt
+ * @ap: ATA interface
+ *
+ * Check IDE interrupt in MRDMODE register.
+ */
+
+static bool cmd648_sff_irq_check(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long base = pci_resource_start(pdev, 4);
+ int irq_mask = ap->port_no ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+ u8 mrdmode = inb(base + 1);
+
+ return mrdmode & irq_mask;
+}
+
+/**
+ * cmd648_sff_irq_clear - clear IDE interrupt
+ * @ap: ATA interface
+ *
+ * Clear IDE interrupt in MRDMODE and DMA status registers.
+ */
+
+static void cmd648_sff_irq_clear(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long base = pci_resource_start(pdev, 4);
+ int irq_mask = ap->port_no ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+ u8 mrdmode;
+
+ ata_bmdma_irq_clear(ap);
+
+ /* Clear this port's interrupt bit (leaving the other port alone) */
+ mrdmode = inb(base + 1);
+ mrdmode &= ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1);
+ outb(mrdmode | irq_mask, base + 1);
+}
+
+/**
+ * cmd646r1_bmdma_stop - DMA stop callback
* @qc: Command in progress
*
* Stub for now while investigating the r1 quirk in the old driver.
@@ -273,18 +331,30 @@ static const struct ata_port_operations cmd64x_base_ops = {
static struct ata_port_operations cmd64x_port_ops = {
.inherits = &cmd64x_base_ops,
+ .sff_irq_check = cmd64x_sff_irq_check,
+ .sff_irq_clear = cmd64x_sff_irq_clear,
.cable_detect = ata_cable_40wire,
};
static struct ata_port_operations cmd646r1_port_ops = {
.inherits = &cmd64x_base_ops,
+ .sff_irq_check = cmd64x_sff_irq_check,
+ .sff_irq_clear = cmd64x_sff_irq_clear,
.bmdma_stop = cmd646r1_bmdma_stop,
.cable_detect = ata_cable_40wire,
};
+static struct ata_port_operations cmd646r3_port_ops = {
+ .inherits = &cmd64x_base_ops,
+ .sff_irq_check = cmd648_sff_irq_check,
+ .sff_irq_clear = cmd648_sff_irq_clear,
+ .cable_detect = ata_cable_40wire,
+};
+
static struct ata_port_operations cmd648_port_ops = {
.inherits = &cmd64x_base_ops,
- .bmdma_stop = cmd648_bmdma_stop,
+ .sff_irq_check = cmd648_sff_irq_check,
+ .sff_irq_clear = cmd648_sff_irq_clear,
.cable_detect = cmd648_cable_detect,
};
@@ -306,7 +376,7 @@ static void cmd64x_fixup(struct pci_dev *pdev)
static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
- static const struct ata_port_info cmd_info[6] = {
+ static const struct ata_port_info cmd_info[7] = {
{ /* CMD 643 - no UDMA */
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
@@ -319,12 +389,18 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
.mwdma_mask = ATA_MWDMA2,
.port_ops = &cmd64x_port_ops
},
- { /* CMD 646 with working UDMA */
+ { /* CMD 646U with broken UDMA */
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .port_ops = &cmd646r3_port_ops
+ },
+ { /* CMD 646U2 with working UDMA */
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA2,
- .port_ops = &cmd64x_port_ops
+ .port_ops = &cmd646r3_port_ops
},
{ /* CMD 646 rev 1 */
.flags = ATA_FLAG_SLAVE_POSS,
@@ -368,21 +444,30 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (id->driver_data == 0) /* 643 */
ata_pci_bmdma_clear_simplex(pdev);
- if (pdev->device == PCI_DEVICE_ID_CMD_646) {
- /* Does UDMA work ? */
- if (pdev->revision > 4) {
- ppi[0] = &cmd_info[2];
- ppi[1] = &cmd_info[2];
- }
- /* Early rev with other problems ? */
- else if (pdev->revision == 1) {
+ if (pdev->device == PCI_DEVICE_ID_CMD_646)
+ switch (pdev->revision) {
+ /* UDMA works since rev 5 */
+ default:
ppi[0] = &cmd_info[3];
ppi[1] = &cmd_info[3];
- }
- /* revs 1,2 have no CNTRL_CH0 */
- if (pdev->revision < 3)
+ break;
+ /* Interrupts in MRDMODE since rev 3 */
+ case 3:
+ case 4:
+ ppi[0] = &cmd_info[2];
+ ppi[1] = &cmd_info[2];
+ break;
+ /* Rev 1 with other problems? */
+ case 1:
+ ppi[0] = &cmd_info[4];
+ ppi[1] = &cmd_info[4];
+ /* FALL THRU */
+ /* Early revs have no CNTRL_CH0 */
+ case 2:
+ case 0:
cntrl_ch0_ok = 0;
- }
+ break;
+ }
cmd64x_fixup(pdev);
@@ -423,8 +508,8 @@ static int cmd64x_reinit_one(struct pci_dev *pdev)
static const struct pci_device_id cmd64x[] = {
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 4 },
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 5 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 5 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 6 },
{ },
};