Skip to content

Commit 382a665

Browse files
Robert HancockJeff Garzik
authored andcommitted
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 <[email protected]> Cc: Jeff Garzik <[email protected]> Cc: Tejun Heo <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Jeff Garzik <[email protected]>
1 parent 5bd28a4 commit 382a665

File tree

1 file changed

+25
-7
lines changed

1 file changed

+25
-7
lines changed

drivers/ata/sata_nv.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,16 +1159,31 @@ static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
11591159
cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));
11601160
}
11611161

1162+
static 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+
11621179
static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
11631180
{
11641181
struct nv_adma_port_priv *pp = qc->ap->private_data;
11651182
struct nv_adma_cpb *cpb = &pp->cpb[qc->tag];
11661183
u8 ctl_flags = NV_CPB_CTL_CPB_VALID |
1167-
NV_CPB_CTL_APRD_VALID |
11681184
NV_CPB_CTL_IEN;
11691185

1170-
if (!(qc->flags & ATA_QCFLAG_DMAMAP) ||
1171-
(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
1186+
if (nv_adma_use_reg_mode(qc)) {
11721187
nv_adma_register_mode(qc->ap);
11731188
ata_qc_prep(qc);
11741189
return;
@@ -1188,7 +1203,11 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
11881203

11891204
nv_adma_tf_to_cpb(&qc->tf, cpb->tf);
11901205

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);
11921211

11931212
/* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are
11941213
finished filling in all of the contents */
@@ -1203,10 +1222,9 @@ static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
12031222

12041223
VPRINTK("ENTER\n");
12051224

1206-
if (!(qc->flags & ATA_QCFLAG_DMAMAP) ||
1207-
(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
1225+
if (nv_adma_use_reg_mode(qc)) {
12081226
/* 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);
12101228
nv_adma_register_mode(qc->ap);
12111229
return ata_qc_issue_prot(qc);
12121230
} else

0 commit comments

Comments
 (0)