aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorSuman Tripathi <stripathi@apm.com>2015-01-06 05:02:15 -0500
committerTejun Heo <tj@kernel.org>2015-01-06 08:38:25 -0500
commit1540035da71ea0feecdf24eeb98471ffa08da0d3 (patch)
tree099e706e3677f60f45c8e00bebcf0c57a7f27c66 /drivers/ata
parentb84b25cb0900b99b28c742dd33101be779f58259 (diff)
ahci_xgene: Implement the xgene_ahci_poll_reg_val to support PMP.
This patch implements the function xgene_ahci_poll_reg_val to poll PxCI for multiple IDENTIFY DEVICE commands to finish before restarting the DMA engine. 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.c56
1 files changed, 54 insertions, 2 deletions
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
index cbcd20810355..afa9c03ecfd6 100644
--- a/drivers/ata/ahci_xgene.c
+++ b/drivers/ata/ahci_xgene.c
@@ -105,17 +105,69 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
105} 105}
106 106
107/** 107/**
108 * xgene_ahci_poll_reg_val- Poll a register on a specific value.
109 * @ap : ATA port of interest.
110 * @reg : Register of interest.
111 * @val : Value to be attained.
112 * @interval : waiting interval for polling.
113 * @timeout : timeout for achieving the value.
114 */
115static int xgene_ahci_poll_reg_val(struct ata_port *ap,
116 void __iomem *reg, unsigned
117 int val, unsigned long interval,
118 unsigned long timeout)
119{
120 unsigned long deadline;
121 unsigned int tmp;
122
123 tmp = ioread32(reg);
124 deadline = ata_deadline(jiffies, timeout);
125
126 while (tmp != val && time_before(jiffies, deadline)) {
127 ata_msleep(ap, interval);
128 tmp = ioread32(reg);
129 }
130
131 return tmp;
132}
133
134/**
108 * xgene_ahci_restart_engine - Restart the dma engine. 135 * xgene_ahci_restart_engine - Restart the dma engine.
109 * @ap : ATA port of interest 136 * @ap : ATA port of interest
110 * 137 *
111 * Restarts the dma engine inside the controller. 138 * Waits for completion of multiple commands and restarts
139 * the DMA engine inside the controller.
112 */ 140 */
113static int xgene_ahci_restart_engine(struct ata_port *ap) 141static int xgene_ahci_restart_engine(struct ata_port *ap)
114{ 142{
115 struct ahci_host_priv *hpriv = ap->host->private_data; 143 struct ahci_host_priv *hpriv = ap->host->private_data;
144 struct ahci_port_priv *pp = ap->private_data;
145 void __iomem *port_mmio = ahci_port_base(ap);
146 u32 fbs;
147
148 /*
149 * In case of PMP multiple IDENTIFY DEVICE commands can be
150 * issued inside PxCI. So need to poll PxCI for the
151 * completion of outstanding IDENTIFY DEVICE commands before
152 * we restart the DMA engine.
153 */
154 if (xgene_ahci_poll_reg_val(ap, port_mmio +
155 PORT_CMD_ISSUE, 0x0, 1, 100))
156 return -EBUSY;
116 157
117 ahci_stop_engine(ap); 158 ahci_stop_engine(ap);
118 ahci_start_fis_rx(ap); 159 ahci_start_fis_rx(ap);
160
161 /*
162 * Enable the PxFBS.FBS_EN bit as it
163 * gets cleared due to stopping the engine.
164 */
165 if (pp->fbs_supported) {
166 fbs = readl(port_mmio + PORT_FBS);
167 writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
168 fbs = readl(port_mmio + PORT_FBS);
169 }
170
119 hpriv->start_engine(ap); 171 hpriv->start_engine(ap);
120 172
121 return 0; 173 return 0;
@@ -374,7 +426,7 @@ static struct ata_port_operations xgene_ahci_ops = {
374}; 426};
375 427
376static const struct ata_port_info xgene_ahci_port_info = { 428static const struct ata_port_info xgene_ahci_port_info = {
377 .flags = AHCI_FLAG_COMMON, 429 .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
378 .pio_mask = ATA_PIO4, 430 .pio_mask = ATA_PIO4,
379 .udma_mask = ATA_UDMA6, 431 .udma_mask = ATA_UDMA6,
380 .port_ops = &xgene_ahci_ops, 432 .port_ops = &xgene_ahci_ops,