From patchwork Tue Sep 4 11:08:40 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: shaohui xie X-Patchwork-Id: 181543 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id D5B092C0095 for ; Tue, 4 Sep 2012 21:41:44 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756773Ab2IDLlm (ORCPT ); Tue, 4 Sep 2012 07:41:42 -0400 Received: from db3ehsobe004.messaging.microsoft.com ([213.199.154.142]:13968 "EHLO db3outboundpool.messaging.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752375Ab2IDLll (ORCPT ); Tue, 4 Sep 2012 07:41:41 -0400 Received: from mail66-db3-R.bigfish.com (10.3.81.253) by DB3EHSOBE001.bigfish.com (10.3.84.21) with Microsoft SMTP Server id 14.1.225.23; Tue, 4 Sep 2012 11:41:39 +0000 Received: from mail66-db3 (localhost [127.0.0.1]) by mail66-db3-R.bigfish.com (Postfix) with ESMTP id BF92F2E0179; Tue, 4 Sep 2012 11:41:39 +0000 (UTC) X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPV:NLI; H:mail.freescale.net; RD:none; EFVD:NLI X-SpamScore: 0 X-BigFish: VS0(zzzz1202hzz8275bhz2dh2a8h668h839he5bhf0ah107ah1155h) Received: from mail66-db3 (localhost.localdomain [127.0.0.1]) by mail66-db3 (MessageSwitch) id 1346758897927553_787; Tue, 4 Sep 2012 11:41:37 +0000 (UTC) Received: from DB3EHSMHS003.bigfish.com (unknown [10.3.81.238]) by mail66-db3.bigfish.com (Postfix) with ESMTP id DF5CD4E0164; Tue, 4 Sep 2012 11:41:37 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by DB3EHSMHS003.bigfish.com (10.3.87.103) with Microsoft SMTP Server (TLS) id 14.1.225.23; Tue, 4 Sep 2012 11:41:34 +0000 Received: from az84smr01.freescale.net (10.64.34.197) by 039-SN1MMR1-005.039d.mgd.msft.net (10.84.1.17) with Microsoft SMTP Server (TLS) id 14.2.309.3; Tue, 4 Sep 2012 06:41:33 -0500 Received: from localhost.localdomain (rock.ap.freescale.net [10.193.20.106]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id q84BfNIQ027417; Tue, 4 Sep 2012 04:41:28 -0700 From: Shaohui Xie To: , CC: , , Shaohui Xie , Anju Bhartiya Subject: [PATCH] sata_fsl: add workaround for data length mismatch on freescale V2 controller Date: Tue, 4 Sep 2012 19:08:40 +0800 Message-ID: <1346756920-19128-1-git-send-email-Shaohui.Xie@freescale.com> X-Mailer: git-send-email 1.6.4 MIME-Version: 1.0 X-OriginatorOrg: freescale.com Sender: linux-ide-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ide@vger.kernel.org The freescale V2 SATA controller checks if the received data length matches the programmed length 'ttl', if not, it assumes that this is an error. In ATAPI, the 'ttl' is based on max allocation length and not the actual data transfer length, controller will raise 'DLM' (Data length Mismatch) error bit in Hstatus register. Along with 'DLM', DE (Device error) and FE (fatal Error) bits are also set in Hstatus register, 'E' (Internal Error) bit is set in Serror register and CE (Command Error) and DE (Device error) registers have the corresponding bit set. In this condition, we need to clear errors in following way: in the service routine, based on 'DLM' flag, HCONTROL[27] operation clears Hstatus, CE and DE registers, clear Serror register. Signed-off-by: Shaohui Xie Signed-off-by: Anju Bhartiya --- drivers/ata/sata_fsl.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index d6577b9..00a00cc 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -143,6 +143,7 @@ enum { FATAL_ERR_CRC_ERR_RX | FATAL_ERR_FIFO_OVRFL_TX | FATAL_ERR_FIFO_OVRFL_RX, + INT_ON_DATA_LENGTH_MISMATCH = (1 << 12), INT_ON_FATAL_ERR = (1 << 5), INT_ON_PHYRDY_CHG = (1 << 4), @@ -283,6 +284,8 @@ struct sata_fsl_host_priv { int irq; int data_snoop; struct device_attribute intr_coalescing; + u32 quirks; +#define SATA_FSL_QUIRK_V2_ERRATA (1 << 1) }; static void fsl_sata_set_irq_coalescing(struct ata_host *host, @@ -1180,26 +1183,58 @@ static void sata_fsl_host_intr(struct ata_port *ap) void __iomem *hcr_base = host_priv->hcr_base; u32 hstatus, done_mask = 0; struct ata_queued_cmd *qc; - u32 SError; + u32 SError, tag, atapi_flag = 0; + u32 status_mask = INT_ON_ERROR; hstatus = ioread32(hcr_base + HSTATUS); sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError); + /* Read command completed register */ + done_mask = ioread32(hcr_base + CC); + + if (host_priv->quirks & SATA_FSL_QUIRK_V2_ERRATA) { + if (unlikely(hstatus & INT_ON_DATA_LENGTH_MISMATCH)) { + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + qc = ata_qc_from_tag(ap, tag); + if (qc && ata_is_atapi(qc->tf.protocol)) { + atapi_flag = 1; + break; + } + } + } + } + + /* Workaround for data length mismatch errata */ + if (atapi_flag) { + u32 Hcontrol; +#define HCONTROL_CLEAR_ERROR (1 << 27) + /* Set HControl[27] to clear error registers */ + Hcontrol = ioread32(hcr_base + HCONTROL); + iowrite32(Hcontrol | HCONTROL_CLEAR_ERROR, hcr_base + HCONTROL); + + /* Clear HControl[27] */ + iowrite32(Hcontrol & (~HCONTROL_CLEAR_ERROR), + hcr_base + HCONTROL); + + /* Clear SError[E] bit */ + sata_fsl_scr_write(&ap->link, SCR_ERROR, SError); + + /* Ignore fatal error and device error */ + status_mask &= ~(INT_ON_SINGL_DEVICE_ERR | INT_ON_FATAL_ERR); + } + if (unlikely(SError & 0xFFFF0000)) { DPRINTK("serror @host_intr : 0x%x\n", SError); sata_fsl_error_intr(ap); } - if (unlikely(hstatus & INT_ON_ERROR)) { + if (unlikely(hstatus & status_mask)) { DPRINTK("error interrupt!!\n"); sata_fsl_error_intr(ap); return; } - /* Read command completed register */ - done_mask = ioread32(hcr_base + CC); - VPRINTK("Status of all queues :\n"); VPRINTK("done_mask/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n", done_mask, @@ -1437,6 +1472,9 @@ static int sata_fsl_probe(struct platform_device *ofdev) else host_priv->data_snoop = DATA_SNOOP_ENABLE_V1; + if (of_device_is_compatible(ofdev->dev.of_node, "fsl,pq-sata-v2")) + host_priv->quirks |= SATA_FSL_QUIRK_V2_ERRATA; + /* allocate host structure */ host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_FSL_MAX_PORTS); if (!host) {