diff options
-rw-r--r-- | drivers/ata/ahci_xgene.c | 56 |
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 | */ | ||
115 | static 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 | */ |
113 | static int xgene_ahci_restart_engine(struct ata_port *ap) | 141 | static 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 | ||
376 | static const struct ata_port_info xgene_ahci_port_info = { | 428 | static 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, |