aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorSuman Tripathi <stripathi@apm.com>2015-01-06 05:02:16 -0500
committerTejun Heo <tj@kernel.org>2015-01-06 08:38:25 -0500
commita3a84bc7c885eee954f1971c43e36a3587fbf565 (patch)
tree716bfc911157bf8d68b32d74c883485f66afdfe9 /drivers/ata
parent1540035da71ea0feecdf24eeb98471ffa08da0d3 (diff)
ahci_xgene: Implement the workaround to support PMP enumeration and discovery.
Due to H/W errata, the controller is unable to save the PMP field fetched from command header before sending the H2D FIS. When the device returns the PMP port field in the D2H FIS, there is a mismatch and results in command completion failure. The workaround is to write the pmp value to PxFBS.DEV field before issuing any command to PMP. Signed-off-by: Suman Tripathi <stripathi@apm.com> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ahci_xgene.c133
1 files changed, 128 insertions, 5 deletions
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
index afa9c03ecfd6..7f6887535c1e 100644
--- a/drivers/ata/ahci_xgene.c
+++ b/drivers/ata/ahci_xgene.c
@@ -85,6 +85,7 @@ struct xgene_ahci_context {
85 struct ahci_host_priv *hpriv; 85 struct ahci_host_priv *hpriv;
86 struct device *dev; 86 struct device *dev;
87 u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/ 87 u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/
88 u32 class[MAX_AHCI_CHN_PERCTR]; /* tracking the class of device */
88 void __iomem *csr_core; /* Core CSR address of IP */ 89 void __iomem *csr_core; /* Core CSR address of IP */
89 void __iomem *csr_diag; /* Diag CSR address of IP */ 90 void __iomem *csr_diag; /* Diag CSR address of IP */
90 void __iomem *csr_axi; /* AXI CSR address of IP */ 91 void __iomem *csr_axi; /* AXI CSR address of IP */
@@ -177,11 +178,17 @@ static int xgene_ahci_restart_engine(struct ata_port *ap)
177 * xgene_ahci_qc_issue - Issue commands to the device 178 * xgene_ahci_qc_issue - Issue commands to the device
178 * @qc: Command to issue 179 * @qc: Command to issue
179 * 180 *
180 * Due to Hardware errata for IDENTIFY DEVICE command and PACKET 181 * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot
181 * command of ATAPI protocol set, the controller cannot clear the BSY bit 182 * clear the BSY bit after receiving the PIO setup FIS. This results in the dma
182 * after receiving the PIO setup FIS. This results in the DMA state machine 183 * state machine goes into the CMFatalErrorUpdate state and locks up. By
183 * going into the CMFatalErrorUpdate state and locks up. By restarting the 184 * restarting the dma engine, it removes the controller out of lock up state.
184 * DMA engine, it removes the controller out of lock up state. 185 *
186 * Due to H/W errata, the controller is unable to save the PMP
187 * field fetched from command header before sending the H2D FIS.
188 * When the device returns the PMP port field in the D2H FIS, there is
189 * a mismatch and results in command completion failure. The
190 * workaround is to write the pmp value to PxFBS.DEV field before issuing
191 * any command to PMP.
185 */ 192 */
186static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc) 193static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
187{ 194{
@@ -189,6 +196,19 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
189 struct ahci_host_priv *hpriv = ap->host->private_data; 196 struct ahci_host_priv *hpriv = ap->host->private_data;
190 struct xgene_ahci_context *ctx = hpriv->plat_data; 197 struct xgene_ahci_context *ctx = hpriv->plat_data;
191 int rc = 0; 198 int rc = 0;
199 u32 port_fbs;
200 void *port_mmio = ahci_port_base(ap);
201
202 /*
203 * Write the pmp value to PxFBS.DEV
204 * for case of Port Mulitplier.
205 */
206 if (ctx->class[ap->port_no] == ATA_DEV_PMP) {
207 port_fbs = readl(port_mmio + PORT_FBS);
208 port_fbs &= ~PORT_FBS_DEV_MASK;
209 port_fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
210 writel(port_fbs, port_mmio + PORT_FBS);
211 }
192 212
193 if (unlikely((ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA) || 213 if (unlikely((ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA) ||
194 (ctx->last_cmd[ap->port_no] == ATA_CMD_PACKET))) 214 (ctx->last_cmd[ap->port_no] == ATA_CMD_PACKET)))
@@ -417,12 +437,115 @@ static void xgene_ahci_host_stop(struct ata_host *host)
417 ahci_platform_disable_resources(hpriv); 437 ahci_platform_disable_resources(hpriv);
418} 438}
419 439
440/**
441 * xgene_ahci_pmp_softreset - Issue the softreset to the drives connected
442 * to Port Multiplier.
443 * @link: link to reset
444 * @class: Return value to indicate class of device
445 * @deadline: deadline jiffies for the operation
446 *
447 * Due to H/W errata, the controller is unable to save the PMP
448 * field fetched from command header before sending the H2D FIS.
449 * When the device returns the PMP port field in the D2H FIS, there is
450 * a mismatch and results in command completion failure. The workaround
451 * is to write the pmp value to PxFBS.DEV field before issuing any command
452 * to PMP.
453 */
454static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
455 unsigned long deadline)
456{
457 int pmp = sata_srst_pmp(link);
458 struct ata_port *ap = link->ap;
459 u32 rc;
460 void *port_mmio = ahci_port_base(ap);
461 u32 port_fbs;
462
463 /*
464 * Set PxFBS.DEV field with pmp
465 * value.
466 */
467 port_fbs = readl(port_mmio + PORT_FBS);
468 port_fbs &= ~PORT_FBS_DEV_MASK;
469 port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
470 writel(port_fbs, port_mmio + PORT_FBS);
471
472 rc = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
473
474 return rc;
475}
476
477/**
478 * xgene_ahci_softreset - Issue the softreset to the drive.
479 * @link: link to reset
480 * @class: Return value to indicate class of device
481 * @deadline: deadline jiffies for the operation
482 *
483 * Due to H/W errata, the controller is unable to save the PMP
484 * field fetched from command header before sending the H2D FIS.
485 * When the device returns the PMP port field in the D2H FIS, there is
486 * a mismatch and results in command completion failure. The workaround
487 * is to write the pmp value to PxFBS.DEV field before issuing any command
488 * to PMP. Here is the algorithm to detect PMP :
489 *
490 * 1. Save the PxFBS value
491 * 2. Program PxFBS.DEV with pmp value send by framework. Framework sends
492 * 0xF for both PMP/NON-PMP initially
493 * 3. Issue softreset
494 * 4. If signature class is PMP goto 6
495 * 5. restore the original PxFBS and goto 3
496 * 6. return
497 */
498static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class,
499 unsigned long deadline)
500{
501 int pmp = sata_srst_pmp(link);
502 struct ata_port *ap = link->ap;
503 struct ahci_host_priv *hpriv = ap->host->private_data;
504 struct xgene_ahci_context *ctx = hpriv->plat_data;
505 void *port_mmio = ahci_port_base(ap);
506 u32 port_fbs;
507 u32 port_fbs_save;
508 u32 retry = 1;
509 u32 rc;
510
511 port_fbs_save = readl(port_mmio + PORT_FBS);
512
513 /*
514 * Set PxFBS.DEV field with pmp
515 * value.
516 */
517 port_fbs = readl(port_mmio + PORT_FBS);
518 port_fbs &= ~PORT_FBS_DEV_MASK;
519 port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
520 writel(port_fbs, port_mmio + PORT_FBS);
521
522softreset_retry:
523 rc = ahci_do_softreset(link, class, pmp,
524 deadline, ahci_check_ready);
525
526 ctx->class[ap->port_no] = *class;
527 if (*class != ATA_DEV_PMP) {
528 /*
529 * Retry for normal drives without
530 * setting PxFBS.DEV field with pmp value.
531 */
532 if (retry--) {
533 writel(port_fbs_save, port_mmio + PORT_FBS);
534 goto softreset_retry;
535 }
536 }
537
538 return rc;
539}
540
420static struct ata_port_operations xgene_ahci_ops = { 541static struct ata_port_operations xgene_ahci_ops = {
421 .inherits = &ahci_ops, 542 .inherits = &ahci_ops,
422 .host_stop = xgene_ahci_host_stop, 543 .host_stop = xgene_ahci_host_stop,
423 .hardreset = xgene_ahci_hardreset, 544 .hardreset = xgene_ahci_hardreset,
424 .read_id = xgene_ahci_read_id, 545 .read_id = xgene_ahci_read_id,
425 .qc_issue = xgene_ahci_qc_issue, 546 .qc_issue = xgene_ahci_qc_issue,
547 .softreset = xgene_ahci_softreset,
548 .pmp_softreset = xgene_ahci_pmp_softreset
426}; 549};
427 550
428static const struct ata_port_info xgene_ahci_port_info = { 551static const struct ata_port_info xgene_ahci_port_info = {