From patchwork Fri Aug 3 01:26:36 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ike Panhc X-Patchwork-Id: 174834 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id 05D472C0095 for ; Fri, 3 Aug 2012 11:26:51 +1000 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1Sx6f6-0001dq-Ob; Fri, 03 Aug 2012 01:26:44 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1Sx6f4-0001dg-D3 for kernel-team@lists.ubuntu.com; Fri, 03 Aug 2012 01:26:42 +0000 Received: from 220-134-16-35.hinet-ip.hinet.net ([220.134.16.35] helo=canonical.com) by youngberry.canonical.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1Sx6f3-0006eQ-B8 for kernel-team@lists.ubuntu.com; Fri, 03 Aug 2012 01:26:42 +0000 From: Ike Panhc To: kernel-team@lists.ubuntu.com Subject: [PATCH 13/14] UBUNTU: SAUCE: ahci_platform: add custom hard reset for Calxeda ahci ctrlr Date: Fri, 3 Aug 2012 09:26:36 +0800 Message-Id: <1343957196-5703-1-git-send-email-ike.pan@canonical.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1343956968-5248-1-git-send-email-ike.pan@canonical.com> References: <1343956968-5248-1-git-send-email-ike.pan@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.13 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com From: Rob Herring BugLink: http://launchpad.net/bugs/1008345 Calxeda highbank SATA phy has intermittent problems bringing up a link with Gen3 drives. Retrying the phy hard reset can work-around this issue. Signed-off-by: Rob Herring Signed-off-by: Ike Panhc --- drivers/ata/ahci_platform.c | 74 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 9e419e1..9a155ba 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ enum ahci_type { AHCI, /* standard platform ahci */ IMX53_AHCI, /* ahci on i.mx53 */ STRICT_AHCI, /* delayed DMA engine start */ + CALXEDA_AHCI, }; static struct platform_device_id ahci_devtype[] = { @@ -45,6 +47,50 @@ static struct platform_device_id ahci_devtype[] = { }; MODULE_DEVICE_TABLE(platform, ahci_devtype); +static int ahci_calxeda_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + struct ata_port *ap = link->ap; + struct ahci_port_priv *pp = ap->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + struct ata_taskfile tf; + bool online; + u32 sstatus; + int rc; + int retry = 10; + + ahci_stop_engine(ap); + + /* clear D2H reception area to properly wait for D2H FIS */ + ata_tf_init(link->device, &tf); + tf.command = 0x80; + ata_tf_to_fis(&tf, 0, 0, d2h_fis); + + do { + rc = sata_link_hardreset(link, timing, deadline, &online, NULL); + + /* If the status is 1, we are connected, but the link did not + * come up. So retry resetting the link again. + */ + if (sata_scr_read(link, SCR_STATUS, &sstatus)) + break; + if (!(sstatus & 0x3)) + break; + } while (!online && retry--); + + ahci_start_engine(ap); + + if (online) + *class = ahci_dev_classify(ap); + + return rc; +} + +static struct ata_port_operations ahci_calxeda_ops = { + .inherits = &ahci_ops, + .hardreset = ahci_calxeda_hardreset, +}; static const struct ata_port_info ahci_port_info[] = { /* by features */ @@ -67,27 +113,46 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [CALXEDA_AHCI] = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_calxeda_ops, + }, }; static struct scsi_host_template ahci_platform_sht = { AHCI_SHT("ahci_platform"), }; +static const struct of_device_id ahci_of_match[] = { + { .compatible = "calxeda,hb-ahci", .data = &ahci_port_info[CALXEDA_AHCI], }, + {}, +}; +MODULE_DEVICE_TABLE(of, ahci_of_match); + static int __init ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ahci_platform_data *pdata = dev_get_platdata(dev); const struct platform_device_id *id = platform_get_device_id(pdev); - struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0]; + struct ata_port_info pi; const struct ata_port_info *ppi[] = { &pi, NULL }; struct ahci_host_priv *hpriv; struct ata_host *host; struct resource *mem; + const struct of_device_id *match; int irq; int n_ports; int i; int rc; + match = of_match_device(ahci_of_match, dev); + if (match) + pi = *((struct ata_port_info *)match->data); + else + pi = ahci_port_info[id ? id->driver_data : 0]; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(dev, "no mmio space\n"); @@ -278,13 +343,6 @@ static struct dev_pm_ops ahci_pm_ops = { }; #endif -static const struct of_device_id ahci_of_match[] = { - { .compatible = "calxeda,hb-ahci", }, - { .compatible = "snps,spear-ahci", }, - {}, -}; -MODULE_DEVICE_TABLE(of, ahci_of_match); - static struct platform_driver ahci_driver = { .remove = __devexit_p(ahci_remove), .driver = {