diff options
author | Tejun Heo <tj@kernel.org> | 2014-07-30 12:49:04 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-07-30 12:49:04 -0400 |
commit | e8f781836dc3335b5533f6e177a105bbe3ee7345 (patch) | |
tree | b6f05b7bf6e69bcc436ab894b7dc84c28c746d1a /drivers/ata/ahci_xgene.c | |
parent | 19f5be0f40922717e2b6e39a9822e7e7f30fd81f (diff) | |
parent | 1a112d10f03e83fb3a2fdc4c9165865dec8a3ca6 (diff) |
Merge branch 'for-3.16-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata into for-3.17
The scheduled ahci platform patches depend on change in
for-3.16-fixes. Pull it into for-3.17.
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata/ahci_xgene.c')
-rw-r--r-- | drivers/ata/ahci_xgene.c | 60 |
1 files changed, 47 insertions, 13 deletions
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 997b4178249a..1cfbdca638d2 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c | |||
@@ -81,6 +81,7 @@ | |||
81 | struct xgene_ahci_context { | 81 | struct xgene_ahci_context { |
82 | struct ahci_host_priv *hpriv; | 82 | struct ahci_host_priv *hpriv; |
83 | struct device *dev; | 83 | struct device *dev; |
84 | u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/ | ||
84 | void __iomem *csr_core; /* Core CSR address of IP */ | 85 | void __iomem *csr_core; /* Core CSR address of IP */ |
85 | void __iomem *csr_diag; /* Diag CSR address of IP */ | 86 | void __iomem *csr_diag; /* Diag CSR address of IP */ |
86 | void __iomem *csr_axi; /* AXI CSR address of IP */ | 87 | void __iomem *csr_axi; /* AXI CSR address of IP */ |
@@ -101,20 +102,62 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) | |||
101 | } | 102 | } |
102 | 103 | ||
103 | /** | 104 | /** |
105 | * xgene_ahci_restart_engine - Restart the dma engine. | ||
106 | * @ap : ATA port of interest | ||
107 | * | ||
108 | * Restarts the dma engine inside the controller. | ||
109 | */ | ||
110 | static int xgene_ahci_restart_engine(struct ata_port *ap) | ||
111 | { | ||
112 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
113 | |||
114 | ahci_stop_engine(ap); | ||
115 | ahci_start_fis_rx(ap); | ||
116 | hpriv->start_engine(ap); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /** | ||
122 | * xgene_ahci_qc_issue - Issue commands to the device | ||
123 | * @qc: Command to issue | ||
124 | * | ||
125 | * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot | ||
126 | * clear the BSY bit after receiving the PIO setup FIS. This results in the dma | ||
127 | * state machine goes into the CMFatalErrorUpdate state and locks up. By | ||
128 | * restarting the dma engine, it removes the controller out of lock up state. | ||
129 | */ | ||
130 | static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc) | ||
131 | { | ||
132 | struct ata_port *ap = qc->ap; | ||
133 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
134 | struct xgene_ahci_context *ctx = hpriv->plat_data; | ||
135 | int rc = 0; | ||
136 | |||
137 | if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA)) | ||
138 | xgene_ahci_restart_engine(ap); | ||
139 | |||
140 | rc = ahci_qc_issue(qc); | ||
141 | |||
142 | /* Save the last command issued */ | ||
143 | ctx->last_cmd[ap->port_no] = qc->tf.command; | ||
144 | |||
145 | return rc; | ||
146 | } | ||
147 | |||
148 | /** | ||
104 | * xgene_ahci_read_id - Read ID data from the specified device | 149 | * xgene_ahci_read_id - Read ID data from the specified device |
105 | * @dev: device | 150 | * @dev: device |
106 | * @tf: proposed taskfile | 151 | * @tf: proposed taskfile |
107 | * @id: data buffer | 152 | * @id: data buffer |
108 | * | 153 | * |
109 | * This custom read ID function is required due to the fact that the HW | 154 | * This custom read ID function is required due to the fact that the HW |
110 | * does not support DEVSLP and the controller state machine may get stuck | 155 | * does not support DEVSLP. |
111 | * after processing the ID query command. | ||
112 | */ | 156 | */ |
113 | static unsigned int xgene_ahci_read_id(struct ata_device *dev, | 157 | static unsigned int xgene_ahci_read_id(struct ata_device *dev, |
114 | struct ata_taskfile *tf, u16 *id) | 158 | struct ata_taskfile *tf, u16 *id) |
115 | { | 159 | { |
116 | u32 err_mask; | 160 | u32 err_mask; |
117 | void __iomem *port_mmio = ahci_port_base(dev->link->ap); | ||
118 | 161 | ||
119 | err_mask = ata_do_dev_read_id(dev, tf, id); | 162 | err_mask = ata_do_dev_read_id(dev, tf, id); |
120 | if (err_mask) | 163 | if (err_mask) |
@@ -136,16 +179,6 @@ static unsigned int xgene_ahci_read_id(struct ata_device *dev, | |||
136 | */ | 179 | */ |
137 | id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8); | 180 | id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8); |
138 | 181 | ||
139 | /* | ||
140 | * Due to HW errata, restart the port if no other command active. | ||
141 | * Otherwise the controller may get stuck. | ||
142 | */ | ||
143 | if (!readl(port_mmio + PORT_CMD_ISSUE)) { | ||
144 | writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD); | ||
145 | readl(port_mmio + PORT_CMD); /* Force a barrier */ | ||
146 | writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD); | ||
147 | readl(port_mmio + PORT_CMD); /* Force a barrier */ | ||
148 | } | ||
149 | return 0; | 182 | return 0; |
150 | } | 183 | } |
151 | 184 | ||
@@ -307,6 +340,7 @@ static struct ata_port_operations xgene_ahci_ops = { | |||
307 | .host_stop = xgene_ahci_host_stop, | 340 | .host_stop = xgene_ahci_host_stop, |
308 | .hardreset = xgene_ahci_hardreset, | 341 | .hardreset = xgene_ahci_hardreset, |
309 | .read_id = xgene_ahci_read_id, | 342 | .read_id = xgene_ahci_read_id, |
343 | .qc_issue = xgene_ahci_qc_issue, | ||
310 | }; | 344 | }; |
311 | 345 | ||
312 | static const struct ata_port_info xgene_ahci_port_info = { | 346 | static const struct ata_port_info xgene_ahci_port_info = { |