From ea4ace66782fc35245133d2766f38d62827761cc Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Mon, 23 Jan 2012 16:27:30 -0800 Subject: ahci: AHCI-mode SATA patch for Intel Lynx Point DeviceIDs This patch adds the AHCI-mode SATA DeviceIDs for the Intel Lynx Point PCH. Signed-off-by: Seth Heasley Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index d07bf0366d99..fb659c844506 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -261,6 +261,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */ { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */ { PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */ + { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */ + { PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -- cgit v1.2.3 From 78140cfec503c60a178b11fbaae2fef63e9abdc0 Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Mon, 23 Jan 2012 16:29:50 -0800 Subject: ata_piix: IDE-mode SATA patch for Intel Lynx Point DeviceIDs This patch adds the IDE-mode SATA DeviceIDs for the Intel Lynx Point PCH. Signed-off-by: Seth Heasley Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index fdf27b9fce43..68013f96729f 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -321,6 +321,14 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (Panther Point) */ { 0x8086, 0x1e09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Lynx Point) */ + { 0x8086, 0x8c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Lynx Point) */ + { 0x8086, 0x8c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Lynx Point) */ + { 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Lynx Point) */ + { 0x8086, 0x8c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { } /* terminate list */ }; -- cgit v1.2.3 From 9716387311c790de381214c03e7f1b72b91a8189 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 19 Jan 2012 19:09:56 +0300 Subject: pata_legacy: correctly mask recovery field for HT6560B According to the HT6560H datasheet, the recovery timing field is 4-bit wide, with a value of 0 meaning 16 cycles. Correct obvious thinko in the recovery field mask. Signed-off-by: Sergei Shtylyov Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/pata_legacy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 35aca7d1a3eb..4fe9d2138d48 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -401,8 +401,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); active = clamp_val(t.active, 2, 15); - recover = clamp_val(t.recover, 2, 16); - recover &= 0x15; + recover = clamp_val(t.recover, 2, 16) & 0x0F; inb(0x3E6); inb(0x3E6); -- cgit v1.2.3 From 40679b3ce9d993e33e026f402cbfffb35d2c4e3c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 23 Feb 2012 15:03:53 +0530 Subject: ata/pata_arasan_cf: Add Hibernation support This patch adds in Hibernation related callbacks. Also we don't really need to free DMA channel on suspend. Signed-off-by: Viresh Kumar Signed-off-by: Jeff Garzik --- drivers/ata/pata_arasan_cf.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 048589fad2ca..fc2db2a89a6b 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -925,11 +925,10 @@ static int arasan_cf_suspend(struct device *dev) struct ata_host *host = dev_get_drvdata(dev); struct arasan_cf_dev *acdev = host->ports[0]->private_data; - if (acdev->dma_chan) { + if (acdev->dma_chan) acdev->dma_chan->device->device_control(acdev->dma_chan, DMA_TERMINATE_ALL, 0); - dma_release_channel(acdev->dma_chan); - } + cf_exit(acdev); return ata_host_suspend(host, PMSG_SUSPEND); } @@ -945,10 +944,7 @@ static int arasan_cf_resume(struct device *dev) return 0; } -static const struct dev_pm_ops arasan_cf_pm_ops = { - .suspend = arasan_cf_suspend, - .resume = arasan_cf_resume, -}; +static SIMPLE_DEV_PM_OPS(arasan_cf_pm_ops, arasan_cf_suspend, arasan_cf_resume); #endif static struct platform_driver arasan_cf_driver = { @@ -958,7 +954,7 @@ static struct platform_driver arasan_cf_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, #ifdef CONFIG_PM - .pm = &arasan_cf_pm_ops, + .pm = &arasan_cf_pm_ops, #endif }, }; -- cgit v1.2.3 From 6b4b8fc87dc5cbfcfb5c749dc200906471fb854c Mon Sep 17 00:00:00 2001 From: Qiang Liu Date: Wed, 15 Feb 2012 15:40:34 +0800 Subject: sata_fsl: add support for interrupt coalsecing feature Adds support for interrupt coalescing feature to reduce interrupt events. Provides a mechanism of adjusting coalescing count and timeout tick by sysfs at runtime, so that tradeoff of latency and CPU load can be made depending on different applications. Signed-off-by: Qiang Liu Signed-off-by: Jeff Garzik --- drivers/ata/sata_fsl.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 4 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 0120b0d1e9a5..d6577b93bee3 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -6,7 +6,7 @@ * Author: Ashish Kalra * Li Yang * - * Copyright (c) 2006-2007, 2011 Freescale Semiconductor, Inc. + * Copyright (c) 2006-2007, 2011-2012 Freescale Semiconductor, Inc. * * 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 @@ -26,6 +26,15 @@ #include #include +static unsigned int intr_coalescing_count; +module_param(intr_coalescing_count, int, S_IRUGO); +MODULE_PARM_DESC(intr_coalescing_count, + "INT coalescing count threshold (1..31)"); + +static unsigned int intr_coalescing_ticks; +module_param(intr_coalescing_ticks, int, S_IRUGO); +MODULE_PARM_DESC(intr_coalescing_ticks, + "INT coalescing timer threshold in AHB ticks"); /* Controller information */ enum { SATA_FSL_QUEUE_DEPTH = 16, @@ -82,6 +91,16 @@ enum { SATA_FSL_IRQ_FLAG = IRQF_SHARED, }; +/* + * Interrupt Coalescing Control Register bitdefs */ +enum { + ICC_MIN_INT_COUNT_THRESHOLD = 1, + ICC_MAX_INT_COUNT_THRESHOLD = ((1 << 5) - 1), + ICC_MIN_INT_TICKS_THRESHOLD = 0, + ICC_MAX_INT_TICKS_THRESHOLD = ((1 << 19) - 1), + ICC_SAFE_INT_TICKS = 1, +}; + /* * Host Controller command register set - per port */ @@ -263,8 +282,65 @@ struct sata_fsl_host_priv { void __iomem *csr_base; int irq; int data_snoop; + struct device_attribute intr_coalescing; }; +static void fsl_sata_set_irq_coalescing(struct ata_host *host, + unsigned int count, unsigned int ticks) +{ + struct sata_fsl_host_priv *host_priv = host->private_data; + void __iomem *hcr_base = host_priv->hcr_base; + + if (count > ICC_MAX_INT_COUNT_THRESHOLD) + count = ICC_MAX_INT_COUNT_THRESHOLD; + else if (count < ICC_MIN_INT_COUNT_THRESHOLD) + count = ICC_MIN_INT_COUNT_THRESHOLD; + + if (ticks > ICC_MAX_INT_TICKS_THRESHOLD) + ticks = ICC_MAX_INT_TICKS_THRESHOLD; + else if ((ICC_MIN_INT_TICKS_THRESHOLD == ticks) && + (count > ICC_MIN_INT_COUNT_THRESHOLD)) + ticks = ICC_SAFE_INT_TICKS; + + spin_lock(&host->lock); + iowrite32((count << 24 | ticks), hcr_base + ICC); + + intr_coalescing_count = count; + intr_coalescing_ticks = ticks; + spin_unlock(&host->lock); + + DPRINTK("intrrupt coalescing, count = 0x%x, ticks = %x\n", + intr_coalescing_count, intr_coalescing_ticks); + DPRINTK("ICC register status: (hcr base: 0x%x) = 0x%x\n", + hcr_base, ioread32(hcr_base + ICC)); +} + +static ssize_t fsl_sata_intr_coalescing_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d %d\n", + intr_coalescing_count, intr_coalescing_ticks); +} + +static ssize_t fsl_sata_intr_coalescing_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int coalescing_count, coalescing_ticks; + + if (sscanf(buf, "%d%d", + &coalescing_count, + &coalescing_ticks) != 2) { + printk(KERN_ERR "fsl-sata: wrong parameter format.\n"); + return -EINVAL; + } + + fsl_sata_set_irq_coalescing(dev_get_drvdata(dev), + coalescing_count, coalescing_ticks); + + return strlen(buf); +} + static inline unsigned int sata_fsl_tag(unsigned int tag, void __iomem *hcr_base) { @@ -346,10 +422,10 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc, (unsigned long long)sg_addr, sg_len); /* warn if each s/g element is not dword aligned */ - if (sg_addr & 0x03) + if (unlikely(sg_addr & 0x03)) ata_port_err(qc->ap, "s/g addr unaligned : 0x%llx\n", (unsigned long long)sg_addr); - if (sg_len & 0x03) + if (unlikely(sg_len & 0x03)) ata_port_err(qc->ap, "s/g len unaligned : 0x%x\n", sg_len); @@ -1245,6 +1321,13 @@ static int sata_fsl_init_controller(struct ata_host *host) iowrite32(0x00000FFFF, hcr_base + CE); iowrite32(0x00000FFFF, hcr_base + DE); + /* + * reset the number of command complete bits which will cause the + * interrupt to be signaled + */ + fsl_sata_set_irq_coalescing(host, intr_coalescing_count, + intr_coalescing_ticks); + /* * host controller will be brought on-line, during xx_port_start() * callback, that should also initiate the OOB, COMINIT sequence @@ -1309,7 +1392,7 @@ static int sata_fsl_probe(struct platform_device *ofdev) void __iomem *csr_base = NULL; struct sata_fsl_host_priv *host_priv = NULL; int irq; - struct ata_host *host; + struct ata_host *host = NULL; u32 temp; struct ata_port_info pi = sata_fsl_port_info[0]; @@ -1356,6 +1439,10 @@ static int sata_fsl_probe(struct platform_device *ofdev) /* allocate host structure */ host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_FSL_MAX_PORTS); + if (!host) { + retval = -ENOMEM; + goto error_exit_with_cleanup; + } /* host->iomap is not used currently */ host->private_data = host_priv; @@ -1373,10 +1460,24 @@ static int sata_fsl_probe(struct platform_device *ofdev) dev_set_drvdata(&ofdev->dev, host); + host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show; + host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store; + sysfs_attr_init(&host_priv->intr_coalescing.attr); + host_priv->intr_coalescing.attr.name = "intr_coalescing"; + host_priv->intr_coalescing.attr.mode = S_IRUGO | S_IWUSR; + retval = device_create_file(host->dev, &host_priv->intr_coalescing); + if (retval) + goto error_exit_with_cleanup; + return 0; error_exit_with_cleanup: + if (host) { + dev_set_drvdata(&ofdev->dev, NULL); + ata_host_detach(host); + } + if (hcr_base) iounmap(hcr_base); if (host_priv) @@ -1390,6 +1491,8 @@ static int sata_fsl_remove(struct platform_device *ofdev) struct ata_host *host = dev_get_drvdata(&ofdev->dev); struct sata_fsl_host_priv *host_priv = host->private_data; + device_remove_file(&ofdev->dev, &host_priv->intr_coalescing); + ata_host_detach(host); dev_set_drvdata(&ofdev->dev, NULL); -- cgit v1.2.3 From 66583c9fa63d05d5580e409f9a58d3cad6d76d17 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 21 Feb 2012 10:38:42 -0800 Subject: ahci: add AHCI_HFLAG_DELAY_ENGINE host flag The following commit was intended to fix problems with specific AHCI controller(s) that would become bricks if the AHCI specification was not followed strictly (that is, if ahci_start_engine() was called while the controller was in the wrong state): commit 7faa33da9b7add01db9f1ad92c6a5d9145e940a7 ahci: start engine only during soft/hard resets However, some devices currently have issues with that fix, so we must implement a flag that delays the ahci_start_engine() call only for specific controllers. This commit simply introduces the flag, without enabling it in any driver. Note that even when AHCI_HFLAG_DELAY_ENGINE is not enabled, this patch does not constitue a full revert to commit 7faa33da; there is still a change in behavior to the ahci_port_suspend() failure path. Signed-off-by: Brian Norris Signed-off-by: Jeff Garzik Cc: stable@kernel.org --- drivers/ata/ahci.h | 3 +++ drivers/ata/libahci.c | 5 +++++ 2 files changed, 8 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index b1750007c8dc..feb127ef4e4e 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -210,6 +210,9 @@ enum { AHCI_HFLAG_NO_SNTF = (1 << 12), /* no sntf */ AHCI_HFLAG_NO_FPDMA_AA = (1 << 13), /* no FPDMA AA */ AHCI_HFLAG_YES_FBS = (1 << 14), /* force FBS cap on */ + AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on + port start (wait until + error-handling stage) */ /* ap->flags bits */ diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index a72bfd0ecfee..f9eaa82311a9 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -737,6 +737,7 @@ static void ahci_power_down(struct ata_port *ap) static void ahci_start_port(struct ata_port *ap) { + struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; struct ata_link *link; struct ahci_em_priv *emp; @@ -746,6 +747,10 @@ static void ahci_start_port(struct ata_port *ap) /* enable FIS reception */ ahci_start_fis_rx(ap); + /* enable DMA */ + if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE)) + ahci_start_engine(ap); + /* turn on LEDs */ if (ap->flags & ATA_FLAG_EM) { ata_for_each_link(link, ap, EDGE) { -- cgit v1.2.3 From 55d5ec316627b64c3764e4c1b4b8e1988e272c1f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 21 Feb 2012 10:38:43 -0800 Subject: ahci: move AHCI_HFLAGS() macro to ahci.h We will need this macro in both ahci.c and ahci_platform.c, so just move it to the header. Signed-off-by: Brian Norris Signed-off-by: Jeff Garzik Cc: stable@kernel.org --- drivers/ata/ahci.c | 2 -- drivers/ata/ahci.h | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index fb659c844506..79a1e9dd56d9 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -103,8 +103,6 @@ static struct ata_port_operations ahci_p5wdh_ops = { .hardreset = ahci_p5wdh_hardreset, }; -#define AHCI_HFLAGS(flags) .private_data = (void *)(flags) - static const struct ata_port_info ahci_port_info[] = { /* by features */ [board_ahci] = diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index feb127ef4e4e..c2594ddf25b0 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -195,6 +195,9 @@ enum { PORT_FBS_EN = (1 << 0), /* Enable FBS */ /* hpriv->flags bits */ + +#define AHCI_HFLAGS(flags) .private_data = (void *)(flags) + AHCI_HFLAG_NO_NCQ = (1 << 0), AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ -- cgit v1.2.3 From d408e2b14fba4fa214fa5bc24b7baae8a55e563c Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 21 Feb 2012 10:38:44 -0800 Subject: ahci_platform: add STRICT_AHCI platform type Some platforms need to make use of the AHCI_HFLAG_DELAY_ENGINE flag. Signed-off-by: Brian Norris Signed-off-by: Jeff Garzik Cc: stable@kernel.org --- drivers/ata/ahci_platform.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/ata') diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 48be4e189163..0c86c77764bc 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -26,6 +26,7 @@ enum ahci_type { AHCI, /* standard platform ahci */ IMX53_AHCI, /* ahci on i.mx53 */ + STRICT_AHCI, /* delayed DMA engine start */ }; static struct platform_device_id ahci_devtype[] = { @@ -35,6 +36,9 @@ static struct platform_device_id ahci_devtype[] = { }, { .name = "imx53-ahci", .driver_data = IMX53_AHCI, + }, { + .name = "strict-ahci", + .driver_data = STRICT_AHCI, }, { /* sentinel */ } @@ -56,6 +60,13 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_pmp_retry_srst_ops, }, + [STRICT_AHCI] = { + AHCI_HFLAGS (AHCI_HFLAG_DELAY_ENGINE), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, }; static struct scsi_host_template ahci_platform_sht = { -- cgit v1.2.3 From d01159dffa15e3a734e43cf58c5d9f04c4106d83 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 11 Mar 2012 21:12:09 +0100 Subject: drivers/ata/pata_mpc52xx.c: clean up error handling code This patch makes a number of changes with respect to the error-handling code: * Remove cleanup calls for the devm functions in both the error handling code and the remove function. This cleanup is done automatically. * The previous change simplifies the cleanup code at the end of the function such that there is nothing to do on the failure of the call to devm_ioremap. So it is changed to just return directly. * There is no need for the ifs in the cleanup code at the end of the function, because in each case the cleanup needed is statically known. Drop the ifs, add new err labels, and drop the initializations of the tested variables to NULL. * Change the call to request_irq to a call to devm_request_irq, so that it is cleaned up on exit. * Cause the return value of devm_request_irq to go into the returned variable rv rather than the unused variable ret. Drop ret. Signed-off-by: Julia Lawall Signed-off-by: Jeff Garzik --- drivers/ata/pata_mpc52xx.c | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 00748ae1a016..d2c102fd4330 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -687,11 +687,11 @@ mpc52xx_ata_probe(struct platform_device *op) int ata_irq = 0; struct mpc52xx_ata __iomem *ata_regs; struct mpc52xx_ata_priv *priv = NULL; - int rv, ret, task_irq = 0; + int rv, task_irq; int mwdma_mask = 0, udma_mask = 0; const __be32 *prop; int proplen; - struct bcom_task *dmatsk = NULL; + struct bcom_task *dmatsk; /* Get ipb frequency */ ipb_freq = mpc5xxx_get_bus_frequency(op->dev.of_node); @@ -717,8 +717,7 @@ mpc52xx_ata_probe(struct platform_device *op) ata_regs = devm_ioremap(&op->dev, res_mem.start, sizeof(*ata_regs)); if (!ata_regs) { dev_err(&op->dev, "error mapping device registers\n"); - rv = -ENOMEM; - goto err; + return -ENOMEM; } /* @@ -753,7 +752,7 @@ mpc52xx_ata_probe(struct platform_device *op) if (!priv) { dev_err(&op->dev, "error allocating private structure\n"); rv = -ENOMEM; - goto err; + goto err1; } priv->ipb_period = 1000000000 / (ipb_freq / 1000); @@ -776,15 +775,15 @@ mpc52xx_ata_probe(struct platform_device *op) if (!dmatsk) { dev_err(&op->dev, "bestcomm initialization failed\n"); rv = -ENOMEM; - goto err; + goto err1; } task_irq = bcom_get_task_irq(dmatsk); - ret = request_irq(task_irq, &mpc52xx_ata_task_irq, 0, + rv = devm_request_irq(&op->dev, task_irq, &mpc52xx_ata_task_irq, 0, "ATA task", priv); - if (ret) { + if (rv) { dev_err(&op->dev, "error requesting DMA IRQ\n"); - goto err; + goto err2; } priv->dmatsk = dmatsk; @@ -792,7 +791,7 @@ mpc52xx_ata_probe(struct platform_device *op) rv = mpc52xx_ata_hw_init(priv); if (rv) { dev_err(&op->dev, "error initializing hardware\n"); - goto err; + goto err2; } /* Register ourselves to libata */ @@ -800,23 +799,16 @@ mpc52xx_ata_probe(struct platform_device *op) mwdma_mask, udma_mask); if (rv) { dev_err(&op->dev, "error registering with ATA layer\n"); - goto err; + goto err2; } return 0; - err: - devm_release_mem_region(&op->dev, res_mem.start, sizeof(*ata_regs)); - if (ata_irq) - irq_dispose_mapping(ata_irq); - if (task_irq) - irq_dispose_mapping(task_irq); - if (dmatsk) - bcom_ata_release(dmatsk); - if (ata_regs) - devm_iounmap(&op->dev, ata_regs); - if (priv) - devm_kfree(&op->dev, priv); + err2: + irq_dispose_mapping(task_irq); + bcom_ata_release(dmatsk); + err1: + irq_dispose_mapping(ata_irq); return rv; } @@ -835,12 +827,6 @@ mpc52xx_ata_remove(struct platform_device *op) bcom_ata_release(priv->dmatsk); irq_dispose_mapping(priv->ata_irq); - /* Clear up IO allocations */ - devm_iounmap(&op->dev, priv->ata_regs); - devm_release_mem_region(&op->dev, priv->ata_regs_pa, - sizeof(*priv->ata_regs)); - devm_kfree(&op->dev, priv); - return 0; } -- cgit v1.2.3 From 8fcfa7bd1b77514cfdce77751c980460535f56b4 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 11 Mar 2012 22:29:02 +0300 Subject: pata_cmd64x: turn string of *if* statements into *switch* Convert string of the *if* statements all checking 'pdev->revision' into more natural *switch* statement. While at it, somewhat clarify the comments there... Increment the driver version, accounting for the patches that neglected to do this in the past. Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/pata_cmd64x.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index e1fb39a74ce1..028638c7c1d9 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -32,7 +32,7 @@ #include #define DRV_NAME "pata_cmd64x" -#define DRV_VERSION "0.2.5" +#define DRV_VERSION "0.2.15" /* * CMD64x specific registers definition. @@ -368,21 +368,27 @@ 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) { + if (pdev->device == PCI_DEVICE_ID_CMD_646) + switch (pdev->revision) { + /* UDMA works since rev 5 */ + default: ppi[0] = &cmd_info[2]; ppi[1] = &cmd_info[2]; - } - /* Early rev with other problems ? */ - else if (pdev->revision == 1) { + break; + case 3: + case 4: + break; + /* Rev 1 with other problems? */ + case 1: ppi[0] = &cmd_info[3]; ppi[1] = &cmd_info[3]; - } - /* revs 1,2 have no CNTRL_CH0 */ - if (pdev->revision < 3) + /* FALL THRU */ + /* Early revs have no CNTRL_CH0 */ + case 2: + case 0: cntrl_ch0_ok = 0; - } + break; + } cmd64x_fixup(pdev); -- cgit v1.2.3 From 8a686bc984454c1eba6788d0d97dec72ad87f052 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 11 Mar 2012 22:25:30 +0300 Subject: pata_cmd64x: use interrupt status from MRDMODE register Start using faster version of the bmdma_stop() method for the PCI0646U and newer chips that have the duplicate interrupt status bits in the I/O mapped MRDMODE register. Use the old, slow bmdma_stop() method on the older chips, taking into account that the interrupt bits are not coupled to DMA and that's enough to read the register to clear the interrupt (on the older chips). Determine what method to use at the driver load time. Fix kernel-doc of the bmdma_stop() methods, while at it. Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/pata_cmd64x.c | 73 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 17 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 028638c7c1d9..f0dcb7056b19 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -3,6 +3,7 @@ * (C) 2005 Red Hat Inc * Alan Cox * (C) 2009-2010 Bartlomiej Zolnierkiewicz + * (C) 2012 MontaVista Software, LLC * * Based upon * linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002 @@ -32,7 +33,7 @@ #include #define DRV_NAME "pata_cmd64x" -#define DRV_VERSION "0.2.15" +#define DRV_VERSION "0.2.16" /* * CMD64x specific registers definition. @@ -229,7 +230,27 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) } /** - * cmd648_dma_stop - DMA stop callback + * cmd64x_bmdma_stop - DMA stop callback + * @qc: Command in progress + * + * DMA has completed. + */ + +static void cmd64x_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + int irq_reg = ap->port_no ? ARTTIM23 : CFR; + u8 irq_stat; + + ata_bmdma_stop(qc); + + /* Reading the register should be enough to clear the interrupt */ + pci_read_config_byte(pdev, irq_reg, &irq_stat); +} + +/** + * cmd648_bmdma_stop - DMA stop callback * @qc: Command in progress * * DMA has completed. @@ -239,18 +260,20 @@ static void cmd648_bmdma_stop(struct ata_queued_cmd *qc) { 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; + unsigned long base = pci_resource_start(pdev, 4); + int irq_mask = ap->port_no ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; + u8 mrdmode; ata_bmdma_stop(qc); - pci_read_config_byte(pdev, dma_reg, &dma_intr); - pci_write_config_byte(pdev, dma_reg, dma_intr | dma_mask); + /* 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_dma_stop - DMA stop callback + * cmd646r1_bmdma_stop - DMA stop callback * @qc: Command in progress * * Stub for now while investigating the r1 quirk in the old driver. @@ -273,6 +296,7 @@ static const struct ata_port_operations cmd64x_base_ops = { static struct ata_port_operations cmd64x_port_ops = { .inherits = &cmd64x_base_ops, + .bmdma_stop = cmd64x_bmdma_stop, .cable_detect = ata_cable_40wire, }; @@ -282,6 +306,12 @@ static struct ata_port_operations cmd646r1_port_ops = { .cable_detect = ata_cable_40wire, }; +static struct ata_port_operations cmd646r3_port_ops = { + .inherits = &cmd64x_base_ops, + .bmdma_stop = cmd648_bmdma_stop, + .cable_detect = ata_cable_40wire, +}; + static struct ata_port_operations cmd648_port_ops = { .inherits = &cmd64x_base_ops, .bmdma_stop = cmd648_bmdma_stop, @@ -306,7 +336,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 +349,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, @@ -372,16 +408,19 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) switch (pdev->revision) { /* UDMA works since rev 5 */ default: - ppi[0] = &cmd_info[2]; - ppi[1] = &cmd_info[2]; + ppi[0] = &cmd_info[3]; + ppi[1] = &cmd_info[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[3]; - ppi[1] = &cmd_info[3]; + ppi[0] = &cmd_info[4]; + ppi[1] = &cmd_info[4]; /* FALL THRU */ /* Early revs have no CNTRL_CH0 */ case 2: @@ -429,8 +468,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 }, { }, }; -- cgit v1.2.3 From 419fd2461354f7675ef298fa26ffceff4d0b2168 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 11 Mar 2012 22:27:01 +0300 Subject: pata_cmd64x: implement sff_irq_clear() method Convert the driver's two bmdma_stop() methods into sff_irq_clear() methods -- they shouldn't have been bothering with clearing interrupts from the very start; the driver will now use the standard bmdma_stop() method implementation (where appropriate). Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/pata_cmd64x.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index f0dcb7056b19..d4f26a515ef8 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -33,7 +33,7 @@ #include #define DRV_NAME "pata_cmd64x" -#define DRV_VERSION "0.2.16" +#define DRV_VERSION "0.2.17" /* * CMD64x specific registers definition. @@ -230,41 +230,39 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) } /** - * cmd64x_bmdma_stop - DMA stop callback - * @qc: Command in progress + * cmd64x_sff_irq_clear - clear IDE interrupt + * @ap: ATA interface * - * DMA has completed. + * Clear IDE interrupt in CFR/ARTTIM23 and DMA status registers. */ -static void cmd64x_bmdma_stop(struct ata_queued_cmd *qc) +static void cmd64x_sff_irq_clear(struct ata_port *ap) { - struct ata_port *ap = qc->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); int irq_reg = ap->port_no ? ARTTIM23 : CFR; u8 irq_stat; - ata_bmdma_stop(qc); + ata_bmdma_irq_clear(ap); /* Reading the register should be enough to clear the interrupt */ pci_read_config_byte(pdev, irq_reg, &irq_stat); } /** - * cmd648_bmdma_stop - DMA stop callback - * @qc: Command in progress + * cmd648_sff_irq_clear - clear IDE interrupt + * @ap: ATA interface * - * DMA has completed. + * Clear IDE interrupt in MRDMODE and DMA status registers. */ -static void cmd648_bmdma_stop(struct ata_queued_cmd *qc) +static void cmd648_sff_irq_clear(struct ata_port *ap) { - struct ata_port *ap = qc->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_stop(qc); + ata_bmdma_irq_clear(ap); /* Clear this port's interrupt bit (leaving the other port alone) */ mrdmode = inb(base + 1); @@ -296,25 +294,26 @@ static const struct ata_port_operations cmd64x_base_ops = { static struct ata_port_operations cmd64x_port_ops = { .inherits = &cmd64x_base_ops, - .bmdma_stop = cmd64x_bmdma_stop, + .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_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, - .bmdma_stop = cmd648_bmdma_stop, + .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_clear = cmd648_sff_irq_clear, .cable_detect = cmd648_cable_detect, }; -- cgit v1.2.3 From b8cec3c253a2a001e463c43260fb75fb3223a04d Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 11 Mar 2012 22:28:18 +0300 Subject: pata_cmd64x: implement sff_irq_check() method Implement sff_irq_check() method for both old and new chips. Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/pata_cmd64x.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'drivers/ata') diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index d4f26a515ef8..1c17cd1e8b2d 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -33,7 +33,7 @@ #include #define DRV_NAME "pata_cmd64x" -#define DRV_VERSION "0.2.17" +#define DRV_VERSION "0.2.18" /* * CMD64x specific registers definition. @@ -229,6 +229,26 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) pci_write_config_byte(pdev, pciD, regD); } +/** + * cmd64x_sff_irq_check - check IDE interrupt + * @ap: ATA interface + * + * Check IDE interrupt in CFR/ARTTIM23 registers. + */ + +static bool cmd64x_sff_irq_check(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + int irq_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; + int irq_reg = ap->port_no ? ARTTIM23 : CFR; + u8 irq_stat; + + /* 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 @@ -248,6 +268,23 @@ static void cmd64x_sff_irq_clear(struct ata_port *ap) pci_read_config_byte(pdev, irq_reg, &irq_stat); } +/** + * 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 @@ -294,12 +331,14 @@ 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, @@ -307,12 +346,14 @@ static struct ata_port_operations cmd646r1_port_ops = { 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, + .sff_irq_check = cmd648_sff_irq_check, .sff_irq_clear = cmd648_sff_irq_clear, .cable_detect = cmd648_cable_detect, }; -- cgit v1.2.3