aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRobert Hancock <hancockr@shaw.ca>2007-02-05 19:26:02 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-09 17:39:39 -0500
commit382a6652e91b34d5480cfc0ed840c196650493d4 (patch)
tree53f42152bedf08a0135b010885703605e7b35e5f /drivers
parent5bd28a4b6efa73c5d033f3b86201c2c366b170cf (diff)
sata_nv: use ADMA for NODATA commands
Some problems showed up recently with cache flush commands timing out on sata_nv. Previously these commands were always handled by transitioning to legacy mode from ADMA mode first. The timeout problem was worked around already by a change to the interrupt handling code for legacy mode, but for non-data commands like these it appears we can handle them in ADMA mode, so the switch to legacy mode is not needed. This patch changes the behavior so that we use ADMA mode to submit interrupt-driven commands with ATA_PROT_NODATA protocol. In addition to avoiding the problem mentioned above entirely, this avoids the overhead of switching to legacy mode and back to ADMA mode for handling cache flushes. When handling non-DMA-mapped commands, we leave the APRD blank and clear the NV_CPB_CTL_APRD_VALID field in the CPB so the controller does not attempt to read it. Signed-off-by: Robert Hancock <hancockr@shaw.ca> Cc: Jeff Garzik <jeff@garzik.org> Cc: Tejun Heo <htejun@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/sata_nv.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 3dd5ca16a2ba..19817b376161 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1159,16 +1159,31 @@ static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
1159 cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag))); 1159 cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));
1160} 1160}
1161 1161
1162static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
1163{
1164 struct nv_adma_port_priv *pp = qc->ap->private_data;
1165
1166 /* ADMA engine can only be used for non-ATAPI DMA commands,
1167 or interrupt-driven no-data commands. */
1168 if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
1169 (qc->tf.flags & ATA_TFLAG_POLLING))
1170 return 1;
1171
1172 if((qc->flags & ATA_QCFLAG_DMAMAP) ||
1173 (qc->tf.protocol == ATA_PROT_NODATA))
1174 return 0;
1175
1176 return 1;
1177}
1178
1162static void nv_adma_qc_prep(struct ata_queued_cmd *qc) 1179static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
1163{ 1180{
1164 struct nv_adma_port_priv *pp = qc->ap->private_data; 1181 struct nv_adma_port_priv *pp = qc->ap->private_data;
1165 struct nv_adma_cpb *cpb = &pp->cpb[qc->tag]; 1182 struct nv_adma_cpb *cpb = &pp->cpb[qc->tag];
1166 u8 ctl_flags = NV_CPB_CTL_CPB_VALID | 1183 u8 ctl_flags = NV_CPB_CTL_CPB_VALID |
1167 NV_CPB_CTL_APRD_VALID |
1168 NV_CPB_CTL_IEN; 1184 NV_CPB_CTL_IEN;
1169 1185
1170 if (!(qc->flags & ATA_QCFLAG_DMAMAP) || 1186 if (nv_adma_use_reg_mode(qc)) {
1171 (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
1172 nv_adma_register_mode(qc->ap); 1187 nv_adma_register_mode(qc->ap);
1173 ata_qc_prep(qc); 1188 ata_qc_prep(qc);
1174 return; 1189 return;
@@ -1188,7 +1203,11 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
1188 1203
1189 nv_adma_tf_to_cpb(&qc->tf, cpb->tf); 1204 nv_adma_tf_to_cpb(&qc->tf, cpb->tf);
1190 1205
1191 nv_adma_fill_sg(qc, cpb); 1206 if(qc->flags & ATA_QCFLAG_DMAMAP) {
1207 nv_adma_fill_sg(qc, cpb);
1208 ctl_flags |= NV_CPB_CTL_APRD_VALID;
1209 } else
1210 memset(&cpb->aprd[0], 0, sizeof(struct nv_adma_prd) * 5);
1192 1211
1193 /* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are 1212 /* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are
1194 finished filling in all of the contents */ 1213 finished filling in all of the contents */
@@ -1203,10 +1222,9 @@ static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
1203 1222
1204 VPRINTK("ENTER\n"); 1223 VPRINTK("ENTER\n");
1205 1224
1206 if (!(qc->flags & ATA_QCFLAG_DMAMAP) || 1225 if (nv_adma_use_reg_mode(qc)) {
1207 (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
1208 /* use ATA register mode */ 1226 /* use ATA register mode */
1209 VPRINTK("no dmamap or ATAPI, using ATA register mode: 0x%lx\n", qc->flags); 1227 VPRINTK("using ATA register mode: 0x%lx\n", qc->flags);
1210 nv_adma_register_mode(qc->ap); 1228 nv_adma_register_mode(qc->ap);
1211 return ata_qc_issue_prot(qc); 1229 return ata_qc_issue_prot(qc);
1212 } else 1230 } else