Browse Source

[MMC] extend data timeout for writes

The CSD contains a "read2write factor" which determines the multiplier to
be applied to the read timeout to obtain the write timeout.  We were
ignoring this parameter, resulting in the possibility for writes being
timed out too early.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Russell King 19 years ago
parent
commit
37be4e7809
3 changed files with 9 additions and 0 deletions
  1. 2 0
      drivers/mmc/mmc.c
  2. 6 0
      drivers/mmc/mmc_block.c
  3. 1 0
      include/linux/mmc/card.h

+ 2 - 0
drivers/mmc/mmc.c

@@ -549,6 +549,7 @@ static void mmc_decode_csd(struct mmc_card *card)
 		csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
 		csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
 		csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
 		csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
 		csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
 		csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+		csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
 		csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
 		csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
 		csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
 		csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
 	} else {
 	} else {
@@ -583,6 +584,7 @@ static void mmc_decode_csd(struct mmc_card *card)
 		csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
 		csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
 		csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
 		csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
 		csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
 		csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+		csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
 		csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
 		csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
 		csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
 		csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
 	}
 	}

+ 6 - 0
drivers/mmc/mmc_block.c

@@ -187,6 +187,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 			brq.cmd.opcode = MMC_WRITE_BLOCK;
 			brq.cmd.opcode = MMC_WRITE_BLOCK;
 			brq.data.flags |= MMC_DATA_WRITE;
 			brq.data.flags |= MMC_DATA_WRITE;
 			brq.data.blocks = 1;
 			brq.data.blocks = 1;
+
+			/*
+			 * Scale up the timeout by the r2w factor
+			 */
+			brq.data.timeout_ns <<= card->csd.r2w_factor;
+			brq.data.timeout_clks <<= card->csd.r2w_factor;
 		}
 		}
 
 
 		if (brq.data.blocks > 1) {
 		if (brq.data.blocks > 1) {

+ 1 - 0
include/linux/mmc/card.h

@@ -28,6 +28,7 @@ struct mmc_csd {
 	unsigned short		cmdclass;
 	unsigned short		cmdclass;
 	unsigned short		tacc_clks;
 	unsigned short		tacc_clks;
 	unsigned int		tacc_ns;
 	unsigned int		tacc_ns;
+	unsigned int		r2w_factor;
 	unsigned int		max_dtr;
 	unsigned int		max_dtr;
 	unsigned int		read_blkbits;
 	unsigned int		read_blkbits;
 	unsigned int		write_blkbits;
 	unsigned int		write_blkbits;