aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/ahci_xgene.c60
1 files changed, 47 insertions, 13 deletions
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
index 042a9bb45c86..ee3a3659bd9e 100644
--- a/drivers/ata/ahci_xgene.c
+++ b/drivers/ata/ahci_xgene.c
@@ -78,6 +78,7 @@
78struct xgene_ahci_context { 78struct xgene_ahci_context {
79 struct ahci_host_priv *hpriv; 79 struct ahci_host_priv *hpriv;
80 struct device *dev; 80 struct device *dev;
81 u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/
81 void __iomem *csr_core; /* Core CSR address of IP */ 82 void __iomem *csr_core; /* Core CSR address of IP */
82 void __iomem *csr_diag; /* Diag CSR address of IP */ 83 void __iomem *csr_diag; /* Diag CSR address of IP */
83 void __iomem *csr_axi; /* AXI CSR address of IP */ 84 void __iomem *csr_axi; /* AXI CSR address of IP */
@@ -98,20 +99,62 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
98} 99}
99 100
100/** 101/**
102 * xgene_ahci_restart_engine - Restart the dma engine.
103 * @ap : ATA port of interest
104 *
105 * Restarts the dma engine inside the controller.
106 */
107static int xgene_ahci_restart_engine(struct ata_port *ap)
108{
109 struct ahci_host_priv *hpriv = ap->host->private_data;
110
111 ahci_stop_engine(ap);
112 ahci_start_fis_rx(ap);
113 hpriv->start_engine(ap);
114
115 return 0;
116}
117
118/**
119 * xgene_ahci_qc_issue - Issue commands to the device
120 * @qc: Command to issue
121 *
122 * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot
123 * clear the BSY bit after receiving the PIO setup FIS. This results in the dma
124 * state machine goes into the CMFatalErrorUpdate state and locks up. By
125 * restarting the dma engine, it removes the controller out of lock up state.
126 */
127static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
128{
129 struct ata_port *ap = qc->ap;
130 struct ahci_host_priv *hpriv = ap->host->private_data;
131 struct xgene_ahci_context *ctx = hpriv->plat_data;
132 int rc = 0;
133
134 if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA))
135 xgene_ahci_restart_engine(ap);
136
137 rc = ahci_qc_issue(qc);
138
139 /* Save the last command issued */
140 ctx->last_cmd[ap->port_no] = qc->tf.command;
141
142 return rc;
143}
144
145/**
101 * xgene_ahci_read_id - Read ID data from the specified device 146 * xgene_ahci_read_id - Read ID data from the specified device
102 * @dev: device 147 * @dev: device
103 * @tf: proposed taskfile 148 * @tf: proposed taskfile
104 * @id: data buffer 149 * @id: data buffer
105 * 150 *
106 * This custom read ID function is required due to the fact that the HW 151 * This custom read ID function is required due to the fact that the HW
107 * does not support DEVSLP and the controller state machine may get stuck 152 * does not support DEVSLP.
108 * after processing the ID query command.
109 */ 153 */
110static unsigned int xgene_ahci_read_id(struct ata_device *dev, 154static unsigned int xgene_ahci_read_id(struct ata_device *dev,
111 struct ata_taskfile *tf, u16 *id) 155 struct ata_taskfile *tf, u16 *id)
112{ 156{
113 u32 err_mask; 157 u32 err_mask;
114 void __iomem *port_mmio = ahci_port_base(dev->link->ap);
115 158
116 err_mask = ata_do_dev_read_id(dev, tf, id); 159 err_mask = ata_do_dev_read_id(dev, tf, id);
117 if (err_mask) 160 if (err_mask)
@@ -133,16 +176,6 @@ static unsigned int xgene_ahci_read_id(struct ata_device *dev,
133 */ 176 */
134 id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8); 177 id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8);
135 178
136 /*
137 * Due to HW errata, restart the port if no other command active.
138 * Otherwise the controller may get stuck.
139 */
140 if (!readl(port_mmio + PORT_CMD_ISSUE)) {
141 writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD);
142 readl(port_mmio + PORT_CMD); /* Force a barrier */
143 writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD);
144 readl(port_mmio + PORT_CMD); /* Force a barrier */
145 }
146 return 0; 179 return 0;
147} 180}
148 181
@@ -300,6 +333,7 @@ static struct ata_port_operations xgene_ahci_ops = {
300 .host_stop = xgene_ahci_host_stop, 333 .host_stop = xgene_ahci_host_stop,
301 .hardreset = xgene_ahci_hardreset, 334 .hardreset = xgene_ahci_hardreset,
302 .read_id = xgene_ahci_read_id, 335 .read_id = xgene_ahci_read_id,
336 .qc_issue = xgene_ahci_qc_issue,
303}; 337};
304 338
305static const struct ata_port_info xgene_ahci_port_info = { 339static const struct ata_port_info xgene_ahci_port_info = {