--- kernel-source-2.6.16-2.6.16.rel/include/linux/mmc/card.h 2007-08-22 10:44:38.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/include/linux/mmc/card.h 2007-12-08 21:45:54.000000000 +0100 @@ -39,6 +39,11 @@ write_misalign:1; }; +struct mmc_ext_csd { + unsigned int hs_max_dtr; + unsigned int sectors; +}; + struct sd_scr { unsigned char sda_vsn; unsigned char bus_widths; @@ -46,6 +51,10 @@ #define SD_SCR_BUS_WIDTH_4 (1<<2) }; +struct sd_switch_caps { + unsigned int hs_max_dtr; +}; + struct mmc_host; /* @@ -62,12 +71,17 @@ #define MMC_STATE_BAD (1<<2) /* unrecognised device */ #define MMC_STATE_SDCARD (1<<3) /* is an SD card */ #define MMC_STATE_READONLY (1<<4) /* card is read-only */ +#define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */ +#define MMC_STATE_BLOCKADDR (1<<6) /* card uses block-addressing */ + unsigned int rq_state; /* Last state at end of rq */ u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ u32 raw_scr[2]; /* raw card SCR */ struct mmc_cid cid; /* card identification */ struct mmc_csd csd; /* card specific */ + struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ struct sd_scr scr; /* extra SD information */ + struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ }; #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) @@ -75,12 +89,16 @@ #define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD) #define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) +#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED) +#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD) #define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD) #define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) +#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED) +#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR) #define mmc_card_name(c) ((c)->cid.prod_name) #define mmc_card_id(c) ((c)->dev.bus_id) --- kernel-source-2.6.16-2.6.16.rel/include/linux/mmc/host.h 2007-08-22 10:44:38.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/include/linux/mmc/host.h 2007-12-08 21:46:30.000000000 +0100 @@ -57,11 +57,18 @@ #define MMC_POWER_OFF 0 #define MMC_POWER_UP 1 #define MMC_POWER_ON 2 +#define MMC_POWER_STANDBY 3 unsigned char bus_width; /* data bus width */ #define MMC_BUS_WIDTH_1 0 #define MMC_BUS_WIDTH_4 2 + + unsigned char timing; /* timing specification used */ + +#define MMC_TIMING_LEGACY 0 +#define MMC_TIMING_MMC_HS 1 +#define MMC_TIMING_SD_HS 2 }; struct mmc_host_ops { @@ -77,7 +84,7 @@ struct device *dev; struct class_device class_dev; int index; - struct mmc_host_ops *ops; + const struct mmc_host_ops *ops; unsigned int f_min; unsigned int f_max; u32 ocr_avail; @@ -85,13 +92,20 @@ unsigned long caps; /* Host capabilities */ #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */ +#define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */ +#define MMC_CAP_BYTEBLOCK (1 << 2) /* Can do non-log2 block sizes */ +#define MMC_CAP_MMC_HIGHSPEED (1 << 3) /* Can do MMC high-speed timing */ +#define MMC_CAP_SD_HIGHSPEED (1 << 4) /* Can do SD high-speed timing */ +#define MMC_CAP_STANDBY (1 << 5) /* Low power mode available */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */ unsigned short max_phys_segs; /* see blk_queue_max_phys_segments */ - unsigned short max_sectors; /* see blk_queue_max_sectors */ unsigned short unused; + unsigned int max_req_size; /* maximum number of bytes in one req */ + unsigned int max_blk_size; /* maximum size of one mmc block */ + unsigned int max_blk_count; /* maximum number of blocks in one req */ /* private data */ struct mmc_ios ios; /* current io bus settings */ @@ -104,11 +118,15 @@ struct list_head cards; /* devices attached to this host */ wait_queue_head_t wq; - spinlock_t lock; /* card_busy lock */ - struct mmc_card *card_busy; /* the MMC card claiming host */ + spinlock_t lock; /* claimed lock */ + unsigned int claimed:1; /* host exclusively claimed */ + struct mmc_card *card_selected; /* the selected MMC card */ struct work_struct detect; + struct work_struct idle_work; + struct timer_list idle_timer; + unsigned int idle_delay; unsigned long private[0] ____cacheline_aligned; }; --- kernel-source-2.6.16-2.6.16.rel/include/linux/mmc/protocol.h 2007-08-22 10:44:38.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/include/linux/mmc/protocol.h 2007-12-07 20:21:13.000000000 +0100 @@ -25,14 +25,16 @@ #ifndef MMC_MMC_PROTOCOL_H #define MMC_MMC_PROTOCOL_H -/* Standard MMC commands (3.1) type argument response */ +/* Standard MMC commands (4.1) type argument response */ /* class 1 */ #define MMC_GO_IDLE_STATE 0 /* bc */ #define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ #define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ #define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ #define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ @@ -77,14 +79,50 @@ #define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ /* SD commands type argument response */ - /* class 8 */ + /* class 0 */ /* This is basically the same command as for MMC with some quirks. */ #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ +#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ + + /* class 10 */ +#define SD_SWITCH 6 /* adtc [31:0] See below R1 */ /* Application commands */ #define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ +#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */ #define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ #define SD_APP_SEND_SCR 51 /* adtc R1 */ +/* + * MMC_SWITCH argument format: + * + * [31:26] Always 0 + * [25:24] Access Mode + * [23:16] Location of target Byte in EXT_CSD + * [15:08] Value Byte + * [07:03] Always 0 + * [02:00] Command Set + */ + +/* + * SD_SWITCH argument format: + * + * [31] Check (0) or switch (1) + * [30:24] Reserved (0) + * [23:20] Function group 6 + * [19:16] Function group 5 + * [15:12] Function group 4 + * [11:8] Function group 3 + * [7:4] Function group 2 + * [3:0] Function group 1 + */ + +/* + * SD_SEND_IF_COND argument format: + * + * [31:12] Reserved (0) + * [11:8] Host Voltage Supply Flags + * [7:0] Check Pattern (0xAA) + */ /* MMC status in R1 @@ -124,6 +162,16 @@ #define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ #define R1_APP_CMD (1 << 5) /* sr, c */ +#define R1_STATE_IDLE 0 +#define R1_STATE_READY 1 +#define R1_STATE_IDENT 2 +#define R1_STATE_STBY 3 +#define R1_STATE_TRAN 4 +#define R1_STATE_DATA 5 +#define R1_STATE_REV 6 +#define R1_STATE_PRG 7 +#define R1_STATE_DIS 8 +#define R1_STATE_BTST 9 /* These are unpacked versions of the actual responses */ @@ -229,13 +277,57 @@ #define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ #define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ -#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */ +#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */ +#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */ #define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ #define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ #define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ -#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */ +#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */ +#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */ + +/* + * EXT_CSD fields + */ + +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_CMD_SET_NORMAL (1<<0) +#define EXT_CSD_CMD_SET_SECURE (1<<1) +#define EXT_CSD_CMD_SET_CPSECURE (1<<2) + +#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ + +#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ + +#define EXT_CSD_SEC_CNT_2GB (2 << (30 - 9)) + +/* + * MMC_SWITCH access modes + */ + +#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ +#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ + +/* + * SCR field definitions + */ +#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ +#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ +#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */ /* * SD bus widths --- kernel-source-2.6.16-2.6.16.rel/include/linux/mmc/mmc.h 2006-11-28 14:17:05.000000000 +0100 +++ kernel-source-2.6.16-2.6.16.my/include/linux/mmc/mmc.h 2007-12-07 20:19:30.000000000 +0100 @@ -43,6 +43,7 @@ #define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) #define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC) +#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE)) @@ -68,7 +69,6 @@ struct mmc_data { unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */ unsigned int timeout_clks; /* data timeout (in clocks) */ - unsigned int blksz_bits; /* data block size */ unsigned int blksz; /* data block size */ unsigned int blocks; /* number of blocks */ unsigned int error; /* data error */ @@ -105,6 +105,8 @@ extern int mmc_wait_for_app_cmd(struct mmc_host *, unsigned int, struct mmc_command *, int); +extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *, int); + extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card); static inline void mmc_claim_host(struct mmc_host *host) --- kernel-source-2.6.16-2.6.16.rel/drivers/mmc/mmc_block.c 2007-08-22 10:44:38.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/drivers/mmc/mmc_block.c 2007-12-07 21:55:38.000000000 +0100 @@ -29,10 +29,12 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -82,7 +84,6 @@ md->usage--; if (md->usage == 0) { put_disk(md->disk); - mmc_cleanup_queue(&md->queue); kfree(md); } mutex_unlock(&open_lock); @@ -154,56 +155,152 @@ return stat; } +static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) +{ + int err; + u32 blocks; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + + struct scatterlist sg; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_APP_CMD; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &cmd, 0); + if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) + return (u32)-1; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_APP_SEND_NUM_WR_BLKS; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 4; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, &blocks, 4); + + mmc_wait_for_req(card->host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) + return (u32)-1; + + blocks = ntohl(blocks); + + return blocks; +} + +static int mmc_blk_configure_xfer(struct mmc_card *card, + struct mmc_blk_request *brq, + struct request *req) +{ + u32 readcmd, writecmd; + + if (rq_data_dir(req) != READ && + !(card->host->caps & MMC_CAP_MULTIWRITE) && + !mmc_card_sd(card)) + brq->data.blocks = 1; + + if (brq->data.blocks > 1) { + /* MMC cards behave better (at least with write operations) + * if we specify the block count in advance. */ + if (!mmc_card_sd(card)) { + struct mmc_command cmd; + int err; + + cmd.opcode = MMC_SET_BLOCK_COUNT; + cmd.arg = brq->data.blocks; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + err = mmc_wait_for_cmd(card->host, &cmd, 5); + if (err) { + if (printk_ratelimit()) + printk(KERN_WARNING "%s: error %d setting block count\n", + req->rq_disk->disk_name, cmd.error); + /* Fall back to single-block transfer */ + brq->data.blocks = 1; + } + } else + brq->mrq.stop = &brq->stop; + } + + if (brq->data.blocks > 1) { + brq->data.flags |= MMC_DATA_MULTI; + readcmd = MMC_READ_MULTIPLE_BLOCK; + writecmd = MMC_WRITE_MULTIPLE_BLOCK; + } else { + readcmd = MMC_READ_SINGLE_BLOCK; + writecmd = MMC_WRITE_BLOCK; + } + + if (rq_data_dir(req) == READ) { + brq->cmd.opcode = readcmd; + brq->data.flags |= MMC_DATA_READ; + } else { + brq->cmd.opcode = writecmd; + brq->data.flags |= MMC_DATA_WRITE; + } + + return 0; +} + static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; - int ret; + struct mmc_blk_request brq; + int ret = 1; if (mmc_card_claim_host(card)) - goto cmd_err; + goto flush_queue; do { - struct mmc_blk_request brq; struct mmc_command cmd; - int loop_count = 0, poll_count = 0; memset(&brq, 0, sizeof(struct mmc_blk_request)); brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; - brq.cmd.arg = req->sector << 9; + brq.cmd.arg = req->sector; + if (!mmc_card_blockaddr(card)) + brq.cmd.arg <<= 9; brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - brq.data.timeout_ns = card->csd.tacc_ns * 10; - brq.data.timeout_clks = card->csd.tacc_clks * 10; - brq.data.blksz_bits = md->block_bits; brq.data.blksz = 1 << md->block_bits; - brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); + if (brq.data.blocks > card->host->max_blk_count) + brq.data.blocks = card->host->max_blk_count; - if (rq_data_dir(req) == READ) { - brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK; - brq.data.flags |= MMC_DATA_READ; - } else { - brq.cmd.opcode = MMC_WRITE_BLOCK; - brq.data.flags |= MMC_DATA_WRITE; - 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; - } + mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); - if (brq.data.blocks > 1) { - brq.data.flags |= MMC_DATA_MULTI; - brq.mrq.stop = &brq.stop; - } else { - brq.mrq.stop = NULL; - } + /* + * If the host doesn't support multiple block writes, force + * block writes to single block. SD cards are excepted from + * this rule as they support querying the number of + * successfully written sectors. + */ + if (mmc_blk_configure_xfer(card, &brq, req) < 0) + goto cmd_err; brq.data.sg = mq->sg; brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg); @@ -227,38 +324,29 @@ goto cmd_err; } - do { - int err; - - cmd.opcode = MMC_SEND_STATUS; - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, 5); - if (err) { - printk(KERN_ERR "%s: error %d requesting status\n", - req->rq_disk->disk_name, err); - goto cmd_err; - } - poll_count++; - if (poll_count >= 100) { - loop_count++; - if (loop_count >= 100) { - printk(KERN_ERR "%s: card failed to become ready\n", - req->rq_disk->disk_name); + if (rq_data_dir(req) != READ) { + do { + int err; + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + err = mmc_wait_for_cmd(card->host, &cmd, 5); + if (err) { + printk(KERN_ERR "%s: error %d requesting status\n", + req->rq_disk->disk_name, err); goto cmd_err; } - msleep(5); - poll_count = 0; - } - } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); + } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); #if 0 - if (cmd.resp[0] & ~0x00000900) - printk(KERN_ERR "%s: status = %08x\n", - req->rq_disk->disk_name, cmd.resp[0]); - if (mmc_decode_status(cmd.resp)) - goto cmd_err; + if (cmd.resp[0] & ~0x00000900) + printk(KERN_ERR "%s: status = %08x\n", + req->rq_disk->disk_name, cmd.resp[0]); + if (mmc_decode_status(cmd.resp)) + goto cmd_err; #endif + } /* * A block was successfully transferred. @@ -281,19 +369,46 @@ return 1; cmd_err: + /* + * If this is an SD card and we're writing, we can first + * mark the known good sectors as ok. + * + * If the card is not SD, we can still ok written sectors + * if the controller can do proper error reporting. + * + * For reads we just fail the entire chunk as that should + * be safe in all cases. + */ + if (rq_data_dir(req) != READ && mmc_card_sd(card)) { + u32 blocks; + unsigned int bytes; + + blocks = mmc_sd_num_wr_blocks(card); + if (blocks != (u32)-1) { + if (card->csd.write_partial) + bytes = blocks << md->block_bits; + else + bytes = blocks << 9; + spin_lock_irq(&md->lock); + ret = end_that_request_chunk(req, 1, bytes); + spin_unlock_irq(&md->lock); + } + } else if (rq_data_dir(req) != READ && + (card->host->caps & MMC_CAP_MULTIWRITE)) { + spin_lock_irq(&md->lock); + ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); + spin_unlock_irq(&md->lock); + } + +flush_queue: + mmc_card_release_host(card); - /* - * This is a little draconian, but until we get proper - * error handling sorted out here, its the best we can - * do - especially as some hosts have no idea how much - * data was transferred before the error occurred. - */ spin_lock_irq(&md->lock); - do { + while (ret) { ret = end_that_request_chunk(req, 0, req->current_nr_sectors << 9); - } while (ret); + } add_disk_randomness(req->rq_disk); blkdev_dequeue_request(req); @@ -385,11 +500,20 @@ blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); - /* - * The CSD capacity field is in units of read_blkbits. - * set_capacity takes units of 512 bytes. - */ - set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9)); + if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { + /* + * The EXT_CSD sector count is in number or 512 byte + * sectors. + */ + set_capacity(md->disk, card->ext_csd.sectors); + } else { + /* + * The CSD capacity field is in units of read_blkbits. + * set_capacity takes units of 512 bytes. + */ + set_capacity(md->disk, + card->csd.capacity << (card->csd.read_blkbits - 9)); + } return md; err_putdisk: @@ -406,6 +530,10 @@ struct mmc_command cmd; int err; + /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */ + if (mmc_card_blockaddr(card)) + return 0; + mmc_card_claim_host(card); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = 1 << md->block_bits; @@ -463,12 +591,11 @@ if (md) { int devidx; + /* Stop new requests from getting into the queue */ del_gendisk(md->disk); - /* - * I think this is needed. - */ - md->disk->queue = NULL; + /* Then flush out any already in there */ + mmc_cleanup_queue(&md->queue); devidx = md->disk->first_minor >> MMC_SHIFT; __clear_bit(devidx, dev_use); --- kernel-source-2.6.16-2.6.16.rel/drivers/mmc/mmc.c 2007-08-22 10:44:38.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/drivers/mmc/mmc.c 2007-12-08 21:48:13.000000000 +0100 @@ -4,12 +4,12 @@ * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved. + * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include #include #include #include @@ -57,6 +57,23 @@ 35, 40, 45, 50, 55, 60, 70, 80, }; +static void mmc_idle_work(void *data); +static inline void mmc_set_ios(struct mmc_host *host); + + +static void mmc_card_watch_state(struct mmc_host *host, struct mmc_command *cmd) +{ + struct mmc_card *card = host->card_selected; + + if (!host->claimed || card == NULL || card == (void *)-1) + return; + + if (mmc_resp_type(cmd) == MMC_RSP_R1) { + card->rq_state = R1_CURRENT_STATE(cmd->resp[0]); + mod_timer(&host->idle_timer, + jiffies + host->idle_delay); + } +} /** * mmc_request_done - finish processing an MMC request @@ -82,6 +99,9 @@ cmd->error = 0; host->ops->request(host, mrq); } else if (mrq->done) { + if (host->caps & MMC_CAP_STANDBY) + mmc_card_watch_state(host, cmd); + mrq->done(mrq); } } @@ -103,11 +123,16 @@ mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); - WARN_ON(host->card_busy == NULL); + WARN_ON(!host->claimed); mrq->cmd->error = 0; mrq->cmd->mrq = mrq; if (mrq->data) { + BUG_ON(mrq->data->blksz > host->max_blk_size); + BUG_ON(mrq->data->blocks > host->max_blk_count); + BUG_ON(mrq->data->blocks * mrq->data->blksz > + host->max_req_size); + mrq->cmd->data = mrq->data; mrq->data->error = 0; mrq->data->mrq = mrq; @@ -117,6 +142,12 @@ mrq->stop->mrq = mrq; } } + + if (host->ios.power_mode != MMC_POWER_ON) { + host->ios.power_mode = MMC_POWER_ON; + mmc_set_ios(host); + } + host->ops->request(host, mrq); } @@ -157,7 +188,7 @@ { struct mmc_request mrq; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); memset(&mrq, 0, sizeof(struct mmc_request)); @@ -195,7 +226,7 @@ int i, err; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); BUG_ON(retries < 0); err = MMC_ERR_INVALID; @@ -248,6 +279,58 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd); +/** + * mmc_set_data_timeout - set the timeout for a data command + * @data: data phase for command + * @card: the MMC card associated with the data transfer + * @write: flag to differentiate reads from writes + */ +void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, + int write) +{ + unsigned int mult; + + /* + * SD cards use a 100 multiplier rather than 10 + */ + mult = mmc_card_sd(card) ? 100 : 10; + + /* + * Scale up the multiplier (and therefore the timeout) by + * the r2w factor for writes. + */ + if (write) + mult <<= card->csd.r2w_factor; + + data->timeout_ns = card->csd.tacc_ns * mult; + data->timeout_clks = card->csd.tacc_clks * mult; + + /* + * SD cards also have an upper limit on the timeout. + */ + if (mmc_card_sd(card)) { + unsigned int timeout_us, limit_us; + + timeout_us = data->timeout_ns / 1000; + timeout_us += data->timeout_clks * 1000 / + (card->host->ios.clock / 1000); + + if (write) + limit_us = 250000; + else + limit_us = 100000; + + /* + * SDHC cards always use these fixed values. + */ + if (timeout_us > limit_us || mmc_card_blockaddr(card)) { + data->timeout_ns = limit_us * 1000; + data->timeout_clks = 0; + } + } +} +EXPORT_SYMBOL(mmc_set_data_timeout); + static int mmc_select_card(struct mmc_host *host, struct mmc_card *card); /** @@ -271,14 +354,14 @@ spin_lock_irqsave(&host->lock, flags); while (1) { set_current_state(TASK_UNINTERRUPTIBLE); - if (host->card_busy == NULL) + if (!host->claimed) break; spin_unlock_irqrestore(&host->lock, flags); schedule(); spin_lock_irqsave(&host->lock, flags); } set_current_state(TASK_RUNNING); - host->card_busy = card; + host->claimed = 1; spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); @@ -304,10 +387,10 @@ { unsigned long flags; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); spin_lock_irqsave(&host->lock, flags); - host->card_busy = NULL; + host->claimed = 0; spin_unlock_irqrestore(&host->lock, flags); wake_up(&host->wq); @@ -319,11 +402,12 @@ { struct mmc_ios *ios = &host->ios; - pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", + pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u " + "width %u timing %u\n", mmc_hostname(host), ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, ios->vdd, - ios->bus_width); - + ios->bus_width, ios->timing); + host->ops->set_ios(host, ios); } @@ -332,7 +416,7 @@ int err; struct mmc_command cmd; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); if (host->card_selected == card) return MMC_ERR_NONE; @@ -348,23 +432,23 @@ return err; /* - * Default bus width is 1 bit. - */ - host->ios.bus_width = MMC_BUS_WIDTH_1; - - /* - * We can only change the bus width of the selected - * card so therefore we have to put the handling + * We can only change the bus width of SD cards when + * they are selected so we have to put the handling * here. + * + * The card is in 1 bit mode by default so + * we only need to change if it supports the + * wider version. */ - if (host->caps & MMC_CAP_4_BIT_DATA) { + if (mmc_card_sd(card) && + (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + /* - * The card is in 1 bit mode by default so - * we only need to change if it supports the - * wider version. - */ - if (mmc_card_sd(card) && - (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { + * Default bus width is 1 bit. + */ + host->ios.bus_width = MMC_BUS_WIDTH_1; + + if (host->caps & MMC_CAP_4_BIT_DATA) { struct mmc_command cmd; cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.arg = SD_BUS_WIDTH_4; @@ -427,7 +511,7 @@ if (bit) { bit -= 1; - ocr = 3 << bit; + ocr &= 3 << bit; host->ios.vdd = bit; mmc_set_ios(host); @@ -539,34 +623,65 @@ if (mmc_card_sd(card)) { csd_struct = UNSTUFF_BITS(resp, 126, 2); - if (csd_struct != 0) { + + switch (csd_struct) { + case 0: + m = UNSTUFF_BITS(resp, 115, 4); + e = UNSTUFF_BITS(resp, 112, 3); + csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; + csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + e = UNSTUFF_BITS(resp, 47, 3); + m = UNSTUFF_BITS(resp, 62, 12); + csd->capacity = (1 + m) << (e + 2); + + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 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_partial = UNSTUFF_BITS(resp, 21, 1); + break; + case 1: + /* + * This is a block-addressed SDHC card. Most + * interesting fields are unused and have fixed + * values. To avoid getting tripped by buggy cards, + * we assume those fixed values ourselves. + */ + mmc_card_set_blockaddr(card); + + csd->tacc_ns = 0; /* Unused */ + csd->tacc_clks = 0; /* Unused */ + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + m = UNSTUFF_BITS(resp, 48, 22); + csd->capacity = (1 + m) << 10; + + csd->read_blkbits = 9; + csd->read_partial = 0; + csd->write_misalign = 0; + csd->read_misalign = 0; + csd->r2w_factor = 4; /* Unused */ + csd->write_blkbits = 9; + csd->write_partial = 0; + break; + default: printk("%s: unrecognised CSD structure version %d\n", mmc_hostname(card->host), csd_struct); mmc_card_set_bad(card); return; } - - m = UNSTUFF_BITS(resp, 115, 4); - e = UNSTUFF_BITS(resp, 112, 3); - csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; - csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; - - m = UNSTUFF_BITS(resp, 99, 4); - e = UNSTUFF_BITS(resp, 96, 3); - csd->max_dtr = tran_exp[e] * tran_mant[m]; - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); - - e = UNSTUFF_BITS(resp, 47, 3); - m = UNSTUFF_BITS(resp, 62, 12); - csd->capacity = (1 + m) << (e + 2); - - csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - csd->read_partial = UNSTUFF_BITS(resp, 79, 1); - csd->write_misalign = UNSTUFF_BITS(resp, 78, 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_partial = UNSTUFF_BITS(resp, 21, 1); } else { /* * We only understand CSD structure v1.1 and v1.2. @@ -721,6 +836,7 @@ host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); mmc_delay(1); @@ -740,6 +856,7 @@ host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); } @@ -799,6 +916,41 @@ return err; } +static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2) +{ + struct mmc_command cmd; + int err, sd2; + static const u8 test_pattern = 0xAA; + + /* + * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND + * before SD_APP_OP_COND. This command will harmlessly fail for + * SD 1.0 cards. + */ + cmd.opcode = SD_SEND_IF_COND; + cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; + cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err == MMC_ERR_NONE) { + if ((cmd.resp[0] & 0xFF) == test_pattern) { + sd2 = 1; + } else { + sd2 = 0; + err = MMC_ERR_FAILED; + } + } else { + /* + * Treat errors as SD 1.0 card. + */ + sd2 = 0; + err = MMC_ERR_NONE; + } + if (rsd2) + *rsd2 = sd2; + return err; +} + /* * Discover cards by requesting their CID. If this command * times out, it is not an error; there are no further cards @@ -905,7 +1057,7 @@ } } -static void mmc_read_scrs(struct mmc_host *host) +static void mmc_process_ext_csds(struct mmc_host *host) { int err; struct mmc_card *card; @@ -916,6 +1068,157 @@ struct scatterlist sg; + /* + * As the ext_csd is so large and mostly unused, we don't store the + * raw block in mmc_card. + */ + u8 *ext_csd; + ext_csd = kmalloc(512, GFP_KERNEL); + if (!ext_csd) { + printk("%s: could not allocate a buffer to receive the ext_csd." + "mmc v4 cards will be treated as v3.\n", + mmc_hostname(host)); + return; + } + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (mmc_card_sd(card)) + continue; + if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SEND_EXT_CSD; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 512; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, ext_csd, 512); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + if (card->csd.capacity == (4096 * 512)) { + printk(KERN_ERR "%s: unable to read EXT_CSD " + "on a possible high capacity card. " + "Card will be ignored.\n", + mmc_hostname(card->host)); + mmc_card_set_dead(card); + } else { + printk(KERN_WARNING "%s: unable to read " + "EXT_CSD, performance might " + "suffer.\n", + mmc_hostname(card->host)); + } + continue; + } + + card->ext_csd.sectors = + ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | + ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | + ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | + ext_csd[EXT_CSD_SEC_CNT + 3] << 24; + if (card->ext_csd.sectors > EXT_CSD_SEC_CNT_2GB) + mmc_card_set_blockaddr(card); + + switch (ext_csd[EXT_CSD_CARD_TYPE]) { + case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 52000000; + break; + case EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 26000000; + break; + default: + /* MMC v4 spec says this cannot happen */ + printk("%s: card is mmc v4 but doesn't support " + "any high-speed modes.\n", + mmc_hostname(card->host)); + continue; + } + + if (host->caps & MMC_CAP_MMC_HIGHSPEED) { + /* Activate highspeed support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_HS_TIMING << 16) | + (1 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to mmc v4 " + "high-speed mode.\n", + mmc_hostname(card->host)); + continue; + } + + mmc_card_set_highspeed(card); + + host->ios.timing = MMC_TIMING_MMC_HS; + mmc_set_ios(host); + } + + /* Check for host support for wide-bus modes. */ + if (host->caps & MMC_CAP_4_BIT_DATA) { + /* Activate 4-bit support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BUS_WIDTH << 16) | + (EXT_CSD_BUS_WIDTH_4 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to " + "mmc v4 4-bit bus mode.\n", + mmc_hostname(card->host)); + continue; + } + + host->ios.bus_width = MMC_BUS_WIDTH_4; + mmc_set_ios(host); + } + } + + kfree(ext_csd); + + mmc_deselect_cards(host); +} + +static void mmc_read_scrs(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + struct scatterlist sg; + list_for_each_entry(card, &host->cards, node) { if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) continue; @@ -948,9 +1251,8 @@ memset(&data, 0, sizeof(struct mmc_data)); - data.timeout_ns = card->csd.tacc_ns * 10; - data.timeout_clks = card->csd.tacc_clks * 10; - data.blksz_bits = 3; + mmc_set_data_timeout(&data, card, 0); + data.blksz = 1 << 3; data.blocks = 1; data.flags = MMC_DATA_READ; @@ -980,14 +1282,137 @@ mmc_deselect_cards(host); } +static void mmc_read_switch_caps(struct mmc_host *host) +{ + int err; + struct mmc_card *card; + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + unsigned char *status; + struct scatterlist sg; + + if (!(host->caps & MMC_CAP_SD_HIGHSPEED)) + return; + + status = kmalloc(64, GFP_KERNEL); + if (!status) { + printk(KERN_WARNING "%s: Unable to allocate buffer for " + "reading switch capabilities.\n", + mmc_hostname(host)); + return; + } + + list_for_each_entry(card, &host->cards, node) { + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) + continue; + if (!mmc_card_sd(card)) + continue; + if (card->scr.sda_vsn < SCR_SPEC_VER_1) + continue; + + err = mmc_select_card(host, card); + if (err != MMC_ERR_NONE) { + mmc_card_set_dead(card); + continue; + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_SWITCH; + cmd.arg = 0x00FFFFF1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, status, 64); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { + printk("%s: unable to read switch capabilities, " + "performance might suffer.\n", + mmc_hostname(card->host)); + continue; + } + + if (status[13] & 0x02) + card->sw_caps.hs_max_dtr = 50000000; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_SWITCH; + cmd.arg = 0x80FFFFF1; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + mmc_set_data_timeout(&data, card, 0); + + data.blksz = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, status, 64); + + mmc_wait_for_req(host, &mrq); + + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE || + (status[16] & 0xF) != 1) { + printk(KERN_WARNING "%s: Problem switching card " + "into high-speed mode!\n", + mmc_hostname(host)); + continue; + } + + mmc_card_set_highspeed(card); + + host->ios.timing = MMC_TIMING_SD_HS; + mmc_set_ios(host); + } + + kfree(status); + + mmc_deselect_cards(host); +} + static unsigned int mmc_calculate_clock(struct mmc_host *host) { struct mmc_card *card; unsigned int max_dtr = host->f_max; list_for_each_entry(card, &host->cards, node) - if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) - max_dtr = card->csd.max_dtr; + if (!mmc_card_dead(card) && !mmc_card_bad(card)) { + if (mmc_card_highspeed(card) && mmc_card_sd(card)) { + if (max_dtr > card->sw_caps.hs_max_dtr) + max_dtr = card->sw_caps.hs_max_dtr; + } else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) { + if (max_dtr > card->ext_csd.hs_max_dtr) + max_dtr = card->ext_csd.hs_max_dtr; + } else if (max_dtr > card->csd.max_dtr) { + max_dtr = card->csd.max_dtr; + } + } pr_debug("%s: selected %d.%03dMHz transfer rate\n", mmc_hostname(host), @@ -1029,7 +1454,8 @@ static void mmc_setup(struct mmc_host *host) { - if (host->ios.power_mode != MMC_POWER_ON) { + if (host->ios.power_mode != MMC_POWER_ON && + host->ios.power_mode != MMC_POWER_STANDBY) { int err; u32 ocr; @@ -1038,6 +1464,10 @@ mmc_power_up(host); mmc_idle_cards(host); + err = mmc_send_if_cond(host, host->ocr_avail, NULL); + if (err != MMC_ERR_NONE) { + return; + } err = mmc_send_app_op_cond(host, 0, &ocr); /* @@ -1090,10 +1520,22 @@ * all get the idea that they should be ready for CMD2. * (My SanDisk card seems to need this.) */ - if (host->mode == MMC_MODE_SD) - mmc_send_app_op_cond(host, host->ocr, NULL); - else - mmc_send_op_cond(host, host->ocr, NULL); + if (host->mode == MMC_MODE_SD) { + int err, sd2; + err = mmc_send_if_cond(host, host->ocr, &sd2); + if (err == MMC_ERR_NONE) { + /* + * If SD_SEND_IF_COND indicates an SD 2.0 + * compliant card and we should set bit 30 + * of the ocr to indicate that we can handle + * block-addressed SDHC cards. + */ + mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL); + } + } else { + /* The extra bit indicates that we support high capacity */ + mmc_send_op_cond(host, host->ocr | (1 << 30), NULL); + } mmc_discover_cards(host); @@ -1103,20 +1545,85 @@ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; mmc_set_ios(host); - /* - * Some already detected cards get confused in the card identification - * mode and futher commands can fail. Doing an extra status inquiry - * after the identification mode seems to get cards back to their - * senses. - */ - mmc_check_cards(host); - mmc_read_csds(host); - if (host->mode == MMC_MODE_SD) + if (host->mode == MMC_MODE_SD) { mmc_read_scrs(host); + mmc_read_switch_caps(host); + } else + mmc_process_ext_csds(host); } +/** + * mmc_idle_timer - + * @host: MMC host which completed request + * @mrq: MMC request which request + * + * MMC idle timer is set to run after any read or write request + * to put host standby mode once the cards are idle + */ +static void +mmc_idle_timer(unsigned long data) +{ + struct mmc_host *host = (struct mmc_host *)data; + schedule_work(&host->idle_work); +} + +/** + * mmc_idle_work - put host into standby mode + * @host: MMC host which completed request a while ago + * + * + */ +static void mmc_idle_work(void *data) +{ + struct mmc_host *host = data; + struct list_head *l, *n; + int busy; + + mmc_claim_host(host); + + if (host->ios.power_mode != MMC_POWER_ON && + host->ios.power_mode != MMC_POWER_STANDBY) + goto exit; + + mmc_deselect_cards(host); + busy = 0; + list_for_each_safe(l, n, &host->cards) { + struct mmc_card *card = mmc_list_to_card(l); + struct mmc_command cmd; + int err; + + if (mmc_card_dead(card) || + card->rq_state == R1_STATE_TRAN || + card->rq_state == R1_STATE_STBY) + continue; + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + mmc_detect_change(host, 0); + goto exit; + } + + card->rq_state = R1_CURRENT_STATE(cmd.resp[0]); + if (card->rq_state != R1_STATE_STBY) + busy = 1; + } + + if (busy) + mod_timer(&host->idle_timer, jiffies + host->idle_delay); + else { + host->ios.power_mode = MMC_POWER_STANDBY; + mmc_set_ios(host); + } + +exit: + mmc_release_host(host); +} /** * mmc_detect_change - process change of state on a MMC socket @@ -1129,9 +1636,9 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay) { if (delay) - schedule_delayed_work(&host->detect, delay); + mmc_schedule_delayed_work(&host->detect, delay); else - schedule_work(&host->detect); + mmc_schedule_work(&host->detect); } EXPORT_SYMBOL(mmc_detect_change); @@ -1141,14 +1648,18 @@ { struct mmc_host *host = data; struct list_head *l, *n; + unsigned char power_mode; mmc_claim_host(host); - if (host->ios.power_mode == MMC_POWER_ON) - mmc_check_cards(host); + power_mode = host->ios.power_mode; mmc_setup(host); + if (power_mode == MMC_POWER_ON || + power_mode == MMC_POWER_STANDBY) + mmc_check_cards(host); + if (!list_empty(&host->cards)) { /* * (Re-)calculate the fastest clock rate which the @@ -1209,14 +1720,22 @@ INIT_LIST_HEAD(&host->cards); INIT_WORK(&host->detect, mmc_rescan, host); + init_timer(&host->idle_timer); + host->idle_timer.function = mmc_idle_timer; + host->idle_timer.data = (unsigned long)host; + INIT_WORK(&host->idle_work, mmc_idle_work, host); + /* * By default, hosts do not support SGIO or large requests. * They have to set these according to their abilities. */ host->max_hw_segs = 1; host->max_phys_segs = 1; - host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9); host->max_seg_size = PAGE_CACHE_SIZE; + + host->max_req_size = PAGE_CACHE_SIZE; + host->max_blk_size = 512; + host->max_blk_count = PAGE_CACHE_SIZE / 512; } return host; @@ -1254,6 +1773,7 @@ { struct list_head *l, *n; + del_timer_sync(&host->idle_timer); list_for_each_safe(l, n, &host->cards) { struct mmc_card *card = mmc_list_to_card(l); @@ -1274,7 +1794,7 @@ */ void mmc_free_host(struct mmc_host *host) { - flush_scheduled_work(); + mmc_flush_scheduled_work(); mmc_free_host_sysfs(host); } @@ -1290,6 +1810,7 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state) { mmc_claim_host(host); + del_timer_sync(&host->idle_timer); mmc_deselect_cards(host); mmc_power_off(host); mmc_release_host(host); --- kernel-source-2.6.16-2.6.16.rel/drivers/mmc/mmc.h 2006-11-28 14:17:01.000000000 +0100 +++ kernel-source-2.6.16-2.6.16.my/drivers/mmc/mmc.h 2007-08-29 22:12:20.000000000 +0200 @@ -18,4 +18,8 @@ int mmc_add_host_sysfs(struct mmc_host *host); void mmc_remove_host_sysfs(struct mmc_host *host); void mmc_free_host_sysfs(struct mmc_host *host); + +int mmc_schedule_work(struct work_struct *work); +int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay); +void mmc_flush_scheduled_work(void); #endif --- kernel-source-2.6.16-2.6.16.rel/drivers/mmc/mmc_sysfs.c 2006-11-28 14:17:01.000000000 +0100 +++ kernel-source-2.6.16-2.6.16.my/drivers/mmc/mmc_sysfs.c 2007-08-29 21:48:13.000000000 +0200 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -317,10 +318,41 @@ class_device_put(&host->class_dev); } +static struct workqueue_struct *workqueue; + +/* + * Internal function. Schedule work in the MMC work queue. + */ +int mmc_schedule_work(struct work_struct *work) +{ + return queue_work(workqueue, work); +} + +/* + * Internal function. Schedule delayed work in the MMC work queue. + */ +int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay) +{ + return queue_delayed_work(workqueue, work, delay); +} + +/* + * Internal function. Flush all scheduled work from the MMC work queue. + */ +void mmc_flush_scheduled_work(void) +{ + flush_workqueue(workqueue); +} static int __init mmc_init(void) { - int ret = bus_register(&mmc_bus_type); + int ret; + + workqueue = create_singlethread_workqueue("kmmcd"); + if (!workqueue) + return -ENOMEM; + + ret = bus_register(&mmc_bus_type); if (ret == 0) { ret = class_register(&mmc_host_class); if (ret) @@ -333,6 +365,7 @@ { class_unregister(&mmc_host_class); bus_unregister(&mmc_bus_type); + destroy_workqueue(workqueue); } module_init(mmc_init); --- kernel-source-2.6.16-2.6.16.rel/drivers/mmc/mmc_queue.c 2006-11-28 14:17:01.000000000 +0100 +++ kernel-source-2.6.16-2.6.16.my/drivers/mmc/mmc_queue.c 2007-12-07 22:17:39.000000000 +0100 @@ -41,6 +41,8 @@ * Block I/O requests need translating according * to the protocol. */ + if (!mq) + return ret; ret = mq->prep_fn(mq, req); } else { /* @@ -111,6 +113,19 @@ static void mmc_request(request_queue_t *q) { struct mmc_queue *mq = q->queuedata; + struct request *req; + int ret; + + if (!mq) { + printk(KERN_ERR "MMC: killing requests for dead queue\n"); + while ((req = elv_next_request(q)) != NULL) { + do { + ret = end_that_request_chunk(req, 0, + req->current_nr_sectors << 9); + } while (ret); + } + return; + } if (!mq->req) wake_up(&mq->thread_wq); @@ -140,7 +155,7 @@ blk_queue_prep_rq(mq->queue, mmc_prep_request); blk_queue_bounce_limit(mq->queue, limit); - blk_queue_max_sectors(mq->queue, host->max_sectors); + blk_queue_max_sectors(mq->queue, host->max_req_size / 512); blk_queue_max_phys_segments(mq->queue, host->max_phys_segs); blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); @@ -152,7 +167,7 @@ GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; - goto cleanup; + goto cleanup_queue; } init_completion(&mq->thread_complete); @@ -167,10 +182,9 @@ goto out; } - cleanup: kfree(mq->sg); mq->sg = NULL; - + cleanup_queue: blk_cleanup_queue(mq->queue); out: return ret; @@ -179,6 +193,14 @@ void mmc_cleanup_queue(struct mmc_queue *mq) { + request_queue_t *q = mq->queue; + unsigned long flags; + + /* Mark that we should start throwing out stragglers */ + spin_lock_irqsave(q->queue_lock, flags); + q->queuedata = NULL; + spin_unlock_irqrestore(q->queue_lock, flags); + mq->flags |= MMC_QUEUE_EXIT; wake_up(&mq->thread_wq); wait_for_completion(&mq->thread_complete); --- kernel-source-2.6.16-2.6.16.rel/drivers/mmc/omap.c 2007-08-22 10:44:38.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/drivers/mmc/omap.c 2007-12-08 21:53:54.000000000 +0100 @@ -1,7 +1,7 @@ /* * linux/drivers/media/mmc/omap.c * - * Copyright (C) 2004 Nokia Corporation + * Copyright (C) 2004, 2007 Nokia Corporation * Written by Tuukka Tikkanen and Juha Yrjölä * Misc hacks here and there by Tony Lindgren * Other hacks (DMA, SD, etc) by David Brownell @@ -105,7 +105,7 @@ u16 saved_con; u16 bus_mode; unsigned int fclk_freq; - unsigned powered:1; + unsigned power_mode; struct work_struct cover_work; struct timer_list cover_timer; @@ -133,6 +133,9 @@ unsigned int phys_base; int irq; + struct work_struct cmd_abort; + struct timer_list cmd_timer; + unsigned int sg_len; int sg_idx; u16 * buffer; @@ -154,10 +157,12 @@ wait_queue_head_t slot_wq; int nr_slots; + int fclk_enabled; + struct omap_mmc_platform_data *pdata; }; -static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed) +static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed, int need_clock) { struct mmc_omap_host *host = slot->host; unsigned long flags; @@ -173,13 +178,25 @@ host->mmc = slot->mmc; spin_unlock_irqrestore(&host->slot_lock, flags); no_claim: - clk_enable(host->fclk); if (host->current_slot != slot) { if (host->pdata->switch_slot != NULL) host->pdata->switch_slot(mmc_dev(slot->mmc), slot->id); host->current_slot = slot; } - OMAP_MMC_WRITE(host, CON, slot->saved_con); + + if (need_clock) { + if (host->fclk_enabled == 0) { + host->fclk_enabled = 1; + clk_enable(host->fclk); + } + + /* Doing the dummy read here seems to work around some bug + * at least in OMAP24xx silicon where the command would not + * start after writing the CMD register. Sigh. */ + OMAP_MMC_READ(host, CON); + + OMAP_MMC_WRITE(host, CON, slot->saved_con); + } } static void mmc_omap_start_request(struct mmc_omap_host *host, @@ -192,7 +209,7 @@ int i; BUG_ON(slot == NULL || host->mmc == NULL); - clk_disable(host->fclk); + OMAP_MMC_WRITE(host, CON, slot->saved_con & 0xFC00); spin_lock_irqsave(&host->slot_lock, flags); /* Check for any pending requests */ @@ -209,7 +226,7 @@ host->mmc = new_slot->mmc; spin_unlock_irqrestore(&host->slot_lock, flags); - mmc_omap_select_slot(new_slot, 1); + mmc_omap_select_slot(new_slot, 1, 1); rq = new_slot->mrq; new_slot->mrq = NULL; mmc_omap_start_request(host, rq); @@ -321,6 +338,8 @@ if (host->data && !(host->data->flags & MMC_DATA_WRITE)) cmdreg |= 1 << 15; + mod_timer(&host->cmd_timer, jiffies + HZ/2); + OMAP_MMC_WRITE(host, CTO, 200); OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16); @@ -334,23 +353,30 @@ } static void +mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, + int abort) +{ + enum dma_data_direction dma_data_dir; + + BUG_ON(host->dma_ch < 0); + if (abort) + omap_stop_dma(host->dma_ch); + /* Release DMA channel lazily */ + mod_timer(&host->dma_timer, jiffies + HZ); + if (data->flags & MMC_DATA_WRITE) + dma_data_dir = DMA_TO_DEVICE; + else + dma_data_dir = DMA_FROM_DEVICE; + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, + dma_data_dir); +} + +static void mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) { - if (host->dma_in_use) { - enum dma_data_direction dma_data_dir; + if (host->dma_in_use) + mmc_omap_release_dma(host, data, data->error != MMC_ERR_NONE); - BUG_ON(host->dma_ch < 0); - if (data->error != MMC_ERR_NONE) - omap_stop_dma(host->dma_ch); - /* Release DMA channel lazily */ - mod_timer(&host->dma_timer, jiffies + HZ); - if (data->flags & MMC_DATA_WRITE) - dma_data_dir = DMA_TO_DEVICE; - else - dma_data_dir = DMA_FROM_DEVICE; - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, - dma_data_dir); - } host->data = NULL; host->sg_len = 0; @@ -373,6 +399,52 @@ } static void +mmc_omap_send_abort(struct mmc_omap_host *host) +{ + struct mmc_omap_slot *slot = host->current_slot; + unsigned int restarts, passes, timeout; + u16 stat = 0; + + /* Sending abort takes 80 clocks. Have some extra and round up */ + timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq; + restarts = 0; + while(restarts < 10000) { + OMAP_MMC_WRITE(host, STAT, 0xFFFF); + OMAP_MMC_WRITE(host, CMD, (3 << 12) | (1 << 7)); + + passes = 0; + while (passes < timeout) { + stat = OMAP_MMC_READ(host, STAT); + if (stat & OMAP_MMC_STAT_END_OF_CMD) + goto out; + udelay(1); + passes ++; + } + + restarts++; + } +out: + OMAP_MMC_WRITE(host, STAT, stat); +} + +static void +mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data) +{ + u16 ie; + + if (host->dma_in_use) + mmc_omap_release_dma(host, data, 1); + + host->data = NULL; + host->sg_len = 0; + + ie = OMAP_MMC_READ(host, IE); + OMAP_MMC_WRITE(host, IE, 0); + mmc_omap_send_abort(host); + OMAP_MMC_WRITE(host, IE, ie); +} + +static void mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) { unsigned long flags; @@ -425,6 +497,8 @@ { host->cmd = NULL; + del_timer(&host->cmd_timer); + if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { /* response type 2 */ @@ -451,6 +525,8 @@ if (host->data == NULL || cmd->error != MMC_ERR_NONE) { struct mmc_host *mmc; + if (host->data != NULL) + mmc_omap_abort_xfer(host, host->data); host->mrq = NULL; mmc = host->mmc; mmc_omap_release_slot(host->current_slot); @@ -458,6 +534,46 @@ } } +/* + * Abort stuck command. Can occur when card is removed while it is being + * read. + */ +static void mmc_omap_abort_command(void *data) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) data; + u16 ie; + + ie = OMAP_MMC_READ(host, IE); + OMAP_MMC_WRITE(host, IE, 0); + + if (!host->cmd) { + OMAP_MMC_WRITE(host, IE, ie); + return; + } + + dev_dbg(mmc_dev(host->mmc), "Aborting stuck command CMD%d\n", + host->cmd->opcode); + + if (host->data && host->dma_in_use) + mmc_omap_release_dma(host, host->data, 1); + + host->data = NULL; + host->sg_len = 0; + + mmc_omap_send_abort(host); + host->cmd->error = MMC_ERR_TIMEOUT; + mmc_omap_cmd_done(host, host->cmd); + OMAP_MMC_WRITE(host, IE, ie); +} + +static void +mmc_omap_cmd_timer(unsigned long data) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) data; + + schedule_work(&host->cmd_abort); +} + /* PIO only */ static void mmc_omap_sg_to_buf(struct mmc_omap_host *host) @@ -536,10 +652,16 @@ transfer_error = 0; while ((status = OMAP_MMC_READ(host, STAT)) != 0) { + int cmd; + OMAP_MMC_WRITE(host, STAT, status); + if (host->cmd != NULL) + cmd = host->cmd->opcode; + else + cmd = -1; #ifdef CONFIG_MMC_DEBUG - dev_info(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ", - status, host->cmd != NULL ? host->cmd->opcode : -1); + dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD%d): ", + status, cmd); mmc_omap_report_irq(status); printk("\n"); #endif @@ -551,12 +673,12 @@ mmc_omap_xfer_data(host, 1); } - if (status & OMAP_MMC_STAT_END_OF_DATA) { + if (status & OMAP_MMC_STAT_END_OF_DATA) end_transfer = 1; - } if (status & OMAP_MMC_STAT_DATA_TOUT) { - dev_dbg(mmc_dev(host->mmc), "data timeout\n"); + dev_err(mmc_dev(host->mmc), "data timeout (CMD%d)\n", + cmd); if (host->data) { host->data->error |= MMC_ERR_TIMEOUT; transfer_error = 1; @@ -566,12 +688,12 @@ if (status & OMAP_MMC_STAT_DATA_CRC) { if (host->data) { host->data->error |= MMC_ERR_BADCRC; - dev_dbg(mmc_dev(host->mmc), - "data CRC error, bytes left %d\n", - host->total_bytes_left); + dev_err(mmc_dev(host->mmc), + "data CRC error, bytes left %d (CMD%d)\n", + host->total_bytes_left, cmd); transfer_error = 1; } else { - dev_dbg(mmc_dev(host->mmc), "data CRC error\n"); + dev_err(mmc_dev(host->mmc), "data CRC error\n"); } } @@ -582,8 +704,8 @@ host->cmd->opcode != MMC_SEND_OP_COND && host->cmd->opcode != MMC_APP_CMD) dev_err(mmc_dev(host->mmc), - "command timeout, CMD %d\n", - host->cmd->opcode); + "command timeout (CMD%d)\n", + cmd); host->cmd->error = MMC_ERR_TIMEOUT; end_command = 1; } @@ -593,7 +715,7 @@ if (host->cmd) { dev_err(mmc_dev(host->mmc), "command CRC error (CMD%d, arg 0x%08x)\n", - host->cmd->opcode, host->cmd->arg); + cmd, host->cmd->arg); host->cmd->error = MMC_ERR_BADCRC; end_command = 1; } else @@ -614,8 +736,8 @@ } } - dev_dbg(mmc_dev(host->mmc), "card status error (CMD%d)\n", - host->cmd->opcode); + dev_err(mmc_dev(host->mmc), "card status error (CMD%d)\n", + cmd); if (host->cmd) { host->cmd->error = MMC_ERR_FAILED; end_command = 1; @@ -636,13 +758,14 @@ } } - if (end_command) { + if (end_command) mmc_omap_cmd_done(host, host->cmd); + if (host->data != NULL) { + if (transfer_error) + mmc_omap_xfer_done(host, host->data); + else if (end_transfer) + mmc_omap_end_of_data(host, host->data); } - if (transfer_error) - mmc_omap_xfer_done(host, host->data); - else if (end_transfer) - mmc_omap_end_of_data(host, host->data); return IRQ_HANDLED; } @@ -653,6 +776,10 @@ BUG_ON(slot >= host->nr_slots); + /* Other subsystems can call in here before we're initialised. */ + if (host->nr_slots == 0 || !host->slots[slot]) + return; + schedule_work(&host->slots[slot]->cover_work); } @@ -710,10 +837,10 @@ int sync_dev = 0; data_addr = host->phys_base + OMAP_MMC_REG_DATA; - frame = 1 << data->blksz_bits; + frame = data->blksz; count = sg_dma_len(sg); - if ((data->blocks == 1) && (count > (1 << data->blksz_bits))) + if ((data->blocks == 1) && (count > data->blksz)) count = frame; host->dma_len = count; @@ -901,7 +1028,7 @@ } - block_size = 1 << data->blksz_bits; + block_size = data->blksz; OMAP_MMC_WRITE(host, NBLK, data->blocks - 1); OMAP_MMC_WRITE(host, BLEN, block_size - 1); @@ -983,22 +1110,22 @@ } else host->mmc = mmc; spin_unlock_irqrestore(&host->slot_lock, flags); - mmc_omap_select_slot(slot, 1); + mmc_omap_select_slot(slot, 1, 1); mmc_omap_start_request(host, req); } -static void mmc_omap_set_power(struct mmc_omap_slot *slot, int power_on, int vdd) +static void mmc_omap_set_power(struct mmc_omap_slot *slot, int power_mode, int vdd) { struct mmc_omap_host *host; host = slot->host; if (slot->pdata->set_power != NULL) - slot->pdata->set_power(mmc_dev(slot->mmc), slot->id, power_on, vdd); + slot->pdata->set_power(mmc_dev(slot->mmc), slot->id, power_mode, vdd); if (cpu_is_omap24xx()) { u16 w; - if (power_on) { + if (power_mode != MMC_POWER_OFF) { w = OMAP_MMC_READ(host, CON); OMAP_MMC_WRITE(host, CON, w | (1 << 11)); } else { @@ -1008,12 +1135,31 @@ } } +static void mmc_omap_set_standby(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmc_omap_slot *slot = mmc_priv(mmc); + struct mmc_omap_host *host = slot->host; + mmc_omap_select_slot(slot, 0, 0); + mmc_omap_set_power(slot, MMC_POWER_STANDBY, ios->vdd); + slot->vdd = ios->vdd; + slot->power_mode = MMC_POWER_STANDBY; + if (host->fclk_enabled == 1) { + host->fclk_enabled = 0; + clk_disable(host->fclk); + } + mmc_omap_release_slot(slot); +} + static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmc_omap_slot *slot = mmc_priv(mmc); struct mmc_omap_host *host = slot->host; - int dsor, power_on; + int dsor, power_on, slot_powered; int i; + if (ios->power_mode == MMC_POWER_STANDBY) { + mmc_omap_set_standby(mmc, ios); + return; + } if (ios->clock != 0) { int freq, fclk_rate; @@ -1043,11 +1189,21 @@ else power_on = 0; - mmc_omap_select_slot(slot, 0); - if (slot->powered != power_on || ios->vdd != slot->vdd) { - mmc_omap_set_power(slot, power_on, ios->vdd); - slot->vdd = ios->vdd; - slot->powered = power_on; + mmc_omap_select_slot(slot, 0, 1); + + slot_powered = + slot->power_mode == MMC_POWER_ON || + slot->power_mode == MMC_POWER_UP; + + if (slot_powered != power_on || ios->vdd != slot->vdd) + mmc_omap_set_power(slot, ios->power_mode, ios->vdd); + + slot->vdd = ios->vdd; + slot->power_mode = ios->power_mode; + + if (!power_on && host->fclk_enabled) { + host->fclk_enabled = 0; + clk_disable(host->fclk); } if (power_on) @@ -1110,15 +1266,20 @@ host->slots[id] = slot; + mmc->caps = MMC_CAP_BYTEBLOCK | MMC_CAP_MULTIWRITE; + mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; + mmc->caps |= MMC_CAP_STANDBY; if (host->pdata->wire4) mmc->caps |= MMC_CAP_4_BIT_DATA; + mmc->idle_delay = HZ/2; + mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; - if (cpu_class_is_omap2()) +// if (cpu_class_is_omap2()) mmc->f_max = 48000000; - else - mmc->f_max = 24000000; +// else +// mmc->f_max = 24000000; if (host->pdata->max_freq) mmc->f_max = min(host->pdata->max_freq, mmc->f_max); mmc->ocr_avail = slot->pdata->ocr_mask; @@ -1129,8 +1290,10 @@ */ mmc->max_phys_segs = 32; mmc->max_hw_segs = 32; - mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */ - mmc->max_seg_size = mmc->max_sectors * 512; + mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */ + mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */ + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; r = mmc_add_host(mmc); if (r < 0) @@ -1205,6 +1368,11 @@ goto err_free_mem_region; } + INIT_WORK(&host->cmd_abort, mmc_omap_abort_command, host); + init_timer(&host->cmd_timer); + host->cmd_timer.function = mmc_omap_cmd_timer; + host->cmd_timer.data = (unsigned long) host; + spin_lock_init(&host->dma_lock); init_timer(&host->dma_timer); spin_lock_init(&host->slot_lock); @@ -1322,7 +1490,7 @@ int ret = 0, i; struct mmc_omap_host *host = platform_get_drvdata(pdev); - if (host == NULL || (host != NULL && host->suspended)) + if (host == NULL || host->suspended) return 0; for (i = 0; i < host->nr_slots; i++) { @@ -1347,7 +1515,7 @@ int ret = 0, i; struct mmc_omap_host *host = platform_get_drvdata(pdev); - if (host == NULL || (host != NULL && host->suspended)) + if (host == NULL || !host->suspended) return 0; for (i = 0; i < host->nr_slots; i++) { --- kernel-source-2.6.16-2.6.16.rel/arch/arm/mach-omap1/board-nokia770-mmc.c 2007-05-30 21:38:59.000000000 +0200 +++ kernel-source-2.6.16-2.6.16.my/arch/arm/mach-omap1/board-nokia770-mmc.c 2007-12-07 21:13:26.000000000 +0100 @@ -138,7 +138,7 @@ .enabled = 1, .nr_slots = 1, .wire4 = 0, - .max_freq = 12000000, + .max_freq = 48000000, .init = nokia770_mmc_late_init, .cleanup = nokia770_mmc_cleanup, .slots[0] = {