All of lore.kernel.org
 help / color / mirror / Atom feed
* MMC/eMMC partitioning support.
@ 2011-03-19 11:18 Andrei Warkentin
  2011-03-19 11:18 ` [RFC] MMC: MMC boot partitions support Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-19 11:18 UTC (permalink / raw)
  To: linux-mmc

MMC devices can have boot partitions, as well as a non-replayable
memory block and some general purpose partitions present. As of the moment,
these are not accessible from Linux. I'm sending a patch for comments and review to enable
the boot partitions.

The MMC partitions are effectively separate devices from the default-accessible user area
partition, hence, the extra partitions are exposed as separate block devices.

TOC:
[RFC] MMC: MMC boot partitions support.

Thanks,
A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC] MMC: MMC boot partitions support.
  2011-03-19 11:18 MMC/eMMC partitioning support Andrei Warkentin
@ 2011-03-19 11:18 ` Andrei Warkentin
  2011-03-19 12:13   ` Andrei Warkentin
                     ` (4 more replies)
  0 siblings, 5 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-19 11:18 UTC (permalink / raw)
  To: linux-mmc; +Cc: Andrei Warkentin

Allows device MMC boot partitions to be accessed. MMC partitions
are treated effectively as separate block devices on the same
MMC card.

Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 drivers/mmc/card/Kconfig   |   18 +++++
 drivers/mmc/card/block.c   |  183 ++++++++++++++++++++++++++++++++++----------
 drivers/mmc/core/mmc.c     |    5 +
 drivers/mmc/core/mmc_ops.h |    1 -
 include/linux/mmc/card.h   |    2 +
 include/linux/mmc/core.h   |    1 +
 include/linux/mmc/mmc.h    |    6 ++
 7 files changed, 174 insertions(+), 42 deletions(-)

diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 86948f9..f05e283 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -14,6 +14,24 @@ config MMC_BLOCK
 	  mount the filesystem. Almost everyone wishing MMC support
 	  should say Y or M here.
 
+config MMC_BLOCK_MMC_PART
+	tristate "MMC block MMC device partitioning support"
+	depends on BLOCK
+	default n
+	help
+	  Say Y here to enable access to MMC partitions other than
+	  the user area, such as the boot partitions. The other partitions
+	  will appear as separate mmcblk devices.
+
+config MMC_BLOCK_MMC_PART_BOOT
+	tristate "MMC block MMC boot partition support"
+	depends on MMC_BLOCK_MMC_PART
+	default n
+	help
+	  Say Y here to enable access to the MMC boot partitions. Boot
+	  partitions are used by some devices to store bootloader information.
+	  The boot partitions will appear as separate mmcblk devices.
+
 config MMC_BLOCK_BOUNCE
 	bool "Use bounce buffer for simple hosts"
 	depends on MMC_BLOCK
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 7054fd5..c691296 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -60,9 +60,11 @@ struct mmc_blk_data {
 	spinlock_t	lock;
 	struct gendisk	*disk;
 	struct mmc_queue queue;
+	struct list_head part;
 
 	unsigned int	usage;
 	unsigned int	read_only;
+	unsigned int    part_type;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -153,6 +155,18 @@ struct mmc_blk_request {
 	struct mmc_data		data;
 };
 
+static int mmc_blk_part_switch(struct mmc_card *card, unsigned int part_type)
+{
+	if (mmc_card_mmc(card)) {
+		card->ext_csd.part_cfg &= ~EXT_CSD_PCFG_ACC_MASK;
+		card->ext_csd.part_cfg |= part_type;
+
+		return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				  EXT_CSD_PCFG, card->ext_csd.part_cfg);
+	}
+	return 0;
+}
+
 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 {
 	int err;
@@ -250,8 +264,6 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_erase(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -271,8 +283,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -284,8 +294,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_secure_erase_trim(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -307,8 +315,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -319,8 +325,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 	struct mmc_blk_request brq;
 	int ret = 1, disable_multi = 0;
 
-	mmc_claim_host(card->host);
-
 	do {
 		struct mmc_command cmd;
 		u32 readcmd, writecmd, status = 0;
@@ -504,8 +508,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	} while (ret);
 
-	mmc_release_host(card->host);
-
 	return 1;
 
  cmd_err:
@@ -532,8 +534,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	}
 
-	mmc_release_host(card->host);
-
 	spin_lock_irq(&md->lock);
 	while (ret)
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
@@ -547,6 +547,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card);
 
 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
+	int ret;
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
@@ -557,14 +558,25 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 	}
 #endif
 
+	mmc_claim_host(card->host);
+
+	if (md->part_type)
+		mmc_blk_part_switch(card, md->part_type);
+
 	if (req->cmd_flags & REQ_DISCARD) {
 		if (req->cmd_flags & REQ_SECURE)
-			return mmc_blk_issue_secdiscard_rq(mq, req);
+			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
-			return mmc_blk_issue_discard_rq(mq, req);
+			ret = mmc_blk_issue_discard_rq(mq, req);
 	} else {
-		return mmc_blk_issue_rw_rq(mq, req);
+		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
+
+	if (md->part_type)
+		mmc_blk_part_switch(card, 0);
+
+	mmc_release_host(card->host);
+	return ret;
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -573,7 +585,8 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
 	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
 }
 
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+					      sector_t size)
 {
 	struct mmc_blk_data *md;
 	int devidx, ret;
@@ -589,7 +602,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 		goto out;
 	}
 
-
 	/*
 	 * Set the read-only status based on the supported commands
 	 * and the write protect switch.
@@ -603,6 +615,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	}
 
 	spin_lock_init(&md->lock);
+	INIT_LIST_HEAD(&md->part);
 	md->usage = 1;
 
 	ret = mmc_init_queue(&md->queue, card, &md->lock);
@@ -635,29 +648,82 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	sprintf(md->disk->disk_name, "mmcblk%d", devidx);
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
+	set_capacity(md->disk, size);
+	return md;
+
+ err_putdisk:
+	put_disk(md->disk);
+ err_kfree:
+	kfree(md);
+ out:
+	return ERR_PTR(ret);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+	sector_t size;
+	struct mmc_blk_data *md;
 
 	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);
+		size = 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));
+		size = card->csd.capacity << (card->csd.read_blkbits - 9);
 	}
+
+	md = mmc_blk_alloc_req(card, size);
+	md->part_type = 0;
 	return md;
+}
 
- err_putdisk:
-	put_disk(md->disk);
- err_kfree:
-	kfree(md);
- out:
-	return ERR_PTR(ret);
+static int mmc_blk_alloc_part(struct mmc_card *card, struct mmc_blk_data *md,
+			      unsigned int part_type, sector_t size)
+{
+	char cap_str[10];
+	struct mmc_blk_data *part_md;
+
+	part_md = mmc_blk_alloc_req(card, size);
+	if (IS_ERR(part_md))
+		return PTR_ERR(part_md);
+	part_md->part_type = part_type;
+	list_add(&part_md->part, &md->part);
+
+	string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
+			cap_str, sizeof(cap_str));
+	printk(KERN_INFO "%s: %s %s partition %u %s\n",
+	       part_md->disk->disk_name, mmc_card_id(card),
+	       mmc_card_name(card), part_md->part_type, cap_str);
+	return 0;
+}
+
+static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
+{
+	int ret;
+
+	if (!mmc_card_mmc(card))
+		return 0;
+
+#ifdef CONFIG_MMC_BLOCK_MMC_PART_BOOT
+	if (card->ext_csd.boot_size) {
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PCFG_ACC_BOOT0,
+					 card->ext_csd.boot_size >> 9);
+		if (ret)
+			return ret;
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PCFG_ACC_BOOT1,
+					 card->ext_csd.boot_size >> 9);
+		if (ret)
+			return ret;
+	}
+#endif
+
+	return 0;
 }
 
 static int
@@ -686,9 +752,37 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 	return 0;
 }
 
+static void mmc_blk_remove_req(struct mmc_blk_data *md, bool del_disk)
+{
+	if (md) {
+		if (del_disk) {
+
+			/* Stop new requests from getting into the queue */
+			del_gendisk(md->disk);
+		}
+
+		/* Then flush out any already in there */
+		mmc_cleanup_queue(&md->queue);
+		mmc_blk_put(md);
+	}
+}
+
+static void mmc_blk_remove_parts(struct mmc_card *card,
+				 struct mmc_blk_data *md, bool del_disk)
+{
+	struct list_head *pos, *q;
+	struct mmc_blk_data *part_md;
+
+	list_for_each_safe(pos, q, &md->part) {
+		part_md = list_entry(pos, struct mmc_blk_data, part);
+		list_del(pos);
+		mmc_blk_remove_req(part_md, del_disk);
+	}
+}
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
-	struct mmc_blk_data *md;
+	struct mmc_blk_data *md, *part_md;
 	int err;
 
 	char cap_str[10];
@@ -713,17 +807,23 @@ static int mmc_blk_probe(struct mmc_card *card)
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
 		cap_str, md->read_only ? "(ro)" : "");
 
+	if (mmc_blk_alloc_parts(card, md))
+		goto out;
+
 	mmc_set_drvdata(card, md);
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 	mmc_set_bus_resume_policy(card->host, 1);
 #endif
 	add_disk(md->disk);
+
+	list_for_each_entry(part_md, &md->part, part) {
+		add_disk(part_md->disk);
+	}
 	return 0;
 
  out:
-	mmc_cleanup_queue(&md->queue);
-	mmc_blk_put(md);
-
+	mmc_blk_remove_parts(card, md, false);
+	mmc_blk_remove_req(md, false);
 	return err;
 }
 
@@ -731,15 +831,8 @@ static void mmc_blk_remove(struct mmc_card *card)
 {
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
-	if (md) {
-		/* Stop new requests from getting into the queue */
-		del_gendisk(md->disk);
-
-		/* Then flush out any already in there */
-		mmc_cleanup_queue(&md->queue);
-
-		mmc_blk_put(md);
-	}
+	mmc_blk_remove_parts(card, md, true);
+	mmc_blk_remove_req(md, true);
 	mmc_set_drvdata(card, NULL);
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 	mmc_set_bus_resume_policy(card->host, 0);
@@ -749,16 +842,21 @@ static void mmc_blk_remove(struct mmc_card *card)
 #ifdef CONFIG_PM
 static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_queue_suspend(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_suspend(&part_md->queue);
+		}
 	}
 	return 0;
 }
 
 static int mmc_blk_resume(struct mmc_card *card)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
@@ -766,6 +864,9 @@ static int mmc_blk_resume(struct mmc_card *card)
 		mmc_blk_set_blksize(md, card);
 #endif
 		mmc_queue_resume(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_resume(&part_md->queue);
+		}
 	}
 	return 0;
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6909a54..3d757aa 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -284,6 +284,11 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 			ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
 		card->ext_csd.hc_erase_size =
 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
+
+
+		/* There are two boot regions of equal size */
+		card->ext_csd.part_cfg = ext_csd[EXT_CSD_PCFG];
+		card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] * SZ_128K;
 	}
 
 	if (card->ext_csd.rev >= 4) {
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 653eb8e..b1a806f 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_set_relative_addr(struct mmc_card *card);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index fe9d7be..0911552 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -45,6 +45,7 @@ struct mmc_ext_csd {
 	u8			rev;
 	u8			erase_group_def;
 	u8			sec_feature_support;
+	u8			part_cfg;
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
@@ -53,6 +54,7 @@ struct mmc_ext_csd {
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
 	unsigned int		sec_erase_mult;	/* Secure erase multiplier */
 	unsigned int		trim_timeout;		/* In milliseconds */
+	unsigned int		boot_size;  /* in bytes */
 };
 
 struct sd_scr {
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 7429033..a6cd7c3 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -135,6 +135,7 @@ extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
 	struct mmc_command *, int);
+extern int mmc_switch(struct mmc_card *, u8, u8, u8);
 
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index dd11ae5..9442cbc 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -252,6 +252,7 @@ struct _mmc_csd {
  */
 
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
+#define EXT_CSD_PCFG			179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
@@ -262,6 +263,7 @@ struct _mmc_csd {
 #define EXT_CSD_S_A_TIMEOUT		217	/* RO */
 #define EXT_CSD_ERASE_TIMEOUT_MULT	223	/* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE	224	/* RO */
+#define EXT_CSD_BOOT_MULT		226	/* RO */
 #define EXT_CSD_SEC_TRIM_MULT		229	/* RO */
 #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
@@ -271,6 +273,10 @@ struct _mmc_csd {
  * EXT_CSD field definitions
  */
 
+#define EXT_CSD_PCFG_ACC_MASK           (0x7)
+#define EXT_CSD_PCFG_ACC_BOOT0          (0x1)
+#define EXT_CSD_PCFG_ACC_BOOT1          (0x2)
+
 #define EXT_CSD_CMD_SET_NORMAL		(1<<0)
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [RFC] MMC: MMC boot partitions support.
  2011-03-19 11:18 ` [RFC] MMC: MMC boot partitions support Andrei Warkentin
@ 2011-03-19 12:13   ` Andrei Warkentin
  2011-03-21 14:19   ` [PATCH] " Andrei Warkentin
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-19 12:13 UTC (permalink / raw)
  To: linux-mmc; +Cc: Andrei Warkentin

On Sat, Mar 19, 2011 at 6:18 AM, Andrei Warkentin <andreiw@motorola.com> wrote:
> Allows device MMC boot partitions to be accessed. MMC partitions
> are treated effectively as separate block devices on the same
> MMC card.
>
> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>

Oops, sorry, sent the wrong commit. Please ignore lack of error
checking around mmc_blk_part_switch inside issue_rq :<.

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH] MMC: MMC boot partitions support.
  2011-03-19 11:18 ` [RFC] MMC: MMC boot partitions support Andrei Warkentin
  2011-03-19 12:13   ` Andrei Warkentin
@ 2011-03-21 14:19   ` Andrei Warkentin
  2011-03-22  3:54   ` [PATCHv3] " Andrei Warkentin
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-21 14:19 UTC (permalink / raw)
  To: linux-mmc; +Cc: Andrei Warkentin

Allows device MMC boot partitions to be accessed. MMC partitions
are treated effectively as separate block devices on the same
MMC card.

Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 drivers/mmc/card/Kconfig   |   18 ++++
 drivers/mmc/card/block.c   |  206 +++++++++++++++++++++++++++++++++++---------
 drivers/mmc/core/mmc.c     |    5 +
 drivers/mmc/core/mmc_ops.h |    1 -
 include/linux/mmc/card.h   |    2 +
 include/linux/mmc/core.h   |    1 +
 include/linux/mmc/mmc.h    |    6 ++
 7 files changed, 197 insertions(+), 42 deletions(-)

diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 86948f9..f05e283 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -14,6 +14,24 @@ config MMC_BLOCK
 	  mount the filesystem. Almost everyone wishing MMC support
 	  should say Y or M here.
 
+config MMC_BLOCK_MMC_PART
+	tristate "MMC block MMC device partitioning support"
+	depends on BLOCK
+	default n
+	help
+	  Say Y here to enable access to MMC partitions other than
+	  the user area, such as the boot partitions. The other partitions
+	  will appear as separate mmcblk devices.
+
+config MMC_BLOCK_MMC_PART_BOOT
+	tristate "MMC block MMC boot partition support"
+	depends on MMC_BLOCK_MMC_PART
+	default n
+	help
+	  Say Y here to enable access to the MMC boot partitions. Boot
+	  partitions are used by some devices to store bootloader information.
+	  The boot partitions will appear as separate mmcblk devices.
+
 config MMC_BLOCK_BOUNCE
 	bool "Use bounce buffer for simple hosts"
 	depends on MMC_BLOCK
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 7054fd5..87355d4 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -60,9 +60,18 @@ struct mmc_blk_data {
 	spinlock_t	lock;
 	struct gendisk	*disk;
 	struct mmc_queue queue;
+	struct list_head part;
 
 	unsigned int	usage;
 	unsigned int	read_only;
+	unsigned int    part_type;
+
+	/*
+	   Only set in main mmc_blk_data associated
+	   with mmc_card with mmc_set_drvdata, and keeps
+	   track of the current selected device partition.
+	*/
+	unsigned int    part_curr;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -153,6 +162,28 @@ struct mmc_blk_request {
 	struct mmc_data		data;
 };
 
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+				      struct mmc_blk_data *md)
+{
+	int ret;
+	struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+	if (main_md->part_curr == md->part_type)
+		return 0;
+
+	if (mmc_card_mmc(card)) {
+		card->ext_csd.part_cfg &= ~EXT_CSD_PCFG_ACC_MASK;
+		card->ext_csd.part_cfg |= md->part_type;
+
+		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_PCFG, card->ext_csd.part_cfg);
+		if (ret)
+			return ret;
+	}
+
+	main_md->part_curr = md->part_type;
+	return 0;
+}
+
 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 {
 	int err;
@@ -250,8 +281,6 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_erase(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -271,8 +300,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -284,8 +311,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_secure_erase_trim(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -307,8 +332,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -319,8 +342,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 	struct mmc_blk_request brq;
 	int ret = 1, disable_multi = 0;
 
-	mmc_claim_host(card->host);
-
 	do {
 		struct mmc_command cmd;
 		u32 readcmd, writecmd, status = 0;
@@ -504,8 +525,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	} while (ret);
 
-	mmc_release_host(card->host);
-
 	return 1;
 
  cmd_err:
@@ -532,8 +551,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	}
 
-	mmc_release_host(card->host);
-
 	spin_lock_irq(&md->lock);
 	while (ret)
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
@@ -547,6 +564,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card);
 
 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
+	int ret;
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
@@ -557,14 +575,23 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 	}
 #endif
 
+	mmc_claim_host(card->host);
+	ret = mmc_blk_part_switch(card, md);
+	if (ret)
+		goto out;
+
 	if (req->cmd_flags & REQ_DISCARD) {
 		if (req->cmd_flags & REQ_SECURE)
-			return mmc_blk_issue_secdiscard_rq(mq, req);
+			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
-			return mmc_blk_issue_discard_rq(mq, req);
+			ret = mmc_blk_issue_discard_rq(mq, req);
 	} else {
-		return mmc_blk_issue_rw_rq(mq, req);
+		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
+
+out:
+	mmc_release_host(card->host);
+	return ret;
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -573,7 +600,8 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
 	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
 }
 
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+					      sector_t size)
 {
 	struct mmc_blk_data *md;
 	int devidx, ret;
@@ -589,7 +617,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 		goto out;
 	}
 
-
 	/*
 	 * Set the read-only status based on the supported commands
 	 * and the write protect switch.
@@ -603,6 +630,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	}
 
 	spin_lock_init(&md->lock);
+	INIT_LIST_HEAD(&md->part);
 	md->usage = 1;
 
 	ret = mmc_init_queue(&md->queue, card, &md->lock);
@@ -635,29 +663,84 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	sprintf(md->disk->disk_name, "mmcblk%d", devidx);
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
+	set_capacity(md->disk, size);
+	return md;
+
+ err_putdisk:
+	put_disk(md->disk);
+ err_kfree:
+	kfree(md);
+ out:
+	return ERR_PTR(ret);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+	sector_t size;
+	struct mmc_blk_data *md;
 
 	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);
+		size = 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));
+		size = card->csd.capacity << (card->csd.read_blkbits - 9);
 	}
+
+	md = mmc_blk_alloc_req(card, size);
+	md->part_type = 0;
 	return md;
+}
 
- err_putdisk:
-	put_disk(md->disk);
- err_kfree:
-	kfree(md);
- out:
-	return ERR_PTR(ret);
+static int __maybe_unused mmc_blk_alloc_part(struct mmc_card *card,
+					     struct mmc_blk_data *md,
+					     unsigned int part_type,
+					     sector_t size)
+{
+	char cap_str[10];
+	struct mmc_blk_data *part_md;
+
+	part_md = mmc_blk_alloc_req(card, size);
+	if (IS_ERR(part_md))
+		return PTR_ERR(part_md);
+	part_md->part_type = part_type;
+	list_add(&part_md->part, &md->part);
+
+	string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
+			cap_str, sizeof(cap_str));
+	printk(KERN_INFO "%s: %s %s partition %u %s\n",
+	       part_md->disk->disk_name, mmc_card_id(card),
+	       mmc_card_name(card), part_md->part_type, cap_str);
+	return 0;
+}
+
+static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
+{
+	int ret = 0;
+
+	if (!mmc_card_mmc(card))
+		return 0;
+
+#ifdef CONFIG_MMC_BLOCK_MMC_PART_BOOT
+	if (card->ext_csd.boot_size) {
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PCFG_ACC_BOOT0,
+					 card->ext_csd.boot_size >> 9);
+		if (ret)
+			return ret;
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PCFG_ACC_BOOT1,
+					 card->ext_csd.boot_size >> 9);
+		if (ret)
+			return ret;
+	}
+#endif
+
+	return ret;
 }
 
 static int
@@ -686,9 +769,37 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 	return 0;
 }
 
+static void mmc_blk_remove_req(struct mmc_blk_data *md, bool del_disk)
+{
+	if (md) {
+		if (del_disk) {
+
+			/* Stop new requests from getting into the queue */
+			del_gendisk(md->disk);
+		}
+
+		/* Then flush out any already in there */
+		mmc_cleanup_queue(&md->queue);
+		mmc_blk_put(md);
+	}
+}
+
+static void mmc_blk_remove_parts(struct mmc_card *card,
+				 struct mmc_blk_data *md, bool del_disk)
+{
+	struct list_head *pos, *q;
+	struct mmc_blk_data *part_md;
+
+	list_for_each_safe(pos, q, &md->part) {
+		part_md = list_entry(pos, struct mmc_blk_data, part);
+		list_del(pos);
+		mmc_blk_remove_req(part_md, del_disk);
+	}
+}
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
-	struct mmc_blk_data *md;
+	struct mmc_blk_data *md, *part_md;
 	int err;
 
 	char cap_str[10];
@@ -713,17 +824,23 @@ static int mmc_blk_probe(struct mmc_card *card)
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
 		cap_str, md->read_only ? "(ro)" : "");
 
+	if (mmc_blk_alloc_parts(card, md))
+		goto out;
+
 	mmc_set_drvdata(card, md);
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 	mmc_set_bus_resume_policy(card->host, 1);
 #endif
 	add_disk(md->disk);
+
+	list_for_each_entry(part_md, &md->part, part) {
+		add_disk(part_md->disk);
+	}
 	return 0;
 
  out:
-	mmc_cleanup_queue(&md->queue);
-	mmc_blk_put(md);
-
+	mmc_blk_remove_parts(card, md, false);
+	mmc_blk_remove_req(md, false);
 	return err;
 }
 
@@ -731,15 +848,8 @@ static void mmc_blk_remove(struct mmc_card *card)
 {
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
-	if (md) {
-		/* Stop new requests from getting into the queue */
-		del_gendisk(md->disk);
-
-		/* Then flush out any already in there */
-		mmc_cleanup_queue(&md->queue);
-
-		mmc_blk_put(md);
-	}
+	mmc_blk_remove_parts(card, md, true);
+	mmc_blk_remove_req(md, true);
 	mmc_set_drvdata(card, NULL);
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 	mmc_set_bus_resume_policy(card->host, 0);
@@ -749,23 +859,37 @@ static void mmc_blk_remove(struct mmc_card *card)
 #ifdef CONFIG_PM
 static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_queue_suspend(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_suspend(&part_md->queue);
+		}
 	}
 	return 0;
 }
 
 static int mmc_blk_resume(struct mmc_card *card)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 #ifndef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 		mmc_blk_set_blksize(md, card);
 #endif
+
+		/*
+		  Resume involves the card going into idle state,
+		  so current partition is always the main one.
+		 */
+		md->part_curr = md->part_type;
 		mmc_queue_resume(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_resume(&part_md->queue);
+		}
 	}
 	return 0;
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6909a54..3d757aa 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -284,6 +284,11 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 			ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
 		card->ext_csd.hc_erase_size =
 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
+
+
+		/* There are two boot regions of equal size */
+		card->ext_csd.part_cfg = ext_csd[EXT_CSD_PCFG];
+		card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] * SZ_128K;
 	}
 
 	if (card->ext_csd.rev >= 4) {
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 653eb8e..b1a806f 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_set_relative_addr(struct mmc_card *card);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index fe9d7be..0911552 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -45,6 +45,7 @@ struct mmc_ext_csd {
 	u8			rev;
 	u8			erase_group_def;
 	u8			sec_feature_support;
+	u8			part_cfg;
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
@@ -53,6 +54,7 @@ struct mmc_ext_csd {
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
 	unsigned int		sec_erase_mult;	/* Secure erase multiplier */
 	unsigned int		trim_timeout;		/* In milliseconds */
+	unsigned int		boot_size;  /* in bytes */
 };
 
 struct sd_scr {
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 7429033..a6cd7c3 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -135,6 +135,7 @@ extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
 	struct mmc_command *, int);
+extern int mmc_switch(struct mmc_card *, u8, u8, u8);
 
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index dd11ae5..9442cbc 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -252,6 +252,7 @@ struct _mmc_csd {
  */
 
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
+#define EXT_CSD_PCFG			179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
@@ -262,6 +263,7 @@ struct _mmc_csd {
 #define EXT_CSD_S_A_TIMEOUT		217	/* RO */
 #define EXT_CSD_ERASE_TIMEOUT_MULT	223	/* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE	224	/* RO */
+#define EXT_CSD_BOOT_MULT		226	/* RO */
 #define EXT_CSD_SEC_TRIM_MULT		229	/* RO */
 #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
@@ -271,6 +273,10 @@ struct _mmc_csd {
  * EXT_CSD field definitions
  */
 
+#define EXT_CSD_PCFG_ACC_MASK           (0x7)
+#define EXT_CSD_PCFG_ACC_BOOT0          (0x1)
+#define EXT_CSD_PCFG_ACC_BOOT1          (0x2)
+
 #define EXT_CSD_CMD_SET_NORMAL		(1<<0)
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCHv3] MMC: MMC boot partitions support.
  2011-03-19 11:18 ` [RFC] MMC: MMC boot partitions support Andrei Warkentin
  2011-03-19 12:13   ` Andrei Warkentin
  2011-03-21 14:19   ` [PATCH] " Andrei Warkentin
@ 2011-03-22  3:54   ` Andrei Warkentin
  2011-03-22 21:11   ` MMC partitions support (4th revision) Andrei Warkentin
  2011-03-22 21:11   ` [PATCHv4] MMC: MMC boot partitions support Andrei Warkentin
  4 siblings, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-22  3:54 UTC (permalink / raw)
  To: linux-mmc; +Cc: Andrei Warkentin

Allows device MMC boot partitions to be accessed. MMC partitions
are treated effectively as separate block devices on the same
MMC card.

Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 drivers/mmc/card/Kconfig   |   18 ++++
 drivers/mmc/card/block.c   |  208 +++++++++++++++++++++++++++++++++++---------
 drivers/mmc/core/mmc.c     |    5 +
 drivers/mmc/core/mmc_ops.h |    1 -
 include/linux/mmc/card.h   |    2 +
 include/linux/mmc/core.h   |    1 +
 include/linux/mmc/mmc.h    |    6 ++
 7 files changed, 199 insertions(+), 42 deletions(-)

diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 86948f9..f05e283 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -14,6 +14,24 @@ config MMC_BLOCK
 	  mount the filesystem. Almost everyone wishing MMC support
 	  should say Y or M here.
 
+config MMC_BLOCK_MMC_PART
+	tristate "MMC block MMC device partitioning support"
+	depends on BLOCK
+	default n
+	help
+	  Say Y here to enable access to MMC partitions other than
+	  the user area, such as the boot partitions. The other partitions
+	  will appear as separate mmcblk devices.
+
+config MMC_BLOCK_MMC_PART_BOOT
+	tristate "MMC block MMC boot partition support"
+	depends on MMC_BLOCK_MMC_PART
+	default n
+	help
+	  Say Y here to enable access to the MMC boot partitions. Boot
+	  partitions are used by some devices to store bootloader information.
+	  The boot partitions will appear as separate mmcblk devices.
+
 config MMC_BLOCK_BOUNCE
 	bool "Use bounce buffer for simple hosts"
 	depends on MMC_BLOCK
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 7054fd5..ca18218 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -60,9 +60,18 @@ struct mmc_blk_data {
 	spinlock_t	lock;
 	struct gendisk	*disk;
 	struct mmc_queue queue;
+	struct list_head part;
 
 	unsigned int	usage;
 	unsigned int	read_only;
+	unsigned int    part_type;
+
+	/*
+	   Only set in main mmc_blk_data associated
+	   with mmc_card with mmc_set_drvdata, and keeps
+	   track of the current selected device partition.
+	*/
+	unsigned int    part_curr;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -153,6 +162,28 @@ struct mmc_blk_request {
 	struct mmc_data		data;
 };
 
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+				      struct mmc_blk_data *md)
+{
+	int ret;
+	struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+	if (main_md->part_curr == md->part_type)
+		return 0;
+
+	if (mmc_card_mmc(card)) {
+		card->ext_csd.part_cfg &= ~EXT_CSD_PCFG_ACC_MASK;
+		card->ext_csd.part_cfg |= md->part_type;
+
+		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_PCFG, card->ext_csd.part_cfg);
+		if (ret)
+			return ret;
+	}
+
+	main_md->part_curr = md->part_type;
+	return 0;
+}
+
 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 {
 	int err;
@@ -250,8 +281,6 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_erase(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -271,8 +300,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -284,8 +311,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_secure_erase_trim(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -307,8 +332,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -319,8 +342,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 	struct mmc_blk_request brq;
 	int ret = 1, disable_multi = 0;
 
-	mmc_claim_host(card->host);
-
 	do {
 		struct mmc_command cmd;
 		u32 readcmd, writecmd, status = 0;
@@ -504,8 +525,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	} while (ret);
 
-	mmc_release_host(card->host);
-
 	return 1;
 
  cmd_err:
@@ -532,8 +551,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	}
 
-	mmc_release_host(card->host);
-
 	spin_lock_irq(&md->lock);
 	while (ret)
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
@@ -547,6 +564,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card);
 
 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
+	int ret;
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
@@ -557,14 +575,25 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 	}
 #endif
 
+	mmc_claim_host(card->host);
+	ret = mmc_blk_part_switch(card, md);
+	if (ret) {
+		ret = 0;
+		goto out;
+	}
+
 	if (req->cmd_flags & REQ_DISCARD) {
 		if (req->cmd_flags & REQ_SECURE)
-			return mmc_blk_issue_secdiscard_rq(mq, req);
+			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
-			return mmc_blk_issue_discard_rq(mq, req);
+			ret = mmc_blk_issue_discard_rq(mq, req);
 	} else {
-		return mmc_blk_issue_rw_rq(mq, req);
+		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
+
+out:
+	mmc_release_host(card->host);
+	return ret;
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -573,7 +602,8 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
 	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
 }
 
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+					      sector_t size)
 {
 	struct mmc_blk_data *md;
 	int devidx, ret;
@@ -589,7 +619,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 		goto out;
 	}
 
-
 	/*
 	 * Set the read-only status based on the supported commands
 	 * and the write protect switch.
@@ -603,6 +632,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	}
 
 	spin_lock_init(&md->lock);
+	INIT_LIST_HEAD(&md->part);
 	md->usage = 1;
 
 	ret = mmc_init_queue(&md->queue, card, &md->lock);
@@ -635,29 +665,84 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	sprintf(md->disk->disk_name, "mmcblk%d", devidx);
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
+	set_capacity(md->disk, size);
+	return md;
+
+ err_putdisk:
+	put_disk(md->disk);
+ err_kfree:
+	kfree(md);
+ out:
+	return ERR_PTR(ret);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+	sector_t size;
+	struct mmc_blk_data *md;
 
 	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);
+		size = 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));
+		size = card->csd.capacity << (card->csd.read_blkbits - 9);
 	}
+
+	md = mmc_blk_alloc_req(card, size);
+	md->part_type = 0;
 	return md;
+}
 
- err_putdisk:
-	put_disk(md->disk);
- err_kfree:
-	kfree(md);
- out:
-	return ERR_PTR(ret);
+static int __maybe_unused mmc_blk_alloc_part(struct mmc_card *card,
+					     struct mmc_blk_data *md,
+					     unsigned int part_type,
+					     sector_t size)
+{
+	char cap_str[10];
+	struct mmc_blk_data *part_md;
+
+	part_md = mmc_blk_alloc_req(card, size);
+	if (IS_ERR(part_md))
+		return PTR_ERR(part_md);
+	part_md->part_type = part_type;
+	list_add(&part_md->part, &md->part);
+
+	string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
+			cap_str, sizeof(cap_str));
+	printk(KERN_INFO "%s: %s %s partition %u %s\n",
+	       part_md->disk->disk_name, mmc_card_id(card),
+	       mmc_card_name(card), part_md->part_type, cap_str);
+	return 0;
+}
+
+static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
+{
+	int ret = 0;
+
+	if (!mmc_card_mmc(card))
+		return 0;
+
+#ifdef CONFIG_MMC_BLOCK_MMC_PART_BOOT
+	if (card->ext_csd.boot_size) {
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PCFG_ACC_BOOT0,
+					 card->ext_csd.boot_size >> 9);
+		if (ret)
+			return ret;
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PCFG_ACC_BOOT1,
+					 card->ext_csd.boot_size >> 9);
+		if (ret)
+			return ret;
+	}
+#endif
+
+	return ret;
 }
 
 static int
@@ -686,9 +771,37 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 	return 0;
 }
 
+static void mmc_blk_remove_req(struct mmc_blk_data *md, bool del_disk)
+{
+	if (md) {
+		if (del_disk) {
+
+			/* Stop new requests from getting into the queue */
+			del_gendisk(md->disk);
+		}
+
+		/* Then flush out any already in there */
+		mmc_cleanup_queue(&md->queue);
+		mmc_blk_put(md);
+	}
+}
+
+static void mmc_blk_remove_parts(struct mmc_card *card,
+				 struct mmc_blk_data *md, bool del_disk)
+{
+	struct list_head *pos, *q;
+	struct mmc_blk_data *part_md;
+
+	list_for_each_safe(pos, q, &md->part) {
+		part_md = list_entry(pos, struct mmc_blk_data, part);
+		list_del(pos);
+		mmc_blk_remove_req(part_md, del_disk);
+	}
+}
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
-	struct mmc_blk_data *md;
+	struct mmc_blk_data *md, *part_md;
 	int err;
 
 	char cap_str[10];
@@ -713,17 +826,23 @@ static int mmc_blk_probe(struct mmc_card *card)
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
 		cap_str, md->read_only ? "(ro)" : "");
 
+	if (mmc_blk_alloc_parts(card, md))
+		goto out;
+
 	mmc_set_drvdata(card, md);
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 	mmc_set_bus_resume_policy(card->host, 1);
 #endif
 	add_disk(md->disk);
+
+	list_for_each_entry(part_md, &md->part, part) {
+		add_disk(part_md->disk);
+	}
 	return 0;
 
  out:
-	mmc_cleanup_queue(&md->queue);
-	mmc_blk_put(md);
-
+	mmc_blk_remove_parts(card, md, false);
+	mmc_blk_remove_req(md, false);
 	return err;
 }
 
@@ -731,15 +850,8 @@ static void mmc_blk_remove(struct mmc_card *card)
 {
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
-	if (md) {
-		/* Stop new requests from getting into the queue */
-		del_gendisk(md->disk);
-
-		/* Then flush out any already in there */
-		mmc_cleanup_queue(&md->queue);
-
-		mmc_blk_put(md);
-	}
+	mmc_blk_remove_parts(card, md, true);
+	mmc_blk_remove_req(md, true);
 	mmc_set_drvdata(card, NULL);
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 	mmc_set_bus_resume_policy(card->host, 0);
@@ -749,23 +861,37 @@ static void mmc_blk_remove(struct mmc_card *card)
 #ifdef CONFIG_PM
 static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_queue_suspend(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_suspend(&part_md->queue);
+		}
 	}
 	return 0;
 }
 
 static int mmc_blk_resume(struct mmc_card *card)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 #ifndef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 		mmc_blk_set_blksize(md, card);
 #endif
+
+		/*
+		  Resume involves the card going into idle state,
+		  so current partition is always the main one.
+		 */
+		md->part_curr = md->part_type;
 		mmc_queue_resume(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_resume(&part_md->queue);
+		}
 	}
 	return 0;
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6909a54..3d757aa 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -284,6 +284,11 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 			ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
 		card->ext_csd.hc_erase_size =
 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
+
+
+		/* There are two boot regions of equal size */
+		card->ext_csd.part_cfg = ext_csd[EXT_CSD_PCFG];
+		card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] * SZ_128K;
 	}
 
 	if (card->ext_csd.rev >= 4) {
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 653eb8e..b1a806f 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_set_relative_addr(struct mmc_card *card);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index fe9d7be..0911552 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -45,6 +45,7 @@ struct mmc_ext_csd {
 	u8			rev;
 	u8			erase_group_def;
 	u8			sec_feature_support;
+	u8			part_cfg;
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
@@ -53,6 +54,7 @@ struct mmc_ext_csd {
 	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
 	unsigned int		sec_erase_mult;	/* Secure erase multiplier */
 	unsigned int		trim_timeout;		/* In milliseconds */
+	unsigned int		boot_size;  /* in bytes */
 };
 
 struct sd_scr {
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 7429033..a6cd7c3 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -135,6 +135,7 @@ extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
 	struct mmc_command *, int);
+extern int mmc_switch(struct mmc_card *, u8, u8, u8);
 
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index dd11ae5..9442cbc 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -252,6 +252,7 @@ struct _mmc_csd {
  */
 
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
+#define EXT_CSD_PCFG			179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
@@ -262,6 +263,7 @@ struct _mmc_csd {
 #define EXT_CSD_S_A_TIMEOUT		217	/* RO */
 #define EXT_CSD_ERASE_TIMEOUT_MULT	223	/* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE	224	/* RO */
+#define EXT_CSD_BOOT_MULT		226	/* RO */
 #define EXT_CSD_SEC_TRIM_MULT		229	/* RO */
 #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
@@ -271,6 +273,10 @@ struct _mmc_csd {
  * EXT_CSD field definitions
  */
 
+#define EXT_CSD_PCFG_ACC_MASK           (0x7)
+#define EXT_CSD_PCFG_ACC_BOOT0          (0x1)
+#define EXT_CSD_PCFG_ACC_BOOT1          (0x2)
+
 #define EXT_CSD_CMD_SET_NORMAL		(1<<0)
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* MMC partitions support (4th revision)
  2011-03-19 11:18 ` [RFC] MMC: MMC boot partitions support Andrei Warkentin
                     ` (2 preceding siblings ...)
  2011-03-22  3:54   ` [PATCHv3] " Andrei Warkentin
@ 2011-03-22 21:11   ` Andrei Warkentin
  2011-03-22 21:11   ` [PATCHv4] MMC: MMC boot partitions support Andrei Warkentin
  4 siblings, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-22 21:11 UTC (permalink / raw)
  To: linux-mmc

This is the 4th iteration of the MMC partitions support, which also adds
boot partition support and slight cleanup of probe/remove/issue_rq code.

I've rebased this on top of linux-next, but I haven't run tested because
linux-next doesn't have support for my platform yet. Tested on K36. Can anyone try :)?


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCHv4] MMC: MMC boot partitions support.
  2011-03-19 11:18 ` [RFC] MMC: MMC boot partitions support Andrei Warkentin
                     ` (3 preceding siblings ...)
  2011-03-22 21:11   ` MMC partitions support (4th revision) Andrei Warkentin
@ 2011-03-22 21:11   ` Andrei Warkentin
  2011-03-29 22:45     ` Andrei Warkentin
  4 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-22 21:11 UTC (permalink / raw)
  To: linux-mmc; +Cc: Andrei Warkentin

Allows device MMC boot partitions to be accessed. MMC partitions
are treated effectively as separate block devices on the same
MMC card.

Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 drivers/mmc/card/Kconfig   |   18 ++++
 drivers/mmc/card/block.c   |  212 +++++++++++++++++++++++++++++++++++---------
 drivers/mmc/core/mmc.c     |    5 +
 drivers/mmc/core/mmc_ops.h |    1 -
 include/linux/mmc/card.h   |    2 +
 include/linux/mmc/core.h   |    1 +
 include/linux/mmc/mmc.h    |    6 ++
 7 files changed, 203 insertions(+), 42 deletions(-)

diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 3b1f783..c7ad8bb 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -32,6 +32,24 @@ config MMC_BLOCK_MINORS
 
 	  If unsure, say 8 here.
 
+config MMC_BLOCK_MMC_PART
+	tristate "MMC block MMC device partitioning support"
+	depends on BLOCK
+	default n
+	help
+	  Say Y here to enable access to MMC partitions other than
+	  the user area, such as the boot partitions. The other partitions
+	  will appear as separate mmcblk devices.
+
+config MMC_BLOCK_MMC_PART_BOOT
+	tristate "MMC block MMC boot partition support"
+	depends on MMC_BLOCK_MMC_PART
+	default n
+	help
+	  Say Y here to enable access to the MMC boot partitions. Boot
+	  partitions are used by some devices to store bootloader information.
+	  The boot partitions will appear as separate mmcblk devices.
+
 config MMC_BLOCK_BOUNCE
 	bool "Use bounce buffer for simple hosts"
 	depends on MMC_BLOCK
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 61d233a..2595405 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -72,9 +72,18 @@ struct mmc_blk_data {
 	spinlock_t	lock;
 	struct gendisk	*disk;
 	struct mmc_queue queue;
+	struct list_head part;
 
 	unsigned int	usage;
 	unsigned int	read_only;
+	unsigned int    part_type;
+
+	/*
+	   Only set in main mmc_blk_data associated
+	   with mmc_card with mmc_set_drvdata, and keeps
+	   track of the current selected device partition.
+	*/
+	unsigned int    part_curr;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -172,6 +181,28 @@ struct mmc_blk_request {
 	struct mmc_data		data;
 };
 
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+				      struct mmc_blk_data *md)
+{
+	int ret;
+	struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+	if (main_md->part_curr == md->part_type)
+		return 0;
+
+	if (mmc_card_mmc(card)) {
+		card->ext_csd.part_cfg &= ~EXT_CSD_PCFG_ACC_MASK;
+		card->ext_csd.part_cfg |= md->part_type;
+
+		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_PCFG, card->ext_csd.part_cfg);
+		if (ret)
+			return ret;
+	}
+
+	main_md->part_curr = md->part_type;
+	return 0;
+}
+
 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 {
 	int err;
@@ -269,8 +300,6 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_erase(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -290,8 +319,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -303,8 +330,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_secure_erase_trim(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -326,8 +351,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -338,8 +361,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 	struct mmc_blk_request brq;
 	int ret = 1, disable_multi = 0;
 
-	mmc_claim_host(card->host);
-
 	do {
 		struct mmc_command cmd;
 		u32 readcmd, writecmd, status = 0;
@@ -520,8 +541,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	} while (ret);
 
-	mmc_release_host(card->host);
-
 	return 1;
 
  cmd_err:
@@ -548,8 +567,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	}
 
-	mmc_release_host(card->host);
-
 	spin_lock_irq(&md->lock);
 	while (ret)
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
@@ -560,14 +577,29 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 
 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
+	int ret;
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+
+	mmc_claim_host(card->host);
+	ret = mmc_blk_part_switch(card, md);
+	if (ret) {
+		ret = 0;
+		goto out;
+	}
+
 	if (req->cmd_flags & REQ_DISCARD) {
 		if (req->cmd_flags & REQ_SECURE)
-			return mmc_blk_issue_secdiscard_rq(mq, req);
+			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
-			return mmc_blk_issue_discard_rq(mq, req);
+			ret = mmc_blk_issue_discard_rq(mq, req);
 	} else {
-		return mmc_blk_issue_rw_rq(mq, req);
+		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
+
+out:
+	mmc_release_host(card->host);
+	return ret;
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -576,7 +608,8 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
 	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
 }
 
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+					      sector_t size)
 {
 	struct mmc_blk_data *md;
 	int devidx, ret;
@@ -592,7 +625,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 		goto out;
 	}
 
-
 	/*
 	 * Set the read-only status based on the supported commands
 	 * and the write protect switch.
@@ -606,6 +638,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	}
 
 	spin_lock_init(&md->lock);
+	INIT_LIST_HEAD(&md->part);
 	md->usage = 1;
 
 	ret = mmc_init_queue(&md->queue, card, &md->lock);
@@ -639,29 +672,84 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 		"mmcblk%d", devidx);
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
+	set_capacity(md->disk, size);
+	return md;
+
+ err_putdisk:
+	put_disk(md->disk);
+ err_kfree:
+	kfree(md);
+ out:
+	return ERR_PTR(ret);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+	sector_t size;
+	struct mmc_blk_data *md;
 
 	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);
+		size = 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));
+		size = card->csd.capacity << (card->csd.read_blkbits - 9);
 	}
+
+	md = mmc_blk_alloc_req(card, size);
+	md->part_type = 0;
 	return md;
+}
 
- err_putdisk:
-	put_disk(md->disk);
- err_kfree:
-	kfree(md);
- out:
-	return ERR_PTR(ret);
+static int __maybe_unused mmc_blk_alloc_part(struct mmc_card *card,
+					     struct mmc_blk_data *md,
+					     unsigned int part_type,
+					     sector_t size)
+{
+	char cap_str[10];
+	struct mmc_blk_data *part_md;
+
+	part_md = mmc_blk_alloc_req(card, size);
+	if (IS_ERR(part_md))
+		return PTR_ERR(part_md);
+	part_md->part_type = part_type;
+	list_add(&part_md->part, &md->part);
+
+	string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
+			cap_str, sizeof(cap_str));
+	printk(KERN_INFO "%s: %s %s partition %u %s\n",
+	       part_md->disk->disk_name, mmc_card_id(card),
+	       mmc_card_name(card), part_md->part_type, cap_str);
+	return 0;
+}
+
+static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
+{
+	int ret = 0;
+
+	if (!mmc_card_mmc(card))
+		return 0;
+
+#ifdef CONFIG_MMC_BLOCK_MMC_PART_BOOT
+	if (card->ext_csd.boot_size) {
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PCFG_ACC_BOOT0,
+					 card->ext_csd.boot_size >> 9);
+		if (ret)
+			return ret;
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PCFG_ACC_BOOT1,
+					 card->ext_csd.boot_size >> 9);
+		if (ret)
+			return ret;
+	}
+#endif
+
+	return ret;
 }
 
 static int
@@ -682,9 +770,37 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 	return 0;
 }
 
+static void mmc_blk_remove_req(struct mmc_blk_data *md, bool del_disk)
+{
+	if (md) {
+		if (del_disk) {
+
+			/* Stop new requests from getting into the queue */
+			del_gendisk(md->disk);
+		}
+
+		/* Then flush out any already in there */
+		mmc_cleanup_queue(&md->queue);
+		mmc_blk_put(md);
+	}
+}
+
+static void mmc_blk_remove_parts(struct mmc_card *card,
+				 struct mmc_blk_data *md, bool del_disk)
+{
+	struct list_head *pos, *q;
+	struct mmc_blk_data *part_md;
+
+	list_for_each_safe(pos, q, &md->part) {
+		part_md = list_entry(pos, struct mmc_blk_data, part);
+		list_del(pos);
+		mmc_blk_remove_req(part_md, del_disk);
+	}
+}
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
-	struct mmc_blk_data *md;
+	struct mmc_blk_data *md, *part_md;
 	int err;
 	char cap_str[10];
 
@@ -708,14 +824,20 @@ static int mmc_blk_probe(struct mmc_card *card)
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
 		cap_str, md->read_only ? "(ro)" : "");
 
+	if (mmc_blk_alloc_parts(card, md))
+		goto out;
+
 	mmc_set_drvdata(card, md);
 	add_disk(md->disk);
+
+	list_for_each_entry(part_md, &md->part, part) {
+		add_disk(part_md->disk);
+	}
 	return 0;
 
  out:
-	mmc_cleanup_queue(&md->queue);
-	mmc_blk_put(md);
-
+	mmc_blk_remove_parts(card, md, false);
+	mmc_blk_remove_req(md, false);
 	return err;
 }
 
@@ -723,36 +845,44 @@ static void mmc_blk_remove(struct mmc_card *card)
 {
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
-	if (md) {
-		/* Stop new requests from getting into the queue */
-		del_gendisk(md->disk);
-
-		/* Then flush out any already in there */
-		mmc_cleanup_queue(&md->queue);
-
-		mmc_blk_put(md);
-	}
+	mmc_blk_remove_parts(card, md, true);
+	mmc_blk_remove_req(md, true);
 	mmc_set_drvdata(card, NULL);
 }
 
 #ifdef CONFIG_PM
 static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_queue_suspend(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_suspend(&part_md->queue);
+		}
 	}
 	return 0;
 }
 
 static int mmc_blk_resume(struct mmc_card *card)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_blk_set_blksize(md, card);
+
+
+		/*
+		  Resume involves the card going into idle state,
+		  so current partition is always the main one.
+		 */
+		md->part_curr = md->part_type;
 		mmc_queue_resume(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_resume(&part_md->queue);
+		}
 	}
 	return 0;
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 14e95f3..a370230 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -299,6 +299,11 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 			ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
 		card->ext_csd.hc_erase_size =
 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
+
+
+		/* There are two boot regions of equal size */
+		card->ext_csd.part_cfg = ext_csd[EXT_CSD_PCFG];
+		card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] * SZ_128K;
 	}
 
 	if (card->ext_csd.rev >= 4) {
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index e6d44b8..9276946 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_set_relative_addr(struct mmc_card *card);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index adb4888..7f00e37 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -45,6 +45,7 @@ struct mmc_ext_csd {
 	u8			rev;
 	u8			erase_group_def;
 	u8			sec_feature_support;
+	u8			part_cfg;
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
@@ -57,6 +58,7 @@ struct mmc_ext_csd {
 	bool			enhanced_area_en;	/* enable bit */
 	unsigned long long	enhanced_area_offset;	/* Units: Byte */
 	unsigned int		enhanced_area_size;	/* Units: KB */
+	unsigned int		boot_size;		/* in bytes */
 };
 
 struct sd_scr {
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 64e013f..c11bef9 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -135,6 +135,7 @@ extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
 	struct mmc_command *, int);
+extern int mmc_switch(struct mmc_card *, u8, u8, u8);
 
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 264ba54..589670a 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -256,6 +256,7 @@ struct _mmc_csd {
 #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
+#define EXT_CSD_PCFG			179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
@@ -267,6 +268,7 @@ struct _mmc_csd {
 #define EXT_CSD_HC_WP_GRP_SIZE		221	/* RO */
 #define EXT_CSD_ERASE_TIMEOUT_MULT	223	/* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE	224	/* RO */
+#define EXT_CSD_BOOT_MULT		226	/* RO */
 #define EXT_CSD_SEC_TRIM_MULT		229	/* RO */
 #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
@@ -276,6 +278,10 @@ struct _mmc_csd {
  * EXT_CSD field definitions
  */
 
+#define EXT_CSD_PCFG_ACC_MASK           (0x7)
+#define EXT_CSD_PCFG_ACC_BOOT0          (0x1)
+#define EXT_CSD_PCFG_ACC_BOOT1          (0x2)
+
 #define EXT_CSD_CMD_SET_NORMAL		(1<<0)
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-22 21:11   ` [PATCHv4] MMC: MMC boot partitions support Andrei Warkentin
@ 2011-03-29 22:45     ` Andrei Warkentin
  2011-03-30 12:03       ` Arnd Bergmann
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-29 22:45 UTC (permalink / raw)
  To: linux-mmc; +Cc: Andrei Warkentin

On Tue, Mar 22, 2011 at 4:11 PM, Andrei Warkentin <andreiw@motorola.com> wrote:
> Allows device MMC boot partitions to be accessed. MMC partitions
> are treated effectively as separate block devices on the same
> MMC card.
>

Anyone has any opinions on these changes as being good or bad?
Anything I should do differently? Or does everyone like this?

Thanks ahead,
A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-29 22:45     ` Andrei Warkentin
@ 2011-03-30 12:03       ` Arnd Bergmann
  2011-03-30 20:07         ` Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Arnd Bergmann @ 2011-03-30 12:03 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc

On Wednesday 30 March 2011, Andrei Warkentin wrote:
> On Tue, Mar 22, 2011 at 4:11 PM, Andrei Warkentin <andreiw@motorola.com> wrote:
> > Allows device MMC boot partitions to be accessed. MMC partitions
> > are treated effectively as separate block devices on the same
> > MMC card.
> >
> 
> Anyone has any opinions on these changes as being good or bad?
> Anything I should do differently? Or does everyone like this?

I have no objections to the code, but I don't completely understand
what it does. Maybe you can elaborate more in the patch description.

A few questions from me that I suppose should be answered by the
description:

* Is each of the MMC partitions in turn a partitionable device
  like the user partition with its mmcblk0p1/p2/p3... devices?

* Will this patch impact device naming? Suppose you have an
  existing machine with mmcblk0 and mmcblk1 on two physical
  eMMC devices. When you show the partitions as new block
  devices, could it happen that the names are now different
  as you get additional devices inbetween? That would need to
  be documented carefully, as it could break existing setups.

* What devices specifically have these new partitions? Only eMMC 4.4
  or also other versions?

* Would the same method work to support the secure partition on
  SD cards?

* How does a user identify which hardware partition corresponds to
  a given block device and vice versa?

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-30 12:03       ` Arnd Bergmann
@ 2011-03-30 20:07         ` Andrei Warkentin
  2011-03-30 22:43           ` Chris Ball
  2011-03-31 11:17           ` Arnd Bergmann
  0 siblings, 2 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-30 20:07 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-mmc

Hi Arnd,

On Wed, Mar 30, 2011 at 7:03 AM, Arnd Bergmann <arnd@arndb.de> wrote:

> I have no objections to the code, but I don't completely understand
> what it does. Maybe you can elaborate more in the patch description.
>

Sorry, will make it more concrete. This patch allows "device
partitions" to be accessed. Device partitions provide their own
address space - hence, you cannot access the boot partition data at
all unless you specifically switch to the partition using MMC_SWITCH.

> A few questions from me that I suppose should be answered by the
> description:
>
> * Is each of the MMC partitions in turn a partitionable device
>  like the user partition with its mmcblk0p1/p2/p3... devices?
>

Potentially yes. The current patch adds only the boot partitions,
which generally are just some binary blobs specific to the ROM
bootloaders found on embedded platforms.

Since eMMC 4.41, you can create "general purpose" partitions (up to
4), which will be carved out of the user partition, and can be used in
any way possible, thus potentially holding file system partitions.

There is also the "Replay Protected Memory Block" device partition,
which is not able to host a file system in the normal sense (because
layer over the MMC block transfer protocol is a "replay protected
transaction" protocol, which could be used by a user-mode application
directly reading/writing from /dev/block/mmcblkXXX).

> * Will this patch impact device naming? Suppose you have an
>  existing machine with mmcblk0 and mmcblk1 on two physical
>  eMMC devices. When you show the partitions as new block
>  devices, could it happen that the names are now different
>  as you get additional devices inbetween? That would need to
>  be documented carefully, as it could break existing setups.
>

Unfortunately yes, although I am open for suggestions. An idea I
considered is to add a postfix for device partitions. So, for card 0,
the user area will remain mmcblk0, while boot partitions will be
mmcblk0b0 and mmcblk0b1, generic partitions will be mmcblk0g0, and so
on.

> * What devices specifically have these new partitions? Only eMMC 4.4
>  or also other versions?
>

Boot partitions are available in 4.3. The other ones (4 general
purpose ones, rpmb since 4.41).

> * Would the same method work to support the secure partition on
>  SD cards?
>

Most of the generic changes inside block.c apply. I specifically made
the code easy to extend for SD boot partitions. You would just
need the right changes for mmc_blk_part_switch (it already checks for
mmc_card_mmc) and in mmc_blk_alloc_parts.

Unfortunately, since the SD spec is proprietary, I have no way of
confirming whether the SD device partitioning (AFAIK there is a
concept of boot partitions for eSD) works the same way or not, so I
was maximally safe in supporting MMC device partitioning.

> * How does a user identify which hardware partition corresponds to
>  a given block device and vice versa?

Right now, you would just need to know. With postfixes like
mmcblk0b0/mmcblk0g0 you would be able to tell the device partitions
apart from the main mmcblk0.

Thanks for the feedback,
A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-30 20:07         ` Andrei Warkentin
@ 2011-03-30 22:43           ` Chris Ball
  2011-03-30 22:46             ` Chris Ball
  2011-03-31 11:17           ` Arnd Bergmann
  1 sibling, 1 reply; 63+ messages in thread
From: Chris Ball @ 2011-03-30 22:43 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: Arnd Bergmann, linux-mmc

Hi Andrei,

On Wed, Mar 30 2011, Andrei Warkentin wrote:
> Unfortunately yes, although I am open for suggestions. An idea I
> considered is to add a postfix for device partitions. So, for card 0,
> the user area will remain mmcblk0, while boot partitions will be
> mmcblk0b0 and mmcblk0b1, generic partitions will be mmcblk0g0, and so
> on.

Like Arnd, my main concern was around naming, breaking boot setups, and
freaking people out by telling them that their cards have block devices
that they can't usually see and not making it obvious where they came
from.  :)

Your "b/g" postfix solution appears to fix all of these, so I like it.
We still have to think about where we expect users wondering what the
"b" and "g" mean to go in order to find out..

Thanks!

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-30 22:43           ` Chris Ball
@ 2011-03-30 22:46             ` Chris Ball
  2011-03-30 23:18               ` Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Chris Ball @ 2011-03-30 22:46 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: Arnd Bergmann, linux-mmc

Hi,

On Wed, Mar 30 2011, Chris Ball wrote:
> Hi Andrei,
>
> On Wed, Mar 30 2011, Andrei Warkentin wrote:
>> Unfortunately yes, although I am open for suggestions. An idea I
>> considered is to add a postfix for device partitions. So, for card 0,
>> the user area will remain mmcblk0, while boot partitions will be
>> mmcblk0b0 and mmcblk0b1, generic partitions will be mmcblk0g0, and so
>> on.
>
> Like Arnd, my main concern was around naming, breaking boot setups, and
> freaking people out by telling them that their cards have block devices
> that they can't usually see and not making it obvious where they came
> from.  :)
>
> Your "b/g" postfix solution appears to fix all of these, so I like it.
> We still have to think about where we expect users wondering what the
> "b" and "g" mean to go in order to find out..

Oh, one more thing -- if we go with the b/g postfix, what's the
intuition for requiring a Kconfig entry to turn this on?  Is there
any good argument against just turning it on for everyone, as long
as it's not affecting mmcblk*p* naming?

Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-30 22:46             ` Chris Ball
@ 2011-03-30 23:18               ` Andrei Warkentin
  2011-03-30 23:34                 ` Chris Ball
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-30 23:18 UTC (permalink / raw)
  To: Chris Ball; +Cc: Arnd Bergmann, linux-mmc

On Wed, Mar 30, 2011 at 5:46 PM, Chris Ball <cjb@laptop.org> wrote:
> Hi,
>
> On Wed, Mar 30 2011, Chris Ball wrote:
>> Hi Andrei,
>>
>> On Wed, Mar 30 2011, Andrei Warkentin wrote:
>>> Unfortunately yes, although I am open for suggestions. An idea I
>>> considered is to add a postfix for device partitions. So, for card 0,
>>> the user area will remain mmcblk0, while boot partitions will be
>>> mmcblk0b0 and mmcblk0b1, generic partitions will be mmcblk0g0, and so
>>> on.
>>
>> Like Arnd, my main concern was around naming, breaking boot setups, and
>> freaking people out by telling them that their cards have block devices
>> that they can't usually see and not making it obvious where they came
>> from.  :)
>>
>> Your "b/g" postfix solution appears to fix all of these, so I like it.
>> We still have to think about where we expect users wondering what the
>> "b" and "g" mean to go in order to find out..
>

Ok, I'll add that in. I'll add the documentation changes as well.

> Oh, one more thing -- if we go with the b/g postfix, what's the
> intuition for requiring a Kconfig entry to turn this on?  Is there
> any good argument against just turning it on for everyone, as long
> as it's not affecting mmcblk*p* naming?
>

The boot partition support (and any other XYZ partition support in the
future) so far in the patch is a Kconfig entry. So you have to want it
to get it.

The argument against turning it on by default is that someone might
figure that mke2fs-ing the boot partitions is a good way to reclaim
4MB on their rooted device,
and if they didn't realize the data was necessary for boot-up, they
will brick the device. That and people might freak out when they see
more mmcblk entries than they expected :-).

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-30 23:18               ` Andrei Warkentin
@ 2011-03-30 23:34                 ` Chris Ball
  2011-03-31  6:57                   ` Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Chris Ball @ 2011-03-30 23:34 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: Arnd Bergmann, linux-mmc

Hi,

On Wed, Mar 30 2011, Andrei Warkentin wrote:
> The argument against turning it on by default is that someone might
> figure that mke2fs-ing the boot partitions is a good way to reclaim
> 4MB on their rooted device,
> and if they didn't realize the data was necessary for boot-up, they
> will brick the device.

Ah.  Ugh, that sucks; I can totally see that happening.  Now I'm
wondering if we should just be hardcoding boot devices as always
read-only and just refusing to write to them.

What do others think?  Is there an acceptable tradeoff somewhere?
It's not clear to me that Kconfig entries are sufficient to obtain
consent to present r/w mounts of the boot partitions; the user
writing the "dd" line usually isn't the person who made the Kconfig
selection, and the person who made the Kconfig selection is often a
distro maintainer who just turns on new Kconfig symbols without
reading closely.

> That and people might freak out when they see
> more mmcblk entries than they expected :-).

I'm not worried about this one, as long as they have the postfixes.

Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-30 23:34                 ` Chris Ball
@ 2011-03-31  6:57                   ` Andrei Warkentin
  2011-03-31 11:01                     ` Arnd Bergmann
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-31  6:57 UTC (permalink / raw)
  To: Chris Ball; +Cc: Arnd Bergmann, linux-mmc

On Wed, Mar 30, 2011 at 6:34 PM, Chris Ball <cjb@laptop.org> wrote:
> Hi,
>
> On Wed, Mar 30 2011, Andrei Warkentin wrote:
>> The argument against turning it on by default is that someone might
>> figure that mke2fs-ing the boot partitions is a good way to reclaim
>> 4MB on their rooted device,
>> and if they didn't realize the data was necessary for boot-up, they
>> will brick the device.
>
> Ah.  Ugh, that sucks; I can totally see that happening.  Now I'm
> wondering if we should just be hardcoding boot devices as always
> read-only and just refusing to write to them.
>
> What do others think?  Is there an acceptable tradeoff somewhere?
> It's not clear to me that Kconfig entries are sufficient to obtain
> consent to present r/w mounts of the boot partitions; the user
> writing the "dd" line usually isn't the person who made the Kconfig
> selection, and the person who made the Kconfig selection is often a
> distro maintainer who just turns on new Kconfig symbols without
> reading closely.
>

Well, there are less esoteric ways of turning something into a
paperweight =). No, the whole point of adding the device partition
support is so you don't have to go through hoops to read and write
them.

The scenario where it matters (embedded Linux devices booting through
boot partitions) are such, that if you went through sufficient hoops
to get root access, and can build and boot a kernel to enable these
options for that device, then you must know what you're doing, and a
warning message in the Kconfig help is sufficient. The generic case of
people sticking cards into a PCI SDHCI controller under Ubuntu is such
that you can do no real damage.

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-31  6:57                   ` Andrei Warkentin
@ 2011-03-31 11:01                     ` Arnd Bergmann
  2011-03-31 19:17                       ` Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Arnd Bergmann @ 2011-03-31 11:01 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: Chris Ball, linux-mmc

On Thursday 31 March 2011, Andrei Warkentin wrote:
> Well, there are less esoteric ways of turning something into a
> paperweight =). No, the whole point of adding the device partition
> support is so you don't have to go through hoops to read and write
> them.

Agreed.

> The scenario where it matters (embedded Linux devices booting through
> boot partitions) are such, that if you went through sufficient hoops
> to get root access, and can build and boot a kernel to enable these
> options for that device, then you must know what you're doing, and a
> warning message in the Kconfig help is sufficient. The generic case of
> people sticking cards into a PCI SDHCI controller under Ubuntu is such
> that you can do no real damage.

One possible way of dealing with this would be to make the boot partition
a character device instead of a block device. That would still allow
you to overwrite it, but make it very obvious that you cannot mount or
partition it.

On the other hand, it would be a rather esoteric interface, since the
hardware is still fundamentally block based, we just use it in a different
way.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-30 20:07         ` Andrei Warkentin
  2011-03-30 22:43           ` Chris Ball
@ 2011-03-31 11:17           ` Arnd Bergmann
  2011-03-31 19:29             ` Andrei Warkentin
  1 sibling, 1 reply; 63+ messages in thread
From: Arnd Bergmann @ 2011-03-31 11:17 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc

On Wednesday 30 March 2011, Andrei Warkentin wrote:
> On Wed, Mar 30, 2011 at 7:03 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> Since eMMC 4.41, you can create "general purpose" partitions (up to
> 4), which will be carved out of the user partition, and can be used in
> any way possible, thus potentially holding file system partitions.

My feeling is that these should be separate from the boot partition.
It could probably be done using a new fs/partitions/mmc.c file
that directly interacts with the mmc layer instead of looking
at the MS-DOS master boot record. That way, you could define the
same partitions (mmcblk0p1, ...) using a different method.

It also requires a user interface that a new mmc-fdisk tool
can talk to, in order to modify the partition table, not sure
if it's possible to use the BLKPG ioctl for this.
 
> There is also the "Replay Protected Memory Block" device partition,
> which is not able to host a file system in the normal sense (because
> layer over the MMC block transfer protocol is a "replay protected
> transaction" protocol, which could be used by a user-mode application
> directly reading/writing from /dev/block/mmcblkXXX).

Ok. That sounds like a use case for an ioctl interface then, if
we even want to expose it.
 
> > * What devices specifically have these new partitions? Only eMMC 4.4
> >  or also other versions?
> >
> 
> Boot partitions are available in 4.3. The other ones (4 general
> purpose ones, rpmb since 4.41).
 
ok.

> Unfortunately, since the SD spec is proprietary, I have no way of
> confirming whether the SD device partitioning (AFAIK there is a
> concept of boot partitions for eSD) works the same way or not, so I
> was maximally safe in supporting MMC device partitioning.

The public parts of the SD standard specifically require MS-DOS
partitioning to be used, so I assume that there is no internal
method in addition. They also describe the presence of a "secure
area" that can only be accessed after authentication. This could
use a similar method as the boot partition, but it's unclear to
me whether that is something that anyone is interested in.

> > * How does a user identify which hardware partition corresponds to
> >  a given block device and vice versa?
> 
> Right now, you would just need to know. With postfixes like
> mmcblk0b0/mmcblk0g0 you would be able to tell the device partitions
> apart from the main mmcblk0.

Regarding the naming, I would not use a trailing zero, but it's probably
a subjective thing. The other names I could imagine for the boot partition
of mmc 0 are mmcboot0, mmcblk0b or mmcblk0boot.

I also mentioned the character device option. Yet another way would be
to add a sysfs_bin_attribute that corresponds to the boot partition and
can be accessed using read/write, like we do for PCI resources.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-31 11:01                     ` Arnd Bergmann
@ 2011-03-31 19:17                       ` Andrei Warkentin
  2011-03-31 19:37                         ` Chris Ball
  2011-04-01  9:21                         ` Arnd Bergmann
  0 siblings, 2 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-31 19:17 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: Chris Ball, linux-mmc

On Thu, Mar 31, 2011 at 6:01 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Thursday 31 March 2011, Andrei Warkentin wrote:
>> Well, there are less esoteric ways of turning something into a
>> paperweight =). No, the whole point of adding the device partition
>> support is so you don't have to go through hoops to read and write
>> them.
>
> Agreed.
>
>> The scenario where it matters (embedded Linux devices booting through
>> boot partitions) are such, that if you went through sufficient hoops
>> to get root access, and can build and boot a kernel to enable these
>> options for that device, then you must know what you're doing, and a
>> warning message in the Kconfig help is sufficient. The generic case of
>> people sticking cards into a PCI SDHCI controller under Ubuntu is such
>> that you can do no real damage.
>
> One possible way of dealing with this would be to make the boot partition
> a character device instead of a block device. That would still allow
> you to overwrite it, but make it very obvious that you cannot mount or
> partition it.
>
> On the other hand, it would be a rather esoteric interface, since the
> hardware is still fundamentally block based, we just use it in a different
> way.
>

Plus what if you do intend to have a file system there? Other than
complexity and non-obvious usage, I don't see
anything gained by this. I wouldn't worry about ways of misusing this.
As I've said, in the only case it matters (some embedded device
booting from the boot partition), the user would have to gain root
access, build a kernel giving access to the boot partitions and be
able to boot into it. So a warning in Kconfig is sufficient.

If you guys feel concerned, then we can add another Kconfig option
that will allow write access to the boot partitions.

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-31 11:17           ` Arnd Bergmann
@ 2011-03-31 19:29             ` Andrei Warkentin
  2011-04-01 10:38               ` Arnd Bergmann
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-31 19:29 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-mmc

On Thu, Mar 31, 2011 at 6:17 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>
> My feeling is that these should be separate from the boot partition.
> It could probably be done using a new fs/partitions/mmc.c file
> that directly interacts with the mmc layer instead of looking
> at the MS-DOS master boot record. That way, you could define the
> same partitions (mmcblk0p1, ...) using a different method.
>

Nope. The device partitions are one time programmable (partition
once), so you definitely don't want to expose them as regular
partitions. The point
behind the GP partitions is that they can be implemented with enhanced
features (such as better reliability), and so like the enhanced area,
are meant as a complement, not a replacement for file system
partitions.

I don't think there is a need to over complicate this. It's just going
to get more confusing and involve more changes. The device
partitioning support is pretty orthogonal right now.

>
>> There is also the "Replay Protected Memory Block" device partition,
>> which is not able to host a file system in the normal sense (because
>> layer over the MMC block transfer protocol is a "replay protected
>> transaction" protocol, which could be used by a user-mode application
>> directly reading/writing from /dev/block/mmcblkXXX).
>
> Ok. That sounds like a use case for an ioctl interface then, if
> we even want to expose it.
>

Pretty much.

> Regarding the naming, I would not use a trailing zero, but it's probably
> a subjective thing. The other names I could imagine for the boot partition
> of mmc 0 are mmcboot0, mmcblk0b or mmcblk0boot.
>

Since we have two boot partitions and 4 GP ones, for mmcblk0 I'd stick
with something like
mmcblk0boot0, mmcblk0boot1, mmcblk0gp0-mmcblk0gp4. I'd want to keep
the first mmcblk0, so that
a user can easily associate the actual card the device partitions are for.

> I also mentioned the character device option. Yet another way would be
> to add a sysfs_bin_attribute that corresponds to the boot partition and
> can be accessed using read/write, like we do for PCI resources.

I don't think this gains anything, other than a separate path for
performing I/O, inability to use existing tools (filesystems, dd, etc)
more code and a even less obvious way of bricking something =).

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-31 19:17                       ` Andrei Warkentin
@ 2011-03-31 19:37                         ` Chris Ball
  2011-03-31 20:01                           ` Andrei Warkentin
  2011-03-31 20:03                           ` Chris Ball
  2011-04-01  9:21                         ` Arnd Bergmann
  1 sibling, 2 replies; 63+ messages in thread
From: Chris Ball @ 2011-03-31 19:37 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: Arnd Bergmann, linux-mmc

Hi,

On Thu, Mar 31 2011, Andrei Warkentin wrote:
> Plus what if you do intend to have a file system there? Other than
> complexity and non-obvious usage, I don't see
> anything gained by this. I wouldn't worry about ways of misusing this.
> As I've said, in the only case it matters (some embedded device
> booting from the boot partition), the user would have to gain root
> access, build a kernel giving access to the boot partitions and be
> able to boot into it. So a warning in Kconfig is sufficient.
> 
> If you guys feel concerned, then we can add another Kconfig option
> that will allow write access to the boot partitions.

I'm willing to come around to saying that the risk is acceptable, and
that people who overwrite /dev/mmcblk0b0 on their rooted Android phones
won't blame us (at least, not deservedly) for it.

But I'm still concerned after your Kconfig options are added, because
I'm just not reassured by Kconfig options in principle, because of the
case where *the person who built the kernel* is not the same as the
*user who is running commands*.  Imagine that CyanogenMod (or even
Qualcomm!) distributes a kernel with this Kconfig option turned on --
because they don't realize how dangerous it is, perhaps, or because they
had a use for it during development -- to see where I'm coming from.

Now, the presence of block devices that brick machines when overwritten
isn't a new phenomenon, so we've got a fair amount of precedence behind
us if we simply expose what we see and expect that users won't do
something unrecoverable.  But I'm trying to think about if there's
anything we can do to *minimize* that risk, and have people know what's
going on before they do something they shouldn't.  (I think I like Arnd's
suggestion of explicitly having "boot" in the device name rather than
just "b", because that does lend a feeling of "this partition is really
important".)

Does that help clarify my position?  Would be happy to hear any other
suggestions on what the right affordance to shoot for is.

Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-31 19:37                         ` Chris Ball
@ 2011-03-31 20:01                           ` Andrei Warkentin
  2011-03-31 20:03                           ` Chris Ball
  1 sibling, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-31 20:01 UTC (permalink / raw)
  To: Chris Ball; +Cc: Arnd Bergmann, linux-mmc

On Thu, Mar 31, 2011 at 2:37 PM, Chris Ball <cjb@laptop.org> wrote:
> Hi,
>
> On Thu, Mar 31 2011, Andrei Warkentin wrote:
>> Plus what if you do intend to have a file system there? Other than
>> complexity and non-obvious usage, I don't see
>> anything gained by this. I wouldn't worry about ways of misusing this.
>> As I've said, in the only case it matters (some embedded device
>> booting from the boot partition), the user would have to gain root
>> access, build a kernel giving access to the boot partitions and be
>> able to boot into it. So a warning in Kconfig is sufficient.
>>
>> If you guys feel concerned, then we can add another Kconfig option
>> that will allow write access to the boot partitions.
>
> I'm willing to come around to saying that the risk is acceptable, and
> that people who overwrite /dev/mmcblk0b0 on their rooted Android phones
> won't blame us (at least, not deservedly) for it.
>
> But I'm still concerned after your Kconfig options are added, because
> I'm just not reassured by Kconfig options in principle, because of the
> case where *the person who built the kernel* is not the same as the
> *user who is running commands*.  Imagine that CyanogenMod (or even
> Qualcomm!) distributes a kernel with this Kconfig option turned on --
> because they don't realize how dangerous it is, perhaps, or because they
> had a use for it during development -- to see where I'm coming from.
>
> Now, the presence of block devices that brick machines when overwritten
> isn't a new phenomenon, so we've got a fair amount of precedence behind
> us if we simply expose what we see and expect that users won't do
> something unrecoverable.  But I'm trying to think about if there's
> anything we can do to *minimize* that risk, and have people know what's
> going on before they do something they shouldn't.  (I think I like Arnd's
> suggestion of explicitly having "boot" in the device name rather than
> just "b", because that does lend a feeling of "this partition is really
> important".)

Yup I think having 'boot' in there (as in mmcblk0boot0) is a good
idea. I also think having boot write support as a separate
configuration option is also a good idea,
so I'll add that in. I think that should help minimize the risk.

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-31 20:03                           ` Chris Ball
@ 2011-03-31 20:01                             ` Andrei Warkentin
  2011-04-01  9:23                               ` Arnd Bergmann
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-03-31 20:01 UTC (permalink / raw)
  To: Chris Ball; +Cc: Arnd Bergmann, linux-mmc

On Thu, Mar 31, 2011 at 3:03 PM, Chris Ball <cjb@laptop.org> wrote:
> Hi,
>
> On Thu, Mar 31 2011, Chris Ball wrote:
>> But I'm still concerned after your Kconfig options are added, because
>> I'm just not reassured by Kconfig options in principle, because of the
>> case where *the person who built the kernel* is not the same as the
>> *user who is running commands*.  Imagine that CyanogenMod (or even
>> Qualcomm!) distributes a kernel with this Kconfig option turned on --
>> because they don't realize how dangerous it is, perhaps, or because they
>> had a use for it during development -- to see where I'm coming from.
>
> Another strawman, after brainstorming a bit on IRC -- how about
> the block device itself comes up read-only, until you use a module
> parameter/sysfs entry to make it read-write.  As a strawman:
>
> echo 1 > /sys/module/mmc_block/boot_partitions_are_writeable
>
> (That way people who write to it regularly can throw the module parameter
> in their boot environment, and the rooting enthusiasts who didn't compile
> the kernel are safe until they learn enough to be really dangerous..)

Sure, I like this, I'll do it.

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-31 19:37                         ` Chris Ball
  2011-03-31 20:01                           ` Andrei Warkentin
@ 2011-03-31 20:03                           ` Chris Ball
  2011-03-31 20:01                             ` Andrei Warkentin
  1 sibling, 1 reply; 63+ messages in thread
From: Chris Ball @ 2011-03-31 20:03 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: Arnd Bergmann, linux-mmc

Hi,

On Thu, Mar 31 2011, Chris Ball wrote:
> But I'm still concerned after your Kconfig options are added, because
> I'm just not reassured by Kconfig options in principle, because of the
> case where *the person who built the kernel* is not the same as the
> *user who is running commands*.  Imagine that CyanogenMod (or even
> Qualcomm!) distributes a kernel with this Kconfig option turned on --
> because they don't realize how dangerous it is, perhaps, or because they
> had a use for it during development -- to see where I'm coming from.

Another strawman, after brainstorming a bit on IRC -- how about
the block device itself comes up read-only, until you use a module
parameter/sysfs entry to make it read-write.  As a strawman:

echo 1 > /sys/module/mmc_block/boot_partitions_are_writeable

(That way people who write to it regularly can throw the module parameter
in their boot environment, and the rooting enthusiasts who didn't compile
the kernel are safe until they learn enough to be really dangerous..)

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-31 19:17                       ` Andrei Warkentin
  2011-03-31 19:37                         ` Chris Ball
@ 2011-04-01  9:21                         ` Arnd Bergmann
  1 sibling, 0 replies; 63+ messages in thread
From: Arnd Bergmann @ 2011-04-01  9:21 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: Chris Ball, linux-mmc

On Thursday 31 March 2011, Andrei Warkentin wrote:
> Plus what if you do intend to have a file system there? Other than
> complexity and non-obvious usage, I don't see
> anything gained by this. I wouldn't worry about ways of misusing this.
> As I've said, in the only case it matters (some embedded device
> booting from the boot partition), the user would have to gain root
> access, build a kernel giving access to the boot partitions and be
> able to boot into it.

The character device (or sysfs_bin_file actually) would only make
sense if we know that there is no reason to put a file system on it.
The idea of that is that we intentionally treat it like a firmware
flash, not like a block device because that is how it's used.

If there is a reasonable chance that people actually want to have
a file system in the boot partition, it should by all means be 
a block device.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-31 20:01                             ` Andrei Warkentin
@ 2011-04-01  9:23                               ` Arnd Bergmann
  2011-04-01 14:52                                 ` Chris Ball
  0 siblings, 1 reply; 63+ messages in thread
From: Arnd Bergmann @ 2011-04-01  9:23 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: Chris Ball, linux-mmc

On Thursday 31 March 2011, Andrei Warkentin wrote:
> > Another strawman, after brainstorming a bit on IRC -- how about
> > the block device itself comes up read-only, until you use a module
> > parameter/sysfs entry to make it read-write.  As a strawman:
> >
> > echo 1 > /sys/module/mmc_block/boot_partitions_are_writeable
> >
> > (That way people who write to it regularly can throw the module parameter
> > in their boot environment, and the rooting enthusiasts who didn't compile
> > the kernel are safe until they learn enough to be really dangerous..)
> 
> Sure, I like this, I'll do it.

I don't think it's even needed, but it sounds much more useful than
a Kconfig option, so no objections from me.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-03-31 19:29             ` Andrei Warkentin
@ 2011-04-01 10:38               ` Arnd Bergmann
  2011-04-01 18:42                 ` Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Arnd Bergmann @ 2011-04-01 10:38 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc

On Thursday 31 March 2011, Andrei Warkentin wrote:
> On Thu, Mar 31, 2011 at 6:17 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> >
> > My feeling is that these should be separate from the boot partition.
> > It could probably be done using a new fs/partitions/mmc.c file
> > that directly interacts with the mmc layer instead of looking
> > at the MS-DOS master boot record. That way, you could define the
> > same partitions (mmcblk0p1, ...) using a different method.
>
> Nope. The device partitions are one time programmable (partition
> once), so you definitely don't want to expose them as regular
> partitions. The point
> behind the GP partitions is that they can be implemented with enhanced
> features (such as better reliability), and so like the enhanced area,
> are meant as a complement, not a replacement for file system
> partitions.
> 
> I don't think there is a need to over complicate this. It's just going
> to get more confusing and involve more changes. The device
> partitioning support is pretty orthogonal right now.

Even if they are write-once, wouldn't we still need to provide an
interface to write them once?

The question if GP should be used together or instead of MS-DOS
partitions depends on the possible use cases. If you don't want
to partition a GP any further in software, exposing them directly
as mmcblk0pX would be a very nice and simple interface, but
it completely prevents you from creating subpartitions.

The other alternative is to allow each GP to contain a partition
table, but then you need a either a three-level naming (mmcblk0gp1p2)
or make each GP a device by itself (mmcblk0, mmcblk1) that can in
turn be partitioned.

> > Regarding the naming, I would not use a trailing zero, but it's probably
> > a subjective thing. The other names I could imagine for the boot partition
> > of mmc 0 are mmcboot0, mmcblk0b or mmcblk0boot.
> >
> 
> Since we have two boot partitions and 4 GP ones, for mmcblk0 I'd stick
> with something like
> mmcblk0boot0, mmcblk0boot1, mmcblk0gp0-mmcblk0gp4. I'd want to keep
> the first mmcblk0, so that
> a user can easily associate the actual card the device partitions are for.

I would find it rather confusing if the device can be partitioned in
software but the GP devices could not be.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-04-01  9:23                               ` Arnd Bergmann
@ 2011-04-01 14:52                                 ` Chris Ball
  0 siblings, 0 replies; 63+ messages in thread
From: Chris Ball @ 2011-04-01 14:52 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: Andrei Warkentin, linux-mmc

Hi,

On Fri, Apr 01 2011, Arnd Bergmann wrote:
> I don't think it's even needed, but it sounds much more useful than
> a Kconfig option, so no objections from me.

Cool, thanks.  By the way, I'm pretty neutral on whether there need
to be any Kconfig entries for any of this at all after the module
parameter goes in, so feel free to take them out of the patch.

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-04-01 10:38               ` Arnd Bergmann
@ 2011-04-01 18:42                 ` Andrei Warkentin
  2011-04-01 19:25                   ` Arnd Bergmann
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-01 18:42 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-mmc

On Fri, Apr 1, 2011 at 5:38 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>
> Even if they are write-once, wouldn't we still need to provide an
> interface to write them once?
>

True. I first wanted to provide access to them. It would have to be a
special ioctl. There are a number of interesting MMC operations that
don't fit any other way - for example, password protection.

> The question if GP should be used together or instead of MS-DOS
> partitions depends on the possible use cases. If you don't want
> to partition a GP any further in software, exposing them directly
> as mmcblk0pX would be a very nice and simple interface, but
> it completely prevents you from creating subpartitions.
>
> The other alternative is to allow each GP to contain a partition
> table, but then you need a either a three-level naming (mmcblk0gp1p2)
> or make each GP a device by itself (mmcblk0, mmcblk1) that can in
> turn be partitioned.
>

Right now they are exposed as separate devices. This lets the user
pick whatever usage they
see fit (can format it directly, or can partition it), while the
naming (mmcblk0boot0, mmcblk0boot1, mmcblkgp0p1 for first partition on
gp0, for example) conveys that the entries are for device partitions.

>> > Regarding the naming, I would not use a trailing zero, but it's probably
>> > a subjective thing. The other names I could imagine for the boot partition
>> > of mmc 0 are mmcboot0, mmcblk0b or mmcblk0boot.
>> >
>>
>> Since we have two boot partitions and 4 GP ones, for mmcblk0 I'd stick
>> with something like
>> mmcblk0boot0, mmcblk0boot1, mmcblk0gp0-mmcblk0gp4. I'd want to keep
>> the first mmcblk0, so that
>> a user can easily associate the actual card the device partitions are for.
>
> I would find it rather confusing if the device can be partitioned in
> software but the GP devices could not be.
>

Right now you can partition the device partitions, because
effectively, they are separate devices.

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-04-01 18:42                 ` Andrei Warkentin
@ 2011-04-01 19:25                   ` Arnd Bergmann
  2011-04-01 19:42                     ` Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Arnd Bergmann @ 2011-04-01 19:25 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc

On Friday 01 April 2011 20:42:36 Andrei Warkentin wrote:
> Right now they are exposed as separate devices. This lets the user
> pick whatever usage they
> see fit (can format it directly, or can partition it), while the
> naming (mmcblk0boot0, mmcblk0boot1, mmcblkgp0p1 for first partition on
> gp0, for example) conveys that the entries are for device partitions.

Ok, sounds good. How do they show up in sysfs then? I think ideally
a gp device should be a child of the regular device, just like a partition,
and then it can have further children. That way, a user application can
easily find out which ones belong together.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv4] MMC: MMC boot partitions support.
  2011-04-01 19:25                   ` Arnd Bergmann
@ 2011-04-01 19:42                     ` Andrei Warkentin
  2011-04-04 12:22                       ` [PATCH] " Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-01 19:42 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-mmc

On Fri, Apr 1, 2011 at 2:25 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Friday 01 April 2011 20:42:36 Andrei Warkentin wrote:
>> Right now they are exposed as separate devices. This lets the user
>> pick whatever usage they
>> see fit (can format it directly, or can partition it), while the
>> naming (mmcblk0boot0, mmcblk0boot1, mmcblkgp0p1 for first partition on
>> gp0, for example) conveys that the entries are for device partitions.
>
> Ok, sounds good. How do they show up in sysfs then? I think ideally
> a gp device should be a child of the regular device, just like a partition,
> and then it can have further children. That way, a user application can
> easily find out which ones belong together.

Right now, it shows up on the same level as mmcblk0, but I'll fix that
(this is why I wanted the first portion to contain actual device name,
e.g. mmcblk0boot0, but you're right, I should fix the inheritance)

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH] MMC: MMC boot partitions support.
  2011-04-04 12:22                       ` [PATCH] " Andrei Warkentin
@ 2011-04-04 11:52                         ` Andrei Warkentin
  2011-04-11 21:13                           ` [patchv3 1/4] MMC: Rename erase_timeout to cmd_timeout_ms Andrei Warkentin
                                             ` (3 more replies)
  0 siblings, 4 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-04 11:52 UTC (permalink / raw)
  To: linux-mmc; +Cc: Andrei Warkentin, Chris Ball, Arnd Bergmann

On Mon, Apr 4, 2011 at 7:22 AM, Andrei Warkentin <andreiw@motorola.com> wrote:
> Allows device MMC boot partitions to be accessed. MMC partitions
> are treated effectively as separate block devices on the same
> MMC card.
>
> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>

+Chris
+Arnd

This version is different from the previous one in the following ways:
- Rebased on top reliable writes support (because it's in to make
merging easier) + modified MMC: enable TRIM/ERASE caps for SDHCI host
patch that I sent out earlier today
  (because I need to be able to set timeout appropriately for CMD6 and
have it honored by SDHCI)
- Fixes compile error with block support built as module (mmc_switch
wasn't exported)
- Let's mmc_switch be supplied a timeout value. Default of 0 does a
max timeout which is the only valid thing to do for register
modifications where the timeout is not specified by the JEDEC spec or
EXT_CSD values.
- Switching partition timeout is now honored (byte 199 of EXT_CSD)
- Fixes compile error with getting built on architectures where
SZ_128K isn't defined (most of them)
- Fixes naming as discussed - boot partitions are called mmcblkXbootY
- Fixes device parent/child relationship - added disks for boot
partitions are children of main mmc block disk
- Adds "force_ro" block device attribute, which is set by default to
"1" for boot partitions/
- Adds documentation.

Thanks,
A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH] MMC: MMC boot partitions support.
  2011-04-01 19:42                     ` Andrei Warkentin
@ 2011-04-04 12:22                       ` Andrei Warkentin
  2011-04-04 11:52                         ` Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-04 12:22 UTC (permalink / raw)
  To: linux-mmc; +Cc: Andrei Warkentin

Allows device MMC boot partitions to be accessed. MMC partitions
are treated effectively as separate block devices on the same
MMC card.

Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 Documentation/mmc/00-INDEX          |    2 +
 Documentation/mmc/mmc-dev-attrs.txt |   10 ++
 Documentation/mmc/mmc-dev-parts.txt |   26 +++
 drivers/mmc/card/block.c            |  305 +++++++++++++++++++++++++++++------
 drivers/mmc/core/mmc.c              |   35 +++--
 drivers/mmc/core/mmc_ops.c          |   16 ++-
 drivers/mmc/core/mmc_ops.h          |    1 -
 include/linux/mmc/card.h            |    4 +-
 include/linux/mmc/core.h            |    1 +
 include/linux/mmc/mmc.h             |    8 +-
 10 files changed, 341 insertions(+), 67 deletions(-)
 create mode 100644 Documentation/mmc/mmc-dev-parts.txt

diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX
index fca586f..93dd7a7 100644
--- a/Documentation/mmc/00-INDEX
+++ b/Documentation/mmc/00-INDEX
@@ -2,3 +2,5 @@
         - this file
 mmc-dev-attrs.txt
         - info on SD and MMC device attributes
+mmc-dev-parts.txt
+        - info on SD and MMC device partitions
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index ff2bd68..4eecc85 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -1,3 +1,13 @@
+SD and MMC Block Device Attributes
+==================================
+
+These attributes are defined for the block devices associated with the 
+SD or MMC device.
+
+The following attributes are read/write.
+
+	force_ro		Enforce read-only access even if write protect switch is off.
+
 SD and MMC Device Attributes
 ============================
 
diff --git a/Documentation/mmc/mmc-dev-parts.txt b/Documentation/mmc/mmc-dev-parts.txt
new file mode 100644
index 0000000..8821909
--- /dev/null
+++ b/Documentation/mmc/mmc-dev-parts.txt
@@ -0,0 +1,26 @@
+SD and MMC Device Partitions
+============================
+
+Device partitions are additional logical block devices present
+on the SD/MMC device.
+
+As of this writing, MMC boot partitions as supported and exposed as 
+/dev/mmcblkXboot0 and /dev/mmcblkXboot1, where X is the index of the
+parent /dev/mmcblkX.
+
+MMC Boot Partitions
+===================
+
+Read and write access is provided to the two MMC boot partitions. Due
+to the sensitive nature of the boot partition contents, which often store
+a bootloader or bootloader configuration tables crucial to booting the platform,
+write access is by default disabled to reduce the chance of accidental bricking.
+
+To enable write access to /dev/mmcblkXbootY, disable the forced read-only
+access:
+
+echo 0 > /sys/block/mmcblkXbootY/force_ro
+
+To re-enable read-only access:
+
+echo 1 > /sys/block/mmcblkXbootY/force_ro
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 91a6767..ee8f7a9 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -76,9 +76,19 @@ struct mmc_blk_data {
 	spinlock_t	lock;
 	struct gendisk	*disk;
 	struct mmc_queue queue;
+	struct list_head part;
 
 	unsigned int	usage;
 	unsigned int	read_only;
+	unsigned int	part_type;
+
+	/*
+	 * Only set in main mmc_blk_data associated
+	 * with mmc_card with mmc_set_drvdata, and keeps
+	 * track of the current selected device partition.
+	 */
+	unsigned int	part_curr;
+	struct device_attribute force_ro;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -101,17 +111,22 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 	return md;
 }
 
+static int mmc_get_devidx(struct gendisk *disk)
+{
+	int devmaj = MAJOR(disk_devt(disk));
+	int devidx = MINOR(disk_devt(disk)) / perdev_minors;
+
+	if (!devmaj)
+		devidx = disk->first_minor / perdev_minors;
+	return devidx;
+}
+
 static void mmc_blk_put(struct mmc_blk_data *md)
 {
 	mutex_lock(&open_lock);
 	md->usage--;
 	if (md->usage == 0) {
-		int devmaj = MAJOR(disk_devt(md->disk));
-		int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
-
-		if (!devmaj)
-			devidx = md->disk->first_minor / perdev_minors;
-
+		int devidx = mmc_get_devidx(md->disk);
 		blk_cleanup_queue(md->queue.queue);
 
 		__clear_bit(devidx, dev_use);
@@ -122,6 +137,38 @@ static void mmc_blk_put(struct mmc_blk_data *md)
 	mutex_unlock(&open_lock);
 }
 
+static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	int ret;
+	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+
+	ret = snprintf(buf, PAGE_SIZE, "%d",
+		       get_disk_ro(dev_to_disk(dev)) ^
+		       md->read_only);
+	mmc_blk_put(md);
+	return ret;
+}
+
+static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	int ret;
+	char *end;
+	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+	unsigned long set = simple_strtoul(buf, &end, 0);
+	if (end == buf) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	set_disk_ro(dev_to_disk(dev), set || md->read_only);
+	ret = count;
+out:
+	mmc_blk_put(md);
+	return ret;
+}
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -176,6 +223,29 @@ struct mmc_blk_request {
 	struct mmc_data		data;
 };
 
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+				      struct mmc_blk_data *md)
+{
+	int ret;
+	struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+	if (main_md->part_curr == md->part_type)
+		return 0;
+
+	if (mmc_card_mmc(card)) {
+		card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+		card->ext_csd.part_config |= md->part_type;
+
+		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
+				 card->ext_csd.part_time);
+		if (ret)
+			return ret;
+}
+
+	main_md->part_curr = md->part_type;
+	return 0;
+}
+
 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 {
 	int err;
@@ -273,8 +343,6 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_erase(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -294,8 +362,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -307,8 +373,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_secure_erase_trim(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -330,8 +394,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -402,8 +464,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		(rq_data_dir(req) == WRITE) &&
 		REL_WRITES_SUPPORTED(card);
 
-	mmc_claim_host(card->host);
-
 	do {
 		struct mmc_command cmd;
 		u32 readcmd, writecmd, status = 0;
@@ -589,8 +649,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	} while (ret);
 
-	mmc_release_host(card->host);
-
 	return 1;
 
  cmd_err:
@@ -617,8 +675,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	}
 
-	mmc_release_host(card->host);
-
 	spin_lock_irq(&md->lock);
 	while (ret)
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
@@ -629,16 +685,31 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 
 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
+	int ret;
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+
+	mmc_claim_host(card->host);
+	ret = mmc_blk_part_switch(card, md);
+	if (ret) {
+		ret = 0;
+		goto out;
+	}
+
 	if (req->cmd_flags & REQ_DISCARD) {
 		if (req->cmd_flags & REQ_SECURE)
-			return mmc_blk_issue_secdiscard_rq(mq, req);
+			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
-			return mmc_blk_issue_discard_rq(mq, req);
+			ret = mmc_blk_issue_discard_rq(mq, req);
 	} else if (req->cmd_flags & REQ_FLUSH) {
-		return mmc_blk_issue_flush(mq, req);
+		ret = mmc_blk_issue_flush(mq, req);
 	} else {
-		return mmc_blk_issue_rw_rq(mq, req);
+		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
+
+out:
+	mmc_release_host(card->host);
+	return ret;
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -647,7 +718,11 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
 	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
 }
 
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+					      struct device *parent,
+					      sector_t size,
+					      bool default_ro,
+					      const char *subname)
 {
 	struct mmc_blk_data *md;
 	int devidx, ret;
@@ -663,7 +738,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 		goto out;
 	}
 
-
 	/*
 	 * Set the read-only status based on the supported commands
 	 * and the write protect switch.
@@ -677,6 +751,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	}
 
 	spin_lock_init(&md->lock);
+	INIT_LIST_HEAD(&md->part);
 	md->usage = 1;
 
 	ret = mmc_init_queue(&md->queue, card, &md->lock);
@@ -691,8 +766,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	md->disk->fops = &mmc_bdops;
 	md->disk->private_data = md;
 	md->disk->queue = md->queue.queue;
-	md->disk->driverfs_dev = &card->dev;
-	set_disk_ro(md->disk, md->read_only);
+	md->disk->driverfs_dev = parent;
+	set_disk_ro(md->disk, md->read_only || default_ro);
 	if (REL_WRITES_SUPPORTED(card))
 		blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
 
@@ -708,33 +783,97 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	 * messages to tell when the card is present.
 	 */
 
-	snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
-		"mmcblk%d", devidx);
+	if (subname)
+		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+			 "mmcblk%d%s",
+			 mmc_get_devidx(dev_to_disk(parent)), subname);
+	else
+		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+			 "mmcblk%d", devidx);
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
+	set_capacity(md->disk, size);
+	return md;
+
+ err_putdisk:
+	put_disk(md->disk);
+ err_kfree:
+	kfree(md);
+ out:
+	return ERR_PTR(ret);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+	sector_t size;
+	struct mmc_blk_data *md;
 
 	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);
+		size = 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));
+		size = card->csd.capacity << (card->csd.read_blkbits - 9);
 	}
+
+	md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
 	return md;
+}
 
- err_putdisk:
-	put_disk(md->disk);
- err_kfree:
-	kfree(md);
- out:
-	return ERR_PTR(ret);
+static int mmc_blk_alloc_part(struct mmc_card *card,
+			      struct mmc_blk_data *md,
+			      unsigned int part_type,
+			      sector_t size,
+			      bool default_ro,
+			      const char *subname)
+{
+	char cap_str[10];
+	struct mmc_blk_data *part_md;
+
+	part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
+				    subname);
+	if (IS_ERR(part_md))
+		return PTR_ERR(part_md);
+	part_md->part_type = part_type;
+	list_add(&part_md->part, &md->part);
+
+	string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
+			cap_str, sizeof(cap_str));
+	printk(KERN_INFO "%s: %s %s partition %u %s\n",
+	       part_md->disk->disk_name, mmc_card_id(card),
+	       mmc_card_name(card), part_md->part_type, cap_str);
+	return 0;
+}
+
+static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
+{
+	int ret = 0;
+
+	if (!mmc_card_mmc(card))
+		return 0;
+
+	if (card->ext_csd.boot_size) {
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0,
+					 card->ext_csd.boot_size >> 9,
+					 true,
+					 "boot0");
+		if (ret)
+			return ret;
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT1,
+					 card->ext_csd.boot_size >> 9,
+					 true,
+					 "boot1");
+		if (ret)
+			return ret;
+	}
+
+	return ret;
 }
 
 static int
@@ -755,9 +894,54 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 	return 0;
 }
 
+static void mmc_blk_remove_req(struct mmc_blk_data *md)
+{
+	if (md) {
+		if (md->disk->flags & GENHD_FL_UP) {
+			device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+
+			/* Stop new requests from getting into the queue */
+			del_gendisk(md->disk);
+		}
+
+		/* Then flush out any already in there */
+		mmc_cleanup_queue(&md->queue);
+		mmc_blk_put(md);
+	}
+}
+
+static void mmc_blk_remove_parts(struct mmc_card *card,
+				 struct mmc_blk_data *md)
+{
+	struct list_head *pos, *q;
+	struct mmc_blk_data *part_md;
+
+	list_for_each_safe(pos, q, &md->part) {
+		part_md = list_entry(pos, struct mmc_blk_data, part);
+		list_del(pos);
+		mmc_blk_remove_req(part_md);
+	}
+}
+
+static int mmc_add_disk(struct mmc_blk_data *md)
+{
+	int ret;
+
+	add_disk(md->disk);
+	md->force_ro.show = force_ro_show;
+	md->force_ro.store = force_ro_store;
+	md->force_ro.attr.name = "force_ro";
+	md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
+	ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
+	if (ret)
+		del_gendisk(md->disk);
+
+	return ret;
+}
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
-	struct mmc_blk_data *md;
+	struct mmc_blk_data *md, *part_md;
 	int err;
 	char cap_str[10];
 
@@ -781,14 +965,22 @@ static int mmc_blk_probe(struct mmc_card *card)
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
 		cap_str, md->read_only ? "(ro)" : "");
 
+	if (mmc_blk_alloc_parts(card, md))
+		goto out;
+
 	mmc_set_drvdata(card, md);
-	add_disk(md->disk);
+	if (mmc_add_disk(md))
+		goto out;
+
+	list_for_each_entry(part_md, &md->part, part) {
+		if (mmc_add_disk(part_md))
+			goto out;
+	}
 	return 0;
 
  out:
-	mmc_cleanup_queue(&md->queue);
-	mmc_blk_put(md);
-
+	mmc_blk_remove_parts(card, md);
+	mmc_blk_remove_req(md);
 	return err;
 }
 
@@ -796,36 +988,43 @@ static void mmc_blk_remove(struct mmc_card *card)
 {
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
-	if (md) {
-		/* Stop new requests from getting into the queue */
-		del_gendisk(md->disk);
-
-		/* Then flush out any already in there */
-		mmc_cleanup_queue(&md->queue);
-
-		mmc_blk_put(md);
-	}
+	mmc_blk_remove_parts(card, md);
+	mmc_blk_remove_req(md);
 	mmc_set_drvdata(card, NULL);
 }
 
 #ifdef CONFIG_PM
 static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_queue_suspend(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_suspend(&part_md->queue);
+		}
 	}
 	return 0;
 }
 
 static int mmc_blk_resume(struct mmc_card *card)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_blk_set_blksize(md, card);
+
+		/*
+		 * Resume involves the card going into idle state,
+		 * so current partition is always the main one.
+		 */
+		md->part_curr = md->part_type;
 		mmc_queue_resume(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_resume(&part_md->queue);
+		}
 	}
 	return 0;
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index caba751..af4d076 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -288,7 +288,10 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
 	if (card->ext_csd.rev >= 3) {
 		u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
-		card->ext_csd.bootconfig = ext_csd[EXT_CSD_BOOT_CONFIG];
+		card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
+
+		/* EXT_CSD value is in units of 10ms, but we store in ms */
+		card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
 
 		/* Sleep / awake timeout in 100ns units */
 		if (sa_shift > 0 && sa_shift <= 0x17)
@@ -302,6 +305,12 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
 
 		card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C];
+
+		/*
+		 * There are two boot regions of equal size, defined in
+		 * multiples of 128K.
+		 */
+		card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
 	}
 
 	if (card->ext_csd.rev >= 4) {
@@ -548,7 +557,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.enhanced_area_en) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_ERASE_GROUP_DEF, 1);
+				 EXT_CSD_ERASE_GROUP_DEF, 1,
+				 0);
 
 		if (err && err != -EBADMSG)
 			goto free_card;
@@ -576,10 +586,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Ensure eMMC user default partition is enabled
 	 */
-	if (card->ext_csd.bootconfig & 0x7) {
-		card->ext_csd.bootconfig &= ~0x7;
-		mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_CONFIG,
-			   card->ext_csd.bootconfig);
+	if (card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK) {
+		card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,
+				 card->ext_csd.part_config,
+				 card->ext_csd.part_time);
+		if (err && err != -EBADMSG)
+			goto free_card;
 	}
 
 	/*
@@ -588,7 +601,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	if ((card->ext_csd.hs_max_dtr != 0) &&
 		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-			EXT_CSD_HS_TIMING, 1);
+				 EXT_CSD_HS_TIMING, 1, 0);
 		if (err && err != -EBADMSG)
 			goto free_card;
 
@@ -655,7 +668,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				ddr = 0; /* no DDR for 1-bit width */
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0]);
+					 ext_csd_bits[idx][0],
+					 0);
 			if (!err) {
 				mmc_set_bus_width_ddr(card->host,
 						      bus_width, MMC_SDR_MODE);
@@ -674,8 +688,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
 		if (!err && ddr) {
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					EXT_CSD_BUS_WIDTH,
-					ext_csd_bits[idx][1]);
+					 EXT_CSD_BUS_WIDTH,
+					 ext_csd_bits[idx][1],
+					 0);
 		}
 		if (err) {
 			printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 60842f8..6c77212 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -387,7 +387,18 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
 	return err;
 }
 
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
+/**
+ *	mmc_switch - modify EXT_CSD register
+ *	@card: the MMC card associated with the data transfer
+ *	@set: cmd set values
+ *	@index: EXT_CSD register index
+ *	@value: value to program into EXT_CSD register
+ *	@timeout: timeout for operation performed by register write
+ *
+ *	Modifies the EXT_CSD register for selected card.
+ */
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+	       unsigned int timeout)
 {
 	int err;
 	struct mmc_command cmd;
@@ -404,6 +415,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
 		  (value << 8) |
 		  set;
 	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+	cmd.cmd_timeout = timeout;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 	if (err)
@@ -434,6 +446,8 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
 	return 0;
 }
 
+EXPORT_SYMBOL(mmc_switch);
+
 int mmc_send_status(struct mmc_card *card, u32 *status)
 {
 	int err;
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index e6d44b8..9276946 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_set_relative_addr(struct mmc_card *card);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c4e96fa..b90cacc 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -47,7 +47,8 @@ struct mmc_ext_csd {
 	u8			sec_feature_support;
 	u8			rel_sectors;
 	u8			rel_param;
-	u8			bootconfig;
+	u8			part_config;
+	unsigned int		part_time;		/* Units: ms */
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
@@ -60,6 +61,7 @@ struct mmc_ext_csd {
 	bool			enhanced_area_en;	/* enable bit */
 	unsigned long long	enhanced_area_offset;	/* Units: Byte */
 	unsigned int		enhanced_area_size;	/* Units: KB */
+	unsigned int		boot_size;		/* in bytes */
 };
 
 struct sd_scr {
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index a7d7da7..6d4f3df 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -135,6 +135,7 @@ extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
 	struct mmc_command *, int);
+extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
 
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 390aa6e..373b2bf 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -257,19 +257,21 @@ struct _mmc_csd {
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
 #define EXT_CSD_WR_REL_PARAM		166	/* RO */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
-#define EXT_CSD_BOOT_CONFIG		179	/* R/W */
+#define EXT_CSD_PART_CONFIG		179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
 #define EXT_CSD_STRUCTURE		194	/* RO */
 #define EXT_CSD_CARD_TYPE		196	/* RO */
+#define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
 #define EXT_CSD_SEC_CNT			212	/* RO, 4 bytes */
 #define EXT_CSD_S_A_TIMEOUT		217	/* RO */
 #define EXT_CSD_REL_WR_SEC_C		222	/* RO */
 #define EXT_CSD_HC_WP_GRP_SIZE		221	/* RO */
 #define EXT_CSD_ERASE_TIMEOUT_MULT	223	/* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE	224	/* RO */
+#define EXT_CSD_BOOT_MULT		226	/* RO */
 #define EXT_CSD_SEC_TRIM_MULT		229	/* RO */
 #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
@@ -281,6 +283,10 @@ struct _mmc_csd {
 
 #define EXT_CSD_WR_REL_PARAM_EN		(1<<2)
 
+#define EXT_CSD_PART_CONFIG_ACC_MASK	(0x7)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT0	(0x1)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT1	(0x2)
+
 #define EXT_CSD_CMD_SET_NORMAL		(1<<0)
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [patchv3 1/4] MMC: Rename erase_timeout to cmd_timeout_ms.
  2011-04-04 11:52                         ` Andrei Warkentin
@ 2011-04-11 21:13                           ` Andrei Warkentin
  2011-04-11 21:13                           ` [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE Andrei Warkentin
                                             ` (2 subsequent siblings)
  3 siblings, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-11 21:13 UTC (permalink / raw)
  To: linux-mmc; +Cc: arnd, cjb, Andrei Warkentin

Renames erase_timeout to cmd_timeout_ms inside struct mmc_command.
First step to making host honor timeouts for non-data-transfer
commands. Cleans up erase timeout code.

Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 drivers/mmc/core/core.c  |   39 +++++++++++++++++++++------------------
 include/linux/mmc/core.h |    2 +-
 2 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1f453ac..8a000d2 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1187,9 +1187,8 @@ void mmc_init_erase(struct mmc_card *card)
 	}
 }
 
-static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
-				      struct mmc_command *cmd,
-				      unsigned int arg, unsigned int qty)
+static unsigned int  mmc_mmc_erase_timeout(struct mmc_card *card,
+					   unsigned int arg, unsigned int qty)
 {
 	unsigned int erase_timeout;
 
@@ -1246,38 +1245,42 @@ static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
 	if (mmc_host_is_spi(card->host) && erase_timeout < 1000)
 		erase_timeout = 1000;
 
-	cmd->erase_timeout = erase_timeout;
+	return erase_timeout;
 }
 
-static void mmc_set_sd_erase_timeout(struct mmc_card *card,
-				     struct mmc_command *cmd, unsigned int arg,
-				     unsigned int qty)
+static unsigned int mmc_sd_erase_timeout(struct mmc_card *card,
+					 unsigned int arg,
+					 unsigned int qty)
 {
+	unsigned int erase_timeout;
+
 	if (card->ssr.erase_timeout) {
 		/* Erase timeout specified in SD Status Register (SSR) */
-		cmd->erase_timeout = card->ssr.erase_timeout * qty +
-				     card->ssr.erase_offset;
+		erase_timeout = card->ssr.erase_timeout * qty +
+			card->ssr.erase_offset;
 	} else {
 		/*
 		 * Erase timeout not specified in SD Status Register (SSR) so
 		 * use 250ms per write block.
 		 */
-		cmd->erase_timeout = 250 * qty;
+		erase_timeout = 250 * qty;
 	}
 
 	/* Must not be less than 1 second */
-	if (cmd->erase_timeout < 1000)
-		cmd->erase_timeout = 1000;
+	if (erase_timeout < 1000)
+		erase_timeout = 1000;
+
+	return erase_timeout;
 }
 
-static void mmc_set_erase_timeout(struct mmc_card *card,
-				  struct mmc_command *cmd, unsigned int arg,
-				  unsigned int qty)
+static unsigned int mmc_erase_timeout(struct mmc_card *card,
+				      unsigned int arg,
+				      unsigned int qty)
 {
 	if (mmc_card_sd(card))
-		mmc_set_sd_erase_timeout(card, cmd, arg, qty);
+		return mmc_sd_erase_timeout(card, arg, qty);
 	else
-		mmc_set_mmc_erase_timeout(card, cmd, arg, qty);
+		return mmc_mmc_erase_timeout(card, arg, qty);
 }
 
 static int mmc_do_erase(struct mmc_card *card, unsigned int from,
@@ -1351,7 +1354,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
 	cmd.opcode = MMC_ERASE;
 	cmd.arg = arg;
 	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-	mmc_set_erase_timeout(card, &cmd, arg, qty);
+	cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
 	err = mmc_wait_for_cmd(card->host, &cmd, 0);
 	if (err) {
 		printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n",
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 07f27af..811e96e 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -92,7 +92,7 @@ struct mmc_command {
  *              actively failing requests
  */
 
-	unsigned int		erase_timeout;	/* in milliseconds */
+	unsigned int		cmd_timeout_ms;	/* in milliseconds */
 
 	struct mmc_data		*data;		/* data segment associated with cmd */
 	struct mmc_request	*mrq;		/* associated request */
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
  2011-04-04 11:52                         ` Andrei Warkentin
  2011-04-11 21:13                           ` [patchv3 1/4] MMC: Rename erase_timeout to cmd_timeout_ms Andrei Warkentin
@ 2011-04-11 21:13                           ` Andrei Warkentin
  2011-04-12  9:06                             ` Dong, Chuanxiao
  2011-08-10 13:30                             ` Chris Ball
  2011-04-11 21:13                           ` [patchv3 3/4] MMC: Allow setting CMD timeout for CMD6 (SWITCH) Andrei Warkentin
  2011-04-11 21:13                           ` [patchv3 4/4] MMC: MMC boot partitions support Andrei Warkentin
  3 siblings, 2 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-11 21:13 UTC (permalink / raw)
  To: linux-mmc; +Cc: arnd, cjb, Andrei Warkentin

ERASE command needs R1B response, so fix R1B-type command
handling for SDHCI controller. For non-DAT commands using a busy
reponse, the cmd->cmd_timeout_ms (in ms) field is used for timeout
calculations.

Based on patch by Chuanxiao Dong <chuanxiao.dong@intel.com>
Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 drivers/mmc/host/sdhci.c |   43 +++++++++++++++++++++++++++----------------
 1 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9e15f41..173e980 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -40,7 +40,6 @@
 
 static unsigned int debug_quirks = 0;
 
-static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
 static void sdhci_finish_data(struct sdhci_host *);
 
 static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
@@ -591,9 +590,10 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
 		data->sg_len, direction);
 }
 
-static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
+static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	u8 count;
+	struct mmc_data *data = cmd->data;
 	unsigned target_timeout, current_timeout;
 
 	/*
@@ -605,12 +605,16 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
 	if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
 		return 0xE;
 
-	/* timeout in us */
-	target_timeout = data->timeout_ns / 1000 +
-		data->timeout_clks / host->clock;
+	/* Unspecified timeout, assume max */
+	if (!data && !cmd->cmd_timeout_ms)
+		return 0xE;
 
-	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
-		host->timeout_clk = host->clock / 1000;
+	/* timeout in us */
+	if (!data)
+		target_timeout = cmd->cmd_timeout_ms * 1000;
+	else
+		target_timeout = data->timeout_ns / 1000 +
+			data->timeout_clks / host->clock;
 
 	/*
 	 * Figure out needed cycles.
@@ -632,8 +636,9 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
 	}
 
 	if (count >= 0xF) {
-		printk(KERN_WARNING "%s: Too large timeout requested!\n",
-			mmc_hostname(host->mmc));
+		printk(KERN_WARNING "%s: Too large timeout requested for CMD%d!\n",
+		       mmc_hostname(host->mmc),
+		       cmd->opcode);
 		count = 0xE;
 	}
 
@@ -651,15 +656,21 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
 		sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
 }
 
-static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
+static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	u8 count;
 	u8 ctrl;
+	struct mmc_data *data = cmd->data;
 	int ret;
 
 	WARN_ON(host->data);
 
-	if (data == NULL)
+	if (data || (cmd->flags & MMC_RSP_BUSY)) {
+		count = sdhci_calc_timeout(host, cmd);
+		sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+	}
+
+	if (!data)
 		return;
 
 	/* Sanity checks */
@@ -670,9 +681,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 	host->data = data;
 	host->data_early = 0;
 
-	count = sdhci_calc_timeout(host, data);
-	sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
-
 	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
 		host->flags |= SDHCI_REQ_USE_DMA;
 
@@ -920,7 +928,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 
 	host->cmd = cmd;
 
-	sdhci_prepare_data(host, cmd->data);
+	sdhci_prepare_data(host, cmd);
 
 	sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
 
@@ -1867,6 +1875,9 @@ int sdhci_add_host(struct sdhci_host *host)
 	if (caps & SDHCI_TIMEOUT_CLK_UNIT)
 		host->timeout_clk *= 1000;
 
+	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
+		host->timeout_clk = host->clock / 1000;
+
 	/*
 	 * Set host parameters.
 	 */
@@ -1879,7 +1890,7 @@ int sdhci_add_host(struct sdhci_host *host)
 		mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
 	mmc->f_max = host->max_clk;
-	mmc->caps |= MMC_CAP_SDIO_IRQ;
+	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE;
 
 	/*
 	 * A controller may support 8-bit width, but the board itself
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [patchv3 3/4] MMC: Allow setting CMD timeout for CMD6 (SWITCH).
  2011-04-04 11:52                         ` Andrei Warkentin
  2011-04-11 21:13                           ` [patchv3 1/4] MMC: Rename erase_timeout to cmd_timeout_ms Andrei Warkentin
  2011-04-11 21:13                           ` [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE Andrei Warkentin
@ 2011-04-11 21:13                           ` Andrei Warkentin
  2011-04-11 21:13                           ` [patchv3 4/4] MMC: MMC boot partitions support Andrei Warkentin
  3 siblings, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-11 21:13 UTC (permalink / raw)
  To: linux-mmc; +Cc: arnd, cjb, Andrei Warkentin

CMD6 is R1B-type command, where DAT is used as busy. Depending
on register written using CMD6, timeout value can be different
as per spec.

Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 drivers/mmc/core/mmc.c     |   14 ++++++++------
 drivers/mmc/core/mmc_ops.c |   17 ++++++++++++++++-
 drivers/mmc/core/mmc_ops.h |    1 -
 include/linux/mmc/core.h   |    1 +
 4 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index caba751..a5cf423 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -548,7 +548,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	if (card->ext_csd.enhanced_area_en) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				EXT_CSD_ERASE_GROUP_DEF, 1);
+				 EXT_CSD_ERASE_GROUP_DEF, 1, 0);
 
 		if (err && err != -EBADMSG)
 			goto free_card;
@@ -579,7 +579,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	if (card->ext_csd.bootconfig & 0x7) {
 		card->ext_csd.bootconfig &= ~0x7;
 		mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_CONFIG,
-			   card->ext_csd.bootconfig);
+			   card->ext_csd.bootconfig, 0);
 	}
 
 	/*
@@ -588,7 +588,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	if ((card->ext_csd.hs_max_dtr != 0) &&
 		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-			EXT_CSD_HS_TIMING, 1);
+				 EXT_CSD_HS_TIMING, 1, 0);
 		if (err && err != -EBADMSG)
 			goto free_card;
 
@@ -655,7 +655,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 				ddr = 0; /* no DDR for 1-bit width */
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0]);
+					 ext_csd_bits[idx][0],
+					 0);
 			if (!err) {
 				mmc_set_bus_width_ddr(card->host,
 						      bus_width, MMC_SDR_MODE);
@@ -674,8 +675,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
 		if (!err && ddr) {
 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					EXT_CSD_BUS_WIDTH,
-					ext_csd_bits[idx][1]);
+					 EXT_CSD_BUS_WIDTH,
+					 ext_csd_bits[idx][1],
+					 0);
 		}
 		if (err) {
 			printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 60842f8..586f9b4 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -387,7 +387,19 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
 	return err;
 }
 
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
+/**
+ *	mmc_switch - modify EXT_CSD register
+ *	@card: the MMC card associated with the data transfer
+ *	@set: cmd set values
+ *	@index: EXT_CSD register index
+ *	@value: value to program into EXT_CSD register
+ *	@timeout_ms: timeout (ms) for operation performed by register write,
+ *                   timeout of zero implies maximum possible timeout
+ *
+ *	Modifies the EXT_CSD register for selected card.
+ */
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+	unsigned int timeout_ms)
 {
 	int err;
 	struct mmc_command cmd;
@@ -404,6 +416,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
 		  (value << 8) |
 		  set;
 	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+	cmd.cmd_timeout_ms = timeout_ms;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 	if (err)
@@ -434,6 +447,8 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
 	return 0;
 }
 
+EXPORT_SYMBOL(mmc_switch);
+
 int mmc_send_status(struct mmc_card *card, u32 *status)
 {
 	int err;
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index e6d44b8..9276946 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_set_relative_addr(struct mmc_card *card);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 811e96e..f8e4bcb 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -135,6 +135,7 @@ extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
 	struct mmc_command *, int);
+extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
 
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-04 11:52                         ` Andrei Warkentin
                                             ` (2 preceding siblings ...)
  2011-04-11 21:13                           ` [patchv3 3/4] MMC: Allow setting CMD timeout for CMD6 (SWITCH) Andrei Warkentin
@ 2011-04-11 21:13                           ` Andrei Warkentin
  2011-04-11 22:00                             ` Chris Ball
  2011-04-21  1:13                             ` Chris Ball
  3 siblings, 2 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-11 21:13 UTC (permalink / raw)
  To: linux-mmc; +Cc: arnd, cjb, Andrei Warkentin

Allows device MMC boot partitions to be accessed. MMC partitions
are treated effectively as separate block devices on the same
MMC card.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 Documentation/mmc/00-INDEX          |    2 +
 Documentation/mmc/mmc-dev-attrs.txt |   10 ++
 Documentation/mmc/mmc-dev-parts.txt |   26 +++
 drivers/mmc/card/block.c            |  305 +++++++++++++++++++++++++++++------
 drivers/mmc/core/mmc.c              |   22 ++-
 include/linux/mmc/card.h            |    4 +-
 include/linux/mmc/mmc.h             |    8 +-
 7 files changed, 317 insertions(+), 60 deletions(-)
 create mode 100644 Documentation/mmc/mmc-dev-parts.txt

diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX
index fca586f..93dd7a7 100644
--- a/Documentation/mmc/00-INDEX
+++ b/Documentation/mmc/00-INDEX
@@ -2,3 +2,5 @@
         - this file
 mmc-dev-attrs.txt
         - info on SD and MMC device attributes
+mmc-dev-parts.txt
+        - info on SD and MMC device partitions
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index ff2bd68..8898a95 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -1,3 +1,13 @@
+SD and MMC Block Device Attributes
+==================================
+
+These attributes are defined for the block devices associated with the
+SD or MMC device.
+
+The following attributes are read/write.
+
+	force_ro		Enforce read-only access even if write protect switch is off.
+
 SD and MMC Device Attributes
 ============================
 
diff --git a/Documentation/mmc/mmc-dev-parts.txt b/Documentation/mmc/mmc-dev-parts.txt
new file mode 100644
index 0000000..8821909
--- /dev/null
+++ b/Documentation/mmc/mmc-dev-parts.txt
@@ -0,0 +1,26 @@
+SD and MMC Device Partitions
+============================
+
+Device partitions are additional logical block devices present
+on the SD/MMC device.
+
+As of this writing, MMC boot partitions as supported and exposed as 
+/dev/mmcblkXboot0 and /dev/mmcblkXboot1, where X is the index of the
+parent /dev/mmcblkX.
+
+MMC Boot Partitions
+===================
+
+Read and write access is provided to the two MMC boot partitions. Due
+to the sensitive nature of the boot partition contents, which often store
+a bootloader or bootloader configuration tables crucial to booting the platform,
+write access is by default disabled to reduce the chance of accidental bricking.
+
+To enable write access to /dev/mmcblkXbootY, disable the forced read-only
+access:
+
+echo 0 > /sys/block/mmcblkXbootY/force_ro
+
+To re-enable read-only access:
+
+echo 1 > /sys/block/mmcblkXbootY/force_ro
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 91a6767..1e6bd91 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -76,9 +76,19 @@ struct mmc_blk_data {
 	spinlock_t	lock;
 	struct gendisk	*disk;
 	struct mmc_queue queue;
+	struct list_head part;
 
 	unsigned int	usage;
 	unsigned int	read_only;
+	unsigned int	part_type;
+
+	/*
+	 * Only set in main mmc_blk_data associated
+	 * with mmc_card with mmc_set_drvdata, and keeps
+	 * track of the current selected device partition.
+	 */
+	unsigned int	part_curr;
+	struct device_attribute force_ro;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -101,17 +111,22 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 	return md;
 }
 
+static inline int mmc_get_devidx(struct gendisk *disk)
+{
+	int devmaj = MAJOR(disk_devt(disk));
+	int devidx = MINOR(disk_devt(disk)) / perdev_minors;
+
+	if (!devmaj)
+		devidx = disk->first_minor / perdev_minors;
+	return devidx;
+}
+
 static void mmc_blk_put(struct mmc_blk_data *md)
 {
 	mutex_lock(&open_lock);
 	md->usage--;
 	if (md->usage == 0) {
-		int devmaj = MAJOR(disk_devt(md->disk));
-		int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
-
-		if (!devmaj)
-			devidx = md->disk->first_minor / perdev_minors;
-
+		int devidx = mmc_get_devidx(md->disk);
 		blk_cleanup_queue(md->queue.queue);
 
 		__clear_bit(devidx, dev_use);
@@ -122,6 +137,38 @@ static void mmc_blk_put(struct mmc_blk_data *md)
 	mutex_unlock(&open_lock);
 }
 
+static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	int ret;
+	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+
+	ret = snprintf(buf, PAGE_SIZE, "%d",
+		       get_disk_ro(dev_to_disk(dev)) ^
+		       md->read_only);
+	mmc_blk_put(md);
+	return ret;
+}
+
+static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	int ret;
+	char *end;
+	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+	unsigned long set = simple_strtoul(buf, &end, 0);
+	if (end == buf) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	set_disk_ro(dev_to_disk(dev), set || md->read_only);
+	ret = count;
+out:
+	mmc_blk_put(md);
+	return ret;
+}
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -176,6 +223,29 @@ struct mmc_blk_request {
 	struct mmc_data		data;
 };
 
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+				      struct mmc_blk_data *md)
+{
+	int ret;
+	struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+	if (main_md->part_curr == md->part_type)
+		return 0;
+
+	if (mmc_card_mmc(card)) {
+		card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+		card->ext_csd.part_config |= md->part_type;
+
+		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
+				 card->ext_csd.part_time);
+		if (ret)
+			return ret;
+}
+
+	main_md->part_curr = md->part_type;
+	return 0;
+}
+
 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 {
 	int err;
@@ -273,8 +343,6 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_erase(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -294,8 +362,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -307,8 +373,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_secure_erase_trim(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -330,8 +394,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -402,8 +464,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		(rq_data_dir(req) == WRITE) &&
 		REL_WRITES_SUPPORTED(card);
 
-	mmc_claim_host(card->host);
-
 	do {
 		struct mmc_command cmd;
 		u32 readcmd, writecmd, status = 0;
@@ -589,8 +649,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	} while (ret);
 
-	mmc_release_host(card->host);
-
 	return 1;
 
  cmd_err:
@@ -617,8 +675,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	}
 
-	mmc_release_host(card->host);
-
 	spin_lock_irq(&md->lock);
 	while (ret)
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
@@ -629,16 +685,31 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 
 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
+	int ret;
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+
+	mmc_claim_host(card->host);
+	ret = mmc_blk_part_switch(card, md);
+	if (ret) {
+		ret = 0;
+		goto out;
+	}
+
 	if (req->cmd_flags & REQ_DISCARD) {
 		if (req->cmd_flags & REQ_SECURE)
-			return mmc_blk_issue_secdiscard_rq(mq, req);
+			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
-			return mmc_blk_issue_discard_rq(mq, req);
+			ret = mmc_blk_issue_discard_rq(mq, req);
 	} else if (req->cmd_flags & REQ_FLUSH) {
-		return mmc_blk_issue_flush(mq, req);
+		ret = mmc_blk_issue_flush(mq, req);
 	} else {
-		return mmc_blk_issue_rw_rq(mq, req);
+		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
+
+out:
+	mmc_release_host(card->host);
+	return ret;
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -647,7 +718,11 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
 	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
 }
 
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+					      struct device *parent,
+					      sector_t size,
+					      bool default_ro,
+					      const char *subname)
 {
 	struct mmc_blk_data *md;
 	int devidx, ret;
@@ -663,7 +738,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 		goto out;
 	}
 
-
 	/*
 	 * Set the read-only status based on the supported commands
 	 * and the write protect switch.
@@ -677,6 +751,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	}
 
 	spin_lock_init(&md->lock);
+	INIT_LIST_HEAD(&md->part);
 	md->usage = 1;
 
 	ret = mmc_init_queue(&md->queue, card, &md->lock);
@@ -691,8 +766,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	md->disk->fops = &mmc_bdops;
 	md->disk->private_data = md;
 	md->disk->queue = md->queue.queue;
-	md->disk->driverfs_dev = &card->dev;
-	set_disk_ro(md->disk, md->read_only);
+	md->disk->driverfs_dev = parent;
+	set_disk_ro(md->disk, md->read_only || default_ro);
 	if (REL_WRITES_SUPPORTED(card))
 		blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
 
@@ -708,33 +783,97 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	 * messages to tell when the card is present.
 	 */
 
-	snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
-		"mmcblk%d", devidx);
+	if (subname)
+		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+			 "mmcblk%d%s",
+			 mmc_get_devidx(dev_to_disk(parent)), subname);
+	else
+		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+			 "mmcblk%d", devidx);
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
+	set_capacity(md->disk, size);
+	return md;
+
+ err_putdisk:
+	put_disk(md->disk);
+ err_kfree:
+	kfree(md);
+ out:
+	return ERR_PTR(ret);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+	sector_t size;
+	struct mmc_blk_data *md;
 
 	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);
+		size = 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));
+		size = card->csd.capacity << (card->csd.read_blkbits - 9);
 	}
+
+	md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
 	return md;
+}
 
- err_putdisk:
-	put_disk(md->disk);
- err_kfree:
-	kfree(md);
- out:
-	return ERR_PTR(ret);
+static int mmc_blk_alloc_part(struct mmc_card *card,
+			      struct mmc_blk_data *md,
+			      unsigned int part_type,
+			      sector_t size,
+			      bool default_ro,
+			      const char *subname)
+{
+	char cap_str[10];
+	struct mmc_blk_data *part_md;
+
+	part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
+				    subname);
+	if (IS_ERR(part_md))
+		return PTR_ERR(part_md);
+	part_md->part_type = part_type;
+	list_add(&part_md->part, &md->part);
+
+	string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
+			cap_str, sizeof(cap_str));
+	printk(KERN_INFO "%s: %s %s partition %u %s\n",
+	       part_md->disk->disk_name, mmc_card_id(card),
+	       mmc_card_name(card), part_md->part_type, cap_str);
+	return 0;
+}
+
+static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
+{
+	int ret = 0;
+
+	if (!mmc_card_mmc(card))
+		return 0;
+
+	if (card->ext_csd.boot_size) {
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0,
+					 card->ext_csd.boot_size >> 9,
+					 true,
+					 "boot0");
+		if (ret)
+			return ret;
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT1,
+					 card->ext_csd.boot_size >> 9,
+					 true,
+					 "boot1");
+		if (ret)
+			return ret;
+	}
+
+	return ret;
 }
 
 static int
@@ -755,9 +894,54 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 	return 0;
 }
 
+static void mmc_blk_remove_req(struct mmc_blk_data *md)
+{
+	if (md) {
+		if (md->disk->flags & GENHD_FL_UP) {
+			device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+
+			/* Stop new requests from getting into the queue */
+			del_gendisk(md->disk);
+		}
+
+		/* Then flush out any already in there */
+		mmc_cleanup_queue(&md->queue);
+		mmc_blk_put(md);
+	}
+}
+
+static void mmc_blk_remove_parts(struct mmc_card *card,
+				 struct mmc_blk_data *md)
+{
+	struct list_head *pos, *q;
+	struct mmc_blk_data *part_md;
+
+	list_for_each_safe(pos, q, &md->part) {
+		part_md = list_entry(pos, struct mmc_blk_data, part);
+		list_del(pos);
+		mmc_blk_remove_req(part_md);
+	}
+}
+
+static int mmc_add_disk(struct mmc_blk_data *md)
+{
+	int ret;
+
+	add_disk(md->disk);
+	md->force_ro.show = force_ro_show;
+	md->force_ro.store = force_ro_store;
+	md->force_ro.attr.name = "force_ro";
+	md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
+	ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
+	if (ret)
+		del_gendisk(md->disk);
+
+	return ret;
+}
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
-	struct mmc_blk_data *md;
+	struct mmc_blk_data *md, *part_md;
 	int err;
 	char cap_str[10];
 
@@ -781,14 +965,22 @@ static int mmc_blk_probe(struct mmc_card *card)
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
 		cap_str, md->read_only ? "(ro)" : "");
 
+	if (mmc_blk_alloc_parts(card, md))
+		goto out;
+
 	mmc_set_drvdata(card, md);
-	add_disk(md->disk);
+	if (mmc_add_disk(md))
+		goto out;
+
+	list_for_each_entry(part_md, &md->part, part) {
+		if (mmc_add_disk(part_md))
+			goto out;
+	}
 	return 0;
 
  out:
-	mmc_cleanup_queue(&md->queue);
-	mmc_blk_put(md);
-
+	mmc_blk_remove_parts(card, md);
+	mmc_blk_remove_req(md);
 	return err;
 }
 
@@ -796,36 +988,43 @@ static void mmc_blk_remove(struct mmc_card *card)
 {
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
-	if (md) {
-		/* Stop new requests from getting into the queue */
-		del_gendisk(md->disk);
-
-		/* Then flush out any already in there */
-		mmc_cleanup_queue(&md->queue);
-
-		mmc_blk_put(md);
-	}
+	mmc_blk_remove_parts(card, md);
+	mmc_blk_remove_req(md);
 	mmc_set_drvdata(card, NULL);
 }
 
 #ifdef CONFIG_PM
 static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_queue_suspend(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_suspend(&part_md->queue);
+		}
 	}
 	return 0;
 }
 
 static int mmc_blk_resume(struct mmc_card *card)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_blk_set_blksize(md, card);
+
+		/*
+		 * Resume involves the card going into idle state,
+		 * so current partition is always the main one.
+		 */
+		md->part_curr = md->part_type;
 		mmc_queue_resume(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_resume(&part_md->queue);
+		}
 	}
 	return 0;
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a5cf423..ba1c878 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -288,7 +288,10 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
 	if (card->ext_csd.rev >= 3) {
 		u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
-		card->ext_csd.bootconfig = ext_csd[EXT_CSD_BOOT_CONFIG];
+		card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
+
+		/* EXT_CSD value is in units of 10ms, but we store in ms */
+		card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
 
 		/* Sleep / awake timeout in 100ns units */
 		if (sa_shift > 0 && sa_shift <= 0x17)
@@ -302,6 +305,12 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
 
 		card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C];
+
+		/*
+		 * There are two boot regions of equal size, defined in
+		 * multiples of 128K.
+		 */
+		card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
 	}
 
 	if (card->ext_csd.rev >= 4) {
@@ -576,10 +585,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Ensure eMMC user default partition is enabled
 	 */
-	if (card->ext_csd.bootconfig & 0x7) {
-		card->ext_csd.bootconfig &= ~0x7;
-		mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_CONFIG,
-			   card->ext_csd.bootconfig, 0);
+	if (card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK) {
+		card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,
+				 card->ext_csd.part_config,
+				 card->ext_csd.part_time);
+		if (err && err != -EBADMSG)
+			goto free_card;
 	}
 
 	/*
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c4e96fa..b90cacc 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -47,7 +47,8 @@ struct mmc_ext_csd {
 	u8			sec_feature_support;
 	u8			rel_sectors;
 	u8			rel_param;
-	u8			bootconfig;
+	u8			part_config;
+	unsigned int		part_time;		/* Units: ms */
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
@@ -60,6 +61,7 @@ struct mmc_ext_csd {
 	bool			enhanced_area_en;	/* enable bit */
 	unsigned long long	enhanced_area_offset;	/* Units: Byte */
 	unsigned int		enhanced_area_size;	/* Units: KB */
+	unsigned int		boot_size;		/* in bytes */
 };
 
 struct sd_scr {
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 390aa6e..373b2bf 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -257,19 +257,21 @@ struct _mmc_csd {
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
 #define EXT_CSD_WR_REL_PARAM		166	/* RO */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
-#define EXT_CSD_BOOT_CONFIG		179	/* R/W */
+#define EXT_CSD_PART_CONFIG		179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
 #define EXT_CSD_STRUCTURE		194	/* RO */
 #define EXT_CSD_CARD_TYPE		196	/* RO */
+#define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
 #define EXT_CSD_SEC_CNT			212	/* RO, 4 bytes */
 #define EXT_CSD_S_A_TIMEOUT		217	/* RO */
 #define EXT_CSD_REL_WR_SEC_C		222	/* RO */
 #define EXT_CSD_HC_WP_GRP_SIZE		221	/* RO */
 #define EXT_CSD_ERASE_TIMEOUT_MULT	223	/* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE	224	/* RO */
+#define EXT_CSD_BOOT_MULT		226	/* RO */
 #define EXT_CSD_SEC_TRIM_MULT		229	/* RO */
 #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
@@ -281,6 +283,10 @@ struct _mmc_csd {
 
 #define EXT_CSD_WR_REL_PARAM_EN		(1<<2)
 
+#define EXT_CSD_PART_CONFIG_ACC_MASK	(0x7)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT0	(0x1)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT1	(0x2)
+
 #define EXT_CSD_CMD_SET_NORMAL		(1<<0)
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-11 21:13                           ` [patchv3 4/4] MMC: MMC boot partitions support Andrei Warkentin
@ 2011-04-11 22:00                             ` Chris Ball
  2011-04-11 22:10                               ` Andrei Warkentin
  2011-04-21  1:13                             ` Chris Ball
  1 sibling, 1 reply; 63+ messages in thread
From: Chris Ball @ 2011-04-11 22:00 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc, arnd

Hi Andrei,

On Mon, Apr 11 2011, Andrei Warkentin wrote:
> Allows device MMC boot partitions to be accessed. MMC partitions
> are treated effectively as separate block devices on the same
> MMC card.
>
> Acked-by: Arnd Bergmann <arnd@arndb.de>
> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>

Looks fine, but would you mind breaking out the {claim,release}_host
changes around mmc_blk_issue_rq() into a separate patch?  It doesn't
look like they're obviously related to the partitioning support, but
maybe I'm missing something.

Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-11 22:00                             ` Chris Ball
@ 2011-04-11 22:10                               ` Andrei Warkentin
  2011-04-11 22:22                                 ` Chris Ball
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-11 22:10 UTC (permalink / raw)
  To: Chris Ball; +Cc: linux-mmc, arnd

On Mon, Apr 11, 2011 at 5:00 PM, Chris Ball <cjb@laptop.org> wrote:
> Hi Andrei,
>
> On Mon, Apr 11 2011, Andrei Warkentin wrote:
>> Allows device MMC boot partitions to be accessed. MMC partitions
>> are treated effectively as separate block devices on the same
>> MMC card.
>>
>> Acked-by: Arnd Bergmann <arnd@arndb.de>
>> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
>
> Looks fine, but would you mind breaking out the {claim,release}_host
> changes around mmc_blk_issue_rq() into a separate patch?  It doesn't
> look like they're obviously related to the partitioning support, but
> maybe I'm missing something.
>

So it was one of the two -
a) stick mmc_bkl_part_switch into mmc_blk_issue_secdiscard_rq,
mmc_blk_issue_discard_rq,  and mmc_blk_issue_rw_rq.
b) Move claim/release into mmc_blk_issue_rq and put partition switch
code into one place.

(b) is cleaner.  What do you think?

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-11 22:22                                 ` Chris Ball
@ 2011-04-11 22:18                                   ` Andrei Warkentin
  2011-04-11 23:10                                     ` [patchv4 1/2] MMC: block.c cleanup for host claim/release Andrei Warkentin
                                                       ` (2 more replies)
  0 siblings, 3 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-11 22:18 UTC (permalink / raw)
  To: Chris Ball; +Cc: linux-mmc, arnd

On Mon, Apr 11, 2011 at 5:22 PM, Chris Ball <cjb@laptop.org> wrote:
> Hi Andrei,
>
> On Mon, Apr 11 2011, Andrei Warkentin wrote:
>> So it was one of the two -
>> a) stick mmc_bkl_part_switch into mmc_blk_issue_secdiscard_rq,
>> mmc_blk_issue_discard_rq,  and mmc_blk_issue_rw_rq.
>> b) Move claim/release into mmc_blk_issue_rq and put partition switch
>> code into one place.
>>
>> (b) is cleaner.  What do you think?
>
> Thanks, I see.
>
> (b) is definitely fine -- I'm suggesting one patch to push claim/release
> up into mmc_blk_issue_rq() (which should have no other side-effects),
> and then a second patch to add partitioning support and also insert the
> single mmc_blk_part_switch() into the right place.  Does that make sense?
>

Ok, great! Will do.

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-11 22:10                               ` Andrei Warkentin
@ 2011-04-11 22:22                                 ` Chris Ball
  2011-04-11 22:18                                   ` Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Chris Ball @ 2011-04-11 22:22 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc, arnd

Hi Andrei,

On Mon, Apr 11 2011, Andrei Warkentin wrote:
> So it was one of the two -
> a) stick mmc_bkl_part_switch into mmc_blk_issue_secdiscard_rq,
> mmc_blk_issue_discard_rq,  and mmc_blk_issue_rw_rq.
> b) Move claim/release into mmc_blk_issue_rq and put partition switch
> code into one place.
>
> (b) is cleaner.  What do you think?

Thanks, I see.

(b) is definitely fine -- I'm suggesting one patch to push claim/release
up into mmc_blk_issue_rq() (which should have no other side-effects),
and then a second patch to add partitioning support and also insert the
single mmc_blk_part_switch() into the right place.  Does that make sense?

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [patchv4 1/2] MMC: block.c cleanup for host claim/release.
  2011-04-11 22:18                                   ` Andrei Warkentin
@ 2011-04-11 23:10                                     ` Andrei Warkentin
  2011-04-11 23:10                                     ` [patchv4 2/2] MMC: MMC boot partitions support Andrei Warkentin
  2011-04-11 23:20                                     ` [patchv3 4/4] " Chris Ball
  2 siblings, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-11 23:10 UTC (permalink / raw)
  To: linux-mmc; +Cc: arnd, cjb, Andrei Warkentin

Move host claim/release into mmc_blk_issue_rq.

Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 drivers/mmc/card/block.c |   31 +++++++++++++------------------
 1 files changed, 13 insertions(+), 18 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 91a6767..3e9082b 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -273,8 +273,6 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_erase(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -294,8 +292,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -307,8 +303,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
 	unsigned int from, nr, arg;
 	int err = 0;
 
-	mmc_claim_host(card->host);
-
 	if (!mmc_can_secure_erase_trim(card)) {
 		err = -EOPNOTSUPP;
 		goto out;
@@ -330,8 +324,6 @@ out:
 	__blk_end_request(req, err, blk_rq_bytes(req));
 	spin_unlock_irq(&md->lock);
 
-	mmc_release_host(card->host);
-
 	return err ? 0 : 1;
 }
 
@@ -402,8 +394,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		(rq_data_dir(req) == WRITE) &&
 		REL_WRITES_SUPPORTED(card);
 
-	mmc_claim_host(card->host);
-
 	do {
 		struct mmc_command cmd;
 		u32 readcmd, writecmd, status = 0;
@@ -589,8 +579,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	} while (ret);
 
-	mmc_release_host(card->host);
-
 	return 1;
 
  cmd_err:
@@ -617,8 +605,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 		spin_unlock_irq(&md->lock);
 	}
 
-	mmc_release_host(card->host);
-
 	spin_lock_irq(&md->lock);
 	while (ret)
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
@@ -629,16 +615,25 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 
 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
+	int ret;
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+
+	mmc_claim_host(card->host);
+
 	if (req->cmd_flags & REQ_DISCARD) {
 		if (req->cmd_flags & REQ_SECURE)
-			return mmc_blk_issue_secdiscard_rq(mq, req);
+			ret = mmc_blk_issue_secdiscard_rq(mq, req);
 		else
-			return mmc_blk_issue_discard_rq(mq, req);
+			ret = mmc_blk_issue_discard_rq(mq, req);
 	} else if (req->cmd_flags & REQ_FLUSH) {
-		return mmc_blk_issue_flush(mq, req);
+		ret = mmc_blk_issue_flush(mq, req);
 	} else {
-		return mmc_blk_issue_rw_rq(mq, req);
+		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
+
+	mmc_release_host(card->host);
+	return ret;
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [patchv4 2/2] MMC: MMC boot partitions support.
  2011-04-11 22:18                                   ` Andrei Warkentin
  2011-04-11 23:10                                     ` [patchv4 1/2] MMC: block.c cleanup for host claim/release Andrei Warkentin
@ 2011-04-11 23:10                                     ` Andrei Warkentin
  2011-04-11 23:20                                     ` [patchv3 4/4] " Chris Ball
  2 siblings, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-11 23:10 UTC (permalink / raw)
  To: linux-mmc; +Cc: arnd, cjb, Andrei Warkentin

Allows device MMC boot partitions to be accessed. MMC partitions
are treated effectively as separate block devices on the same
MMC card.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 Documentation/mmc/00-INDEX          |    2 +
 Documentation/mmc/mmc-dev-attrs.txt |   10 ++
 Documentation/mmc/mmc-dev-parts.txt |   26 ++++
 drivers/mmc/card/block.c            |  274 ++++++++++++++++++++++++++++++-----
 drivers/mmc/core/mmc.c              |   22 ++-
 include/linux/mmc/card.h            |    4 +-
 include/linux/mmc/mmc.h             |    8 +-
 7 files changed, 304 insertions(+), 42 deletions(-)
 create mode 100644 Documentation/mmc/mmc-dev-parts.txt

diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX
index fca586f..93dd7a7 100644
--- a/Documentation/mmc/00-INDEX
+++ b/Documentation/mmc/00-INDEX
@@ -2,3 +2,5 @@
         - this file
 mmc-dev-attrs.txt
         - info on SD and MMC device attributes
+mmc-dev-parts.txt
+        - info on SD and MMC device partitions
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index ff2bd68..8898a95 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -1,3 +1,13 @@
+SD and MMC Block Device Attributes
+==================================
+
+These attributes are defined for the block devices associated with the
+SD or MMC device.
+
+The following attributes are read/write.
+
+	force_ro		Enforce read-only access even if write protect switch is off.
+
 SD and MMC Device Attributes
 ============================
 
diff --git a/Documentation/mmc/mmc-dev-parts.txt b/Documentation/mmc/mmc-dev-parts.txt
new file mode 100644
index 0000000..8821909
--- /dev/null
+++ b/Documentation/mmc/mmc-dev-parts.txt
@@ -0,0 +1,26 @@
+SD and MMC Device Partitions
+============================
+
+Device partitions are additional logical block devices present
+on the SD/MMC device.
+
+As of this writing, MMC boot partitions as supported and exposed as 
+/dev/mmcblkXboot0 and /dev/mmcblkXboot1, where X is the index of the
+parent /dev/mmcblkX.
+
+MMC Boot Partitions
+===================
+
+Read and write access is provided to the two MMC boot partitions. Due
+to the sensitive nature of the boot partition contents, which often store
+a bootloader or bootloader configuration tables crucial to booting the platform,
+write access is by default disabled to reduce the chance of accidental bricking.
+
+To enable write access to /dev/mmcblkXbootY, disable the forced read-only
+access:
+
+echo 0 > /sys/block/mmcblkXbootY/force_ro
+
+To re-enable read-only access:
+
+echo 1 > /sys/block/mmcblkXbootY/force_ro
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 3e9082b..1e6bd91 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -76,9 +76,19 @@ struct mmc_blk_data {
 	spinlock_t	lock;
 	struct gendisk	*disk;
 	struct mmc_queue queue;
+	struct list_head part;
 
 	unsigned int	usage;
 	unsigned int	read_only;
+	unsigned int	part_type;
+
+	/*
+	 * Only set in main mmc_blk_data associated
+	 * with mmc_card with mmc_set_drvdata, and keeps
+	 * track of the current selected device partition.
+	 */
+	unsigned int	part_curr;
+	struct device_attribute force_ro;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -101,17 +111,22 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 	return md;
 }
 
+static inline int mmc_get_devidx(struct gendisk *disk)
+{
+	int devmaj = MAJOR(disk_devt(disk));
+	int devidx = MINOR(disk_devt(disk)) / perdev_minors;
+
+	if (!devmaj)
+		devidx = disk->first_minor / perdev_minors;
+	return devidx;
+}
+
 static void mmc_blk_put(struct mmc_blk_data *md)
 {
 	mutex_lock(&open_lock);
 	md->usage--;
 	if (md->usage == 0) {
-		int devmaj = MAJOR(disk_devt(md->disk));
-		int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
-
-		if (!devmaj)
-			devidx = md->disk->first_minor / perdev_minors;
-
+		int devidx = mmc_get_devidx(md->disk);
 		blk_cleanup_queue(md->queue.queue);
 
 		__clear_bit(devidx, dev_use);
@@ -122,6 +137,38 @@ static void mmc_blk_put(struct mmc_blk_data *md)
 	mutex_unlock(&open_lock);
 }
 
+static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	int ret;
+	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+
+	ret = snprintf(buf, PAGE_SIZE, "%d",
+		       get_disk_ro(dev_to_disk(dev)) ^
+		       md->read_only);
+	mmc_blk_put(md);
+	return ret;
+}
+
+static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	int ret;
+	char *end;
+	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+	unsigned long set = simple_strtoul(buf, &end, 0);
+	if (end == buf) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	set_disk_ro(dev_to_disk(dev), set || md->read_only);
+	ret = count;
+out:
+	mmc_blk_put(md);
+	return ret;
+}
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -176,6 +223,29 @@ struct mmc_blk_request {
 	struct mmc_data		data;
 };
 
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+				      struct mmc_blk_data *md)
+{
+	int ret;
+	struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+	if (main_md->part_curr == md->part_type)
+		return 0;
+
+	if (mmc_card_mmc(card)) {
+		card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+		card->ext_csd.part_config |= md->part_type;
+
+		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
+				 card->ext_csd.part_time);
+		if (ret)
+			return ret;
+}
+
+	main_md->part_curr = md->part_type;
+	return 0;
+}
+
 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 {
 	int err;
@@ -620,6 +690,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 	struct mmc_card *card = md->queue.card;
 
 	mmc_claim_host(card->host);
+	ret = mmc_blk_part_switch(card, md);
+	if (ret) {
+		ret = 0;
+		goto out;
+	}
 
 	if (req->cmd_flags & REQ_DISCARD) {
 		if (req->cmd_flags & REQ_SECURE)
@@ -632,6 +707,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 		ret = mmc_blk_issue_rw_rq(mq, req);
 	}
 
+out:
 	mmc_release_host(card->host);
 	return ret;
 }
@@ -642,7 +718,11 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
 	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
 }
 
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+					      struct device *parent,
+					      sector_t size,
+					      bool default_ro,
+					      const char *subname)
 {
 	struct mmc_blk_data *md;
 	int devidx, ret;
@@ -658,7 +738,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 		goto out;
 	}
 
-
 	/*
 	 * Set the read-only status based on the supported commands
 	 * and the write protect switch.
@@ -672,6 +751,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	}
 
 	spin_lock_init(&md->lock);
+	INIT_LIST_HEAD(&md->part);
 	md->usage = 1;
 
 	ret = mmc_init_queue(&md->queue, card, &md->lock);
@@ -686,8 +766,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	md->disk->fops = &mmc_bdops;
 	md->disk->private_data = md;
 	md->disk->queue = md->queue.queue;
-	md->disk->driverfs_dev = &card->dev;
-	set_disk_ro(md->disk, md->read_only);
+	md->disk->driverfs_dev = parent;
+	set_disk_ro(md->disk, md->read_only || default_ro);
 	if (REL_WRITES_SUPPORTED(card))
 		blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
 
@@ -703,33 +783,97 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	 * messages to tell when the card is present.
 	 */
 
-	snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
-		"mmcblk%d", devidx);
+	if (subname)
+		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+			 "mmcblk%d%s",
+			 mmc_get_devidx(dev_to_disk(parent)), subname);
+	else
+		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+			 "mmcblk%d", devidx);
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
+	set_capacity(md->disk, size);
+	return md;
+
+ err_putdisk:
+	put_disk(md->disk);
+ err_kfree:
+	kfree(md);
+ out:
+	return ERR_PTR(ret);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+	sector_t size;
+	struct mmc_blk_data *md;
 
 	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);
+		size = 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));
+		size = card->csd.capacity << (card->csd.read_blkbits - 9);
 	}
+
+	md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
 	return md;
+}
 
- err_putdisk:
-	put_disk(md->disk);
- err_kfree:
-	kfree(md);
- out:
-	return ERR_PTR(ret);
+static int mmc_blk_alloc_part(struct mmc_card *card,
+			      struct mmc_blk_data *md,
+			      unsigned int part_type,
+			      sector_t size,
+			      bool default_ro,
+			      const char *subname)
+{
+	char cap_str[10];
+	struct mmc_blk_data *part_md;
+
+	part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
+				    subname);
+	if (IS_ERR(part_md))
+		return PTR_ERR(part_md);
+	part_md->part_type = part_type;
+	list_add(&part_md->part, &md->part);
+
+	string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
+			cap_str, sizeof(cap_str));
+	printk(KERN_INFO "%s: %s %s partition %u %s\n",
+	       part_md->disk->disk_name, mmc_card_id(card),
+	       mmc_card_name(card), part_md->part_type, cap_str);
+	return 0;
+}
+
+static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
+{
+	int ret = 0;
+
+	if (!mmc_card_mmc(card))
+		return 0;
+
+	if (card->ext_csd.boot_size) {
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0,
+					 card->ext_csd.boot_size >> 9,
+					 true,
+					 "boot0");
+		if (ret)
+			return ret;
+		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT1,
+					 card->ext_csd.boot_size >> 9,
+					 true,
+					 "boot1");
+		if (ret)
+			return ret;
+	}
+
+	return ret;
 }
 
 static int
@@ -750,9 +894,54 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 	return 0;
 }
 
+static void mmc_blk_remove_req(struct mmc_blk_data *md)
+{
+	if (md) {
+		if (md->disk->flags & GENHD_FL_UP) {
+			device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+
+			/* Stop new requests from getting into the queue */
+			del_gendisk(md->disk);
+		}
+
+		/* Then flush out any already in there */
+		mmc_cleanup_queue(&md->queue);
+		mmc_blk_put(md);
+	}
+}
+
+static void mmc_blk_remove_parts(struct mmc_card *card,
+				 struct mmc_blk_data *md)
+{
+	struct list_head *pos, *q;
+	struct mmc_blk_data *part_md;
+
+	list_for_each_safe(pos, q, &md->part) {
+		part_md = list_entry(pos, struct mmc_blk_data, part);
+		list_del(pos);
+		mmc_blk_remove_req(part_md);
+	}
+}
+
+static int mmc_add_disk(struct mmc_blk_data *md)
+{
+	int ret;
+
+	add_disk(md->disk);
+	md->force_ro.show = force_ro_show;
+	md->force_ro.store = force_ro_store;
+	md->force_ro.attr.name = "force_ro";
+	md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
+	ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
+	if (ret)
+		del_gendisk(md->disk);
+
+	return ret;
+}
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
-	struct mmc_blk_data *md;
+	struct mmc_blk_data *md, *part_md;
 	int err;
 	char cap_str[10];
 
@@ -776,14 +965,22 @@ static int mmc_blk_probe(struct mmc_card *card)
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
 		cap_str, md->read_only ? "(ro)" : "");
 
+	if (mmc_blk_alloc_parts(card, md))
+		goto out;
+
 	mmc_set_drvdata(card, md);
-	add_disk(md->disk);
+	if (mmc_add_disk(md))
+		goto out;
+
+	list_for_each_entry(part_md, &md->part, part) {
+		if (mmc_add_disk(part_md))
+			goto out;
+	}
 	return 0;
 
  out:
-	mmc_cleanup_queue(&md->queue);
-	mmc_blk_put(md);
-
+	mmc_blk_remove_parts(card, md);
+	mmc_blk_remove_req(md);
 	return err;
 }
 
@@ -791,36 +988,43 @@ static void mmc_blk_remove(struct mmc_card *card)
 {
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
-	if (md) {
-		/* Stop new requests from getting into the queue */
-		del_gendisk(md->disk);
-
-		/* Then flush out any already in there */
-		mmc_cleanup_queue(&md->queue);
-
-		mmc_blk_put(md);
-	}
+	mmc_blk_remove_parts(card, md);
+	mmc_blk_remove_req(md);
 	mmc_set_drvdata(card, NULL);
 }
 
 #ifdef CONFIG_PM
 static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_queue_suspend(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_suspend(&part_md->queue);
+		}
 	}
 	return 0;
 }
 
 static int mmc_blk_resume(struct mmc_card *card)
 {
+	struct mmc_blk_data *part_md;
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
 		mmc_blk_set_blksize(md, card);
+
+		/*
+		 * Resume involves the card going into idle state,
+		 * so current partition is always the main one.
+		 */
+		md->part_curr = md->part_type;
 		mmc_queue_resume(&md->queue);
+		list_for_each_entry(part_md, &md->part, part) {
+			mmc_queue_resume(&part_md->queue);
+		}
 	}
 	return 0;
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 396cb23..a2c795e 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -288,7 +288,10 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
 	if (card->ext_csd.rev >= 3) {
 		u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
-		card->ext_csd.bootconfig = ext_csd[EXT_CSD_BOOT_CONFIG];
+		card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
+
+		/* EXT_CSD value is in units of 10ms, but we store in ms */
+		card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
 
 		/* Sleep / awake timeout in 100ns units */
 		if (sa_shift > 0 && sa_shift <= 0x17)
@@ -302,6 +305,12 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
 
 		card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C];
+
+		/*
+		 * There are two boot regions of equal size, defined in
+		 * multiples of 128K.
+		 */
+		card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
 	}
 
 	if (card->ext_csd.rev >= 4) {
@@ -576,10 +585,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Ensure eMMC user default partition is enabled
 	 */
-	if (card->ext_csd.bootconfig & 0x7) {
-		card->ext_csd.bootconfig &= ~0x7;
-		mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_CONFIG,
-			   card->ext_csd.bootconfig, 0);
+	if (card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK) {
+		card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,
+				 card->ext_csd.part_config,
+				 card->ext_csd.part_time);
+		if (err && err != -EBADMSG)
+			goto free_card;
 	}
 
 	/*
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c651317..8ac96f7 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -48,7 +48,8 @@ struct mmc_ext_csd {
 	u8			sec_feature_support;
 	u8			rel_sectors;
 	u8			rel_param;
-	u8			bootconfig;
+	u8			part_config;
+	unsigned int		part_time;		/* Units: ms */
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
@@ -61,6 +62,7 @@ struct mmc_ext_csd {
 	bool			enhanced_area_en;	/* enable bit */
 	unsigned long long	enhanced_area_offset;	/* Units: Byte */
 	unsigned int		enhanced_area_size;	/* Units: KB */
+	unsigned int		boot_size;		/* in bytes */
 };
 
 struct sd_scr {
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 390aa6e..373b2bf 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -257,19 +257,21 @@ struct _mmc_csd {
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
 #define EXT_CSD_WR_REL_PARAM		166	/* RO */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
-#define EXT_CSD_BOOT_CONFIG		179	/* R/W */
+#define EXT_CSD_PART_CONFIG		179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
 #define EXT_CSD_STRUCTURE		194	/* RO */
 #define EXT_CSD_CARD_TYPE		196	/* RO */
+#define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
 #define EXT_CSD_SEC_CNT			212	/* RO, 4 bytes */
 #define EXT_CSD_S_A_TIMEOUT		217	/* RO */
 #define EXT_CSD_REL_WR_SEC_C		222	/* RO */
 #define EXT_CSD_HC_WP_GRP_SIZE		221	/* RO */
 #define EXT_CSD_ERASE_TIMEOUT_MULT	223	/* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE	224	/* RO */
+#define EXT_CSD_BOOT_MULT		226	/* RO */
 #define EXT_CSD_SEC_TRIM_MULT		229	/* RO */
 #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
@@ -281,6 +283,10 @@ struct _mmc_csd {
 
 #define EXT_CSD_WR_REL_PARAM_EN		(1<<2)
 
+#define EXT_CSD_PART_CONFIG_ACC_MASK	(0x7)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT0	(0x1)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT1	(0x2)
+
 #define EXT_CSD_CMD_SET_NORMAL		(1<<0)
 #define EXT_CSD_CMD_SET_SECURE		(1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-11 22:18                                   ` Andrei Warkentin
  2011-04-11 23:10                                     ` [patchv4 1/2] MMC: block.c cleanup for host claim/release Andrei Warkentin
  2011-04-11 23:10                                     ` [patchv4 2/2] MMC: MMC boot partitions support Andrei Warkentin
@ 2011-04-11 23:20                                     ` Chris Ball
  2011-04-11 23:24                                       ` Andrei Warkentin
  2 siblings, 1 reply; 63+ messages in thread
From: Chris Ball @ 2011-04-11 23:20 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc, arnd

Hi Andrei,

On Mon, Apr 11 2011, Andrei Warkentin wrote:
> Ok, great! Will do.

Great, thanks.  I've just merged:

mmc: quirks: Extends card quirks with MMC/SD quirks matching the CID.
[patchv3 1/4] MMC: Rename erase_timeout to cmd_timeout_ms.
[patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
[patchv3 3/4] MMC: Allow setting CMD timeout for CMD6 (SWITCH).
[patchv4 1/2] MMC: block.c cleanup for host claim/release.
[patchv4 2/2] MMC: MMC boot partitions support.
[PATCH 1/2] MMC: Support for block quirks.
 ^ this had a merge conflict with the partitions patch, easily resolved.
[PATCH 2/2] MMC: Fix erase/trim for certain SanDisk cards.

in that order, and will push out to mmc-next for .40 after a little
testing.  Let me know if anything's been missed or applied in the wrong
order there.

Thanks very much,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-11 23:20                                     ` [patchv3 4/4] " Chris Ball
@ 2011-04-11 23:24                                       ` Andrei Warkentin
  0 siblings, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-11 23:24 UTC (permalink / raw)
  To: Chris Ball; +Cc: linux-mmc, arnd

On Mon, Apr 11, 2011 at 6:20 PM, Chris Ball <cjb@laptop.org> wrote:
> Hi Andrei,
>
> On Mon, Apr 11 2011, Andrei Warkentin wrote:
>> Ok, great! Will do.
>
> Great, thanks.  I've just merged:
>
> mmc: quirks: Extends card quirks with MMC/SD quirks matching the CID.
> [patchv3 1/4] MMC: Rename erase_timeout to cmd_timeout_ms.
> [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
> [patchv3 3/4] MMC: Allow setting CMD timeout for CMD6 (SWITCH).
> [patchv4 1/2] MMC: block.c cleanup for host claim/release.
> [patchv4 2/2] MMC: MMC boot partitions support.
> [PATCH 1/2] MMC: Support for block quirks.
>  ^ this had a merge conflict with the partitions patch, easily resolved.
> [PATCH 2/2] MMC: Fix erase/trim for certain SanDisk cards.
>
> in that order, and will push out to mmc-next for .40 after a little
> testing.  Let me know if anything's been missed or applied in the wrong
> order there.

Should be alright.

Thanks,
A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
  2011-04-11 21:13                           ` [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE Andrei Warkentin
@ 2011-04-12  9:06                             ` Dong, Chuanxiao
  2011-04-12 18:05                               ` Andrei Warkentin
  2011-08-10 13:30                             ` Chris Ball
  1 sibling, 1 reply; 63+ messages in thread
From: Dong, Chuanxiao @ 2011-04-12  9:06 UTC (permalink / raw)
  To: Andrei Warkentin, linux-mmc; +Cc: arnd, cjb



> -----Original Message-----
> From: linux-mmc-owner@vger.kernel.org
> [mailto:linux-mmc-owner@vger.kernel.org] On Behalf Of Andrei Warkentin
> Sent: Tuesday, April 12, 2011 5:14 AM
> To: linux-mmc@vger.kernel.org
> Cc: arnd@arndb.de; cjb@laptop.org; Andrei Warkentin
> Subject: [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
> 
> ERASE command needs R1B response, so fix R1B-type command
> handling for SDHCI controller. For non-DAT commands using a busy
> reponse, the cmd->cmd_timeout_ms (in ms) field is used for timeout
> calculations.
> 
> Based on patch by Chuanxiao Dong <chuanxiao.dong@intel.com>
> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
> ---
>  drivers/mmc/host/sdhci.c |   43 +++++++++++++++++++++++++++----------------
>  1 files changed, 27 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 9e15f41..173e980 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -40,7 +40,6 @@
> 
>  static unsigned int debug_quirks = 0;
> 
> -static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
>  static void sdhci_finish_data(struct sdhci_host *);
> 
>  static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
> @@ -591,9 +590,10 @@ static void sdhci_adma_table_post(struct sdhci_host
> *host,
>  		data->sg_len, direction);
>  }
> 
> -static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
> +static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command
> *cmd)
>  {
>  	u8 count;
> +	struct mmc_data *data = cmd->data;
>  	unsigned target_timeout, current_timeout;
> 
>  	/*
> @@ -605,12 +605,16 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host,
> struct mmc_data *data)
>  	if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
>  		return 0xE;
> 
> -	/* timeout in us */
> -	target_timeout = data->timeout_ns / 1000 +
> -		data->timeout_clks / host->clock;
> +	/* Unspecified timeout, assume max */
> +	if (!data && !cmd->cmd_timeout_ms)
> +		return 0xE;
Just a inline question here. I noticed cmd_timeout_ms only be set for the ERASE command and SWITCH command, for other types of commands, this value is left not initialized. Cmd_timeout_ms may not be zero and also not be initialized. And next, driver will use this value to calculate the timeout. So I think using an uninitialized value here doesn't make sense. If we want to use it, we have to make sure at this point, this value is already initialized.

> 
> -	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
> -		host->timeout_clk = host->clock / 1000;
> +	/* timeout in us */
> +	if (!data)
> +		target_timeout = cmd->cmd_timeout_ms * 1000;
That is where I concerned about the uninitialized cmd_timeout_ms.

> +	else
> +		target_timeout = data->timeout_ns / 1000 +
> +			data->timeout_clks / host->clock;
> 
>  	/*
>  	 * Figure out needed cycles.
> @@ -632,8 +636,9 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host,
> struct mmc_data *data)
>  	}
> 
>  	if (count >= 0xF) {
> -		printk(KERN_WARNING "%s: Too large timeout requested!\n",
> -			mmc_hostname(host->mmc));
> +		printk(KERN_WARNING "%s: Too large timeout requested for
> CMD%d!\n",
> +		       mmc_hostname(host->mmc),
> +		       cmd->opcode);
>  		count = 0xE;
>  	}
> 
> @@ -651,15 +656,21 @@ static void sdhci_set_transfer_irqs(struct sdhci_host
> *host)
>  		sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
>  }
> 
> -static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
> +static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command
> *cmd)
>  {
>  	u8 count;
>  	u8 ctrl;
> +	struct mmc_data *data = cmd->data;
>  	int ret;
> 
>  	WARN_ON(host->data);
> 
> -	if (data == NULL)
> +	if (data || (cmd->flags & MMC_RSP_BUSY)) {
> +		count = sdhci_calc_timeout(host, cmd);
> +		sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
> +	}
> +
> +	if (!data)
>  		return;
> 
>  	/* Sanity checks */
> @@ -670,9 +681,6 @@ static void sdhci_prepare_data(struct sdhci_host *host,
> struct mmc_data *data)
>  	host->data = data;
>  	host->data_early = 0;
> 
> -	count = sdhci_calc_timeout(host, data);
> -	sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
> -
>  	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
>  		host->flags |= SDHCI_REQ_USE_DMA;
> 
> @@ -920,7 +928,7 @@ static void sdhci_send_command(struct sdhci_host *host,
> struct mmc_command *cmd)
> 
>  	host->cmd = cmd;
> 
> -	sdhci_prepare_data(host, cmd->data);
> +	sdhci_prepare_data(host, cmd);
> 
>  	sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
> 
> @@ -1867,6 +1875,9 @@ int sdhci_add_host(struct sdhci_host *host)
>  	if (caps & SDHCI_TIMEOUT_CLK_UNIT)
>  		host->timeout_clk *= 1000;
> 
> +	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
> +		host->timeout_clk = host->clock / 1000;
> +
>  	/*
>  	 * Set host parameters.
>  	 */
> @@ -1879,7 +1890,7 @@ int sdhci_add_host(struct sdhci_host *host)
>  		mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
> 
>  	mmc->f_max = host->max_clk;
> -	mmc->caps |= MMC_CAP_SDIO_IRQ;
> +	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE;
> 
>  	/*
>  	 * A controller may support 8-bit width, but the board itself
> --
> 1.7.0.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
  2011-04-12  9:06                             ` Dong, Chuanxiao
@ 2011-04-12 18:05                               ` Andrei Warkentin
  2011-04-13  1:59                                 ` Dong, Chuanxiao
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-12 18:05 UTC (permalink / raw)
  To: Dong, Chuanxiao; +Cc: linux-mmc, arnd, cjb

On Tue, Apr 12, 2011 at 4:06 AM, Dong, Chuanxiao
<chuanxiao.dong@intel.com> wrote:
>
>
>> -----Original Message-----
>> From: linux-mmc-owner@vger.kernel.org
>> [mailto:linux-mmc-owner@vger.kernel.org] On Behalf Of Andrei Warkentin
>> Sent: Tuesday, April 12, 2011 5:14 AM
>> To: linux-mmc@vger.kernel.org
>> Cc: arnd@arndb.de; cjb@laptop.org; Andrei Warkentin
>> Subject: [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
>>
>> ERASE command needs R1B response, so fix R1B-type command
>> handling for SDHCI controller. For non-DAT commands using a busy
>> reponse, the cmd->cmd_timeout_ms (in ms) field is used for timeout
>> calculations.
>>
>> Based on patch by Chuanxiao Dong <chuanxiao.dong@intel.com>
>> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
>> ---
>>  drivers/mmc/host/sdhci.c |   43 +++++++++++++++++++++++++++----------------
>>  1 files changed, 27 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> index 9e15f41..173e980 100644
>> --- a/drivers/mmc/host/sdhci.c
>> +++ b/drivers/mmc/host/sdhci.c
>> @@ -40,7 +40,6 @@
>>
>>  static unsigned int debug_quirks = 0;
>>
>> -static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
>>  static void sdhci_finish_data(struct sdhci_host *);
>>
>>  static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
>> @@ -591,9 +590,10 @@ static void sdhci_adma_table_post(struct sdhci_host
>> *host,
>>               data->sg_len, direction);
>>  }
>>
>> -static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
>> +static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command
>> *cmd)
>>  {
>>       u8 count;
>> +     struct mmc_data *data = cmd->data;
>>       unsigned target_timeout, current_timeout;
>>
>>       /*
>> @@ -605,12 +605,16 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host,
>> struct mmc_data *data)
>>       if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
>>               return 0xE;
>>
>> -     /* timeout in us */
>> -     target_timeout = data->timeout_ns / 1000 +
>> -             data->timeout_clks / host->clock;
>> +     /* Unspecified timeout, assume max */
>> +     if (!data && !cmd->cmd_timeout_ms)
>> +             return 0xE;
> Just a inline question here. I noticed cmd_timeout_ms only be set for the ERASE command and SWITCH command, for other types of commands, this value is left not initialized. Cmd_timeout_ms may not be zero and also not be initialized. And next, driver will use this value to calculate the timeout. So I think using an uninitialized value here doesn't make sense. If we want to use it, we have to make sure at this point, this value is already initialized.

First, cmd_timeout only has meaning for non-DAT-transfer commands
using DAT as a busy indicator.  This is exactly why the cmd_timeout_ms
affects the "data timeout" on the host. Hence - cmd_timeout_ms only
makes sense for R1b commands. (R5b too, but that's SDIO land and I
don't want to push support for something I can't verify) Second - if
it's not initialized, it is zero (look in block.c, the entire brq is
cleared to 0, look in mmc_ops, sd_ops, sdio_ops).

Remember, if !data and !cmd_timeout, then this must be a busy-wait
command with no timeout specified, we pick the safe maximum of 0xE.
Also again, this timeout has any meaning (and is only calculated) only
if the command actually leverages the DAT line.

What commands are you interested in? There are not a lot of R1b
commands. This patch addressed missing DAT timeout for R1b commands
like erase, switch, etc.

>
>>
>> -     if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
>> -             host->timeout_clk = host->clock / 1000;
>> +     /* timeout in us */
>> +     if (!data)
>> +             target_timeout = cmd->cmd_timeout_ms * 1000;
> That is where I concerned about the uninitialized cmd_timeout_ms.

You claim it's uninitialized, but it is zero because all consumers of
mmc_command memset the structure to 0.

>
>> +     else
>> +             target_timeout = data->timeout_ns / 1000 +
>> +                     data->timeout_clks / host->clock;
>>
>>       /*
>>        * Figure out needed cycles.
>> @@ -632,8 +636,9 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host,
>> struct mmc_data *data)
>>       }
>>
>>       if (count >= 0xF) {
>> -             printk(KERN_WARNING "%s: Too large timeout requested!\n",
>> -                     mmc_hostname(host->mmc));
>> +             printk(KERN_WARNING "%s: Too large timeout requested for
>> CMD%d!\n",
>> +                    mmc_hostname(host->mmc),
>> +                    cmd->opcode);
>>               count = 0xE;
>>       }
>>
>> @@ -651,15 +656,21 @@ static void sdhci_set_transfer_irqs(struct sdhci_host
>> *host)
>>               sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
>>  }
>>
>> -static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
>> +static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command
>> *cmd)
>>  {
>>       u8 count;
>>       u8 ctrl;
>> +     struct mmc_data *data = cmd->data;
>>       int ret;
>>
>>       WARN_ON(host->data);
>>
>> -     if (data == NULL)
>> +     if (data || (cmd->flags & MMC_RSP_BUSY)) {
>> +             count = sdhci_calc_timeout(host, cmd);
>> +             sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
>> +     }
>> +
>> +     if (!data)
>>               return;
>>
>>       /* Sanity checks */
>> @@ -670,9 +681,6 @@ static void sdhci_prepare_data(struct sdhci_host *host,
>> struct mmc_data *data)
>>       host->data = data;
>>       host->data_early = 0;
>>
>> -     count = sdhci_calc_timeout(host, data);
>> -     sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
>> -
>>       if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
>>               host->flags |= SDHCI_REQ_USE_DMA;
>>
>> @@ -920,7 +928,7 @@ static void sdhci_send_command(struct sdhci_host *host,
>> struct mmc_command *cmd)
>>
>>       host->cmd = cmd;
>>
>> -     sdhci_prepare_data(host, cmd->data);
>> +     sdhci_prepare_data(host, cmd);
>>
>>       sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
>>
>> @@ -1867,6 +1875,9 @@ int sdhci_add_host(struct sdhci_host *host)
>>       if (caps & SDHCI_TIMEOUT_CLK_UNIT)
>>               host->timeout_clk *= 1000;
>>
>> +     if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
>> +             host->timeout_clk = host->clock / 1000;
>> +
>>       /*
>>        * Set host parameters.
>>        */
>> @@ -1879,7 +1890,7 @@ int sdhci_add_host(struct sdhci_host *host)
>>               mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
>>
>>       mmc->f_max = host->max_clk;
>> -     mmc->caps |= MMC_CAP_SDIO_IRQ;
>> +     mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE;
>>
>>       /*
>>        * A controller may support 8-bit width, but the board itself
>> --
>> 1.7.0.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
  2011-04-12 18:05                               ` Andrei Warkentin
@ 2011-04-13  1:59                                 ` Dong, Chuanxiao
  2011-04-13  5:44                                   ` Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Dong, Chuanxiao @ 2011-04-13  1:59 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc, arnd, cjb



> -----Original Message-----
> From: Andrei Warkentin [mailto:andreiw@motorola.com]
> Sent: Wednesday, April 13, 2011 2:05 AM
> To: Dong, Chuanxiao
> Cc: linux-mmc@vger.kernel.org; arnd@arndb.de; cjb@laptop.org
> Subject: Re: [patchv3 2/4] MMC: SDHCI R1B command handling +
> MMC_CAP_ERASE.
> 
> On Tue, Apr 12, 2011 at 4:06 AM, Dong, Chuanxiao
> <chuanxiao.dong@intel.com> wrote:
> >
> >
> >> -----Original Message-----
> >> From: linux-mmc-owner@vger.kernel.org
> >> [mailto:linux-mmc-owner@vger.kernel.org] On Behalf Of Andrei Warkentin
> >> Sent: Tuesday, April 12, 2011 5:14 AM
> >> To: linux-mmc@vger.kernel.org
> >> Cc: arnd@arndb.de; cjb@laptop.org; Andrei Warkentin
> >> Subject: [patchv3 2/4] MMC: SDHCI R1B command handling +
> MMC_CAP_ERASE.
> >>
> >> ERASE command needs R1B response, so fix R1B-type command
> >> handling for SDHCI controller. For non-DAT commands using a busy
> >> reponse, the cmd->cmd_timeout_ms (in ms) field is used for timeout
> >> calculations.
> >>
> >> Based on patch by Chuanxiao Dong <chuanxiao.dong@intel.com>
> >> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
> >> ---
> >>  drivers/mmc/host/sdhci.c |   43
> +++++++++++++++++++++++++++----------------
> >>  1 files changed, 27 insertions(+), 16 deletions(-)
> >>
> >> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> >> index 9e15f41..173e980 100644
> >> --- a/drivers/mmc/host/sdhci.c
> >> +++ b/drivers/mmc/host/sdhci.c
> >> @@ -40,7 +40,6 @@
> >>
> >>  static unsigned int debug_quirks = 0;
> >>
> >> -static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
> >>  static void sdhci_finish_data(struct sdhci_host *);
> >>
> >>  static void sdhci_send_command(struct sdhci_host *, struct mmc_command
> *);
> >> @@ -591,9 +590,10 @@ static void sdhci_adma_table_post(struct sdhci_host
> >> *host,
> >>               data->sg_len, direction);
> >>  }
> >>
> >> -static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
> >> +static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command
> >> *cmd)
> >>  {
> >>       u8 count;
> >> +     struct mmc_data *data = cmd->data;
> >>       unsigned target_timeout, current_timeout;
> >>
> >>       /*
> >> @@ -605,12 +605,16 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host,
> >> struct mmc_data *data)
> >>       if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
> >>               return 0xE;
> >>
> >> -     /* timeout in us */
> >> -     target_timeout = data->timeout_ns / 1000 +
> >> -             data->timeout_clks / host->clock;
> >> +     /* Unspecified timeout, assume max */
> >> +     if (!data && !cmd->cmd_timeout_ms)
> >> +             return 0xE;
> > Just a inline question here. I noticed cmd_timeout_ms only be set for the ERASE
> command and SWITCH command, for other types of commands, this value is left
> not initialized. Cmd_timeout_ms may not be zero and also not be initialized. And
> next, driver will use this value to calculate the timeout. So I think using an
> uninitialized value here doesn't make sense. If we want to use it, we have to make
> sure at this point, this value is already initialized.
> 
> First, cmd_timeout only has meaning for non-DAT-transfer commands
> using DAT as a busy indicator.  This is exactly why the cmd_timeout_ms
> affects the "data timeout" on the host. Hence - cmd_timeout_ms only
> makes sense for R1b commands. (R5b too, but that's SDIO land and I
> don't want to push support for something I can't verify) Second - if
> it's not initialized, it is zero (look in block.c, the entire brq is
> cleared to 0, look in mmc_ops, sd_ops, sdio_ops).
> 
> Remember, if !data and !cmd_timeout, then this must be a busy-wait
> command with no timeout specified, we pick the safe maximum of 0xE.
> Also again, this timeout has any meaning (and is only calculated) only
> if the command actually leverages the DAT line.
> 
> What commands are you interested in? There are not a lot of R1b
> commands. This patch addressed missing DAT timeout for R1b commands
> like erase, switch, etc.
> 
> >
> >>
> >> -     if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
> >> -             host->timeout_clk = host->clock / 1000;
> >> +     /* timeout in us */
> >> +     if (!data)
> >> +             target_timeout = cmd->cmd_timeout_ms * 1000;
> > That is where I concerned about the uninitialized cmd_timeout_ms.
> 
> You claim it's uninitialized, but it is zero because all consumers of
> mmc_command memset the structure to 0.
Yes, if all the consumers of mmc_command memset the structure to 0, there will be no problem. But just reviewed the code, and found mmc_app_cmd() (in sd_ops.c) didn't memset the command structure. So I think if we can make sure all the command structures will be initialized before using it, that would be better.

> 
> >
> >> +     else
> >> +             target_timeout = data->timeout_ns / 1000 +
> >> +                     data->timeout_clks / host->clock;
> >>
> >>       /*
> >>        * Figure out needed cycles.
> >> @@ -632,8 +636,9 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host,
> >> struct mmc_data *data)
> >>       }
> >>
> >>       if (count >= 0xF) {
> >> -             printk(KERN_WARNING "%s: Too large timeout requested!\n",
> >> -                     mmc_hostname(host->mmc));
> >> +             printk(KERN_WARNING "%s: Too large timeout requested for
> >> CMD%d!\n",
> >> +                    mmc_hostname(host->mmc),
> >> +                    cmd->opcode);
> >>               count = 0xE;
> >>       }
> >>
> >> @@ -651,15 +656,21 @@ static void sdhci_set_transfer_irqs(struct sdhci_host
> >> *host)
> >>               sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
> >>  }
> >>
> >> -static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data
> *data)
> >> +static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command
> >> *cmd)
> >>  {
> >>       u8 count;
> >>       u8 ctrl;
> >> +     struct mmc_data *data = cmd->data;
> >>       int ret;
> >>
> >>       WARN_ON(host->data);
> >>
> >> -     if (data == NULL)
> >> +     if (data || (cmd->flags & MMC_RSP_BUSY)) {
> >> +             count = sdhci_calc_timeout(host, cmd);
> >> +             sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
> >> +     }
> >> +
> >> +     if (!data)
> >>               return;
> >>
> >>       /* Sanity checks */
> >> @@ -670,9 +681,6 @@ static void sdhci_prepare_data(struct sdhci_host *host,
> >> struct mmc_data *data)
> >>       host->data = data;
> >>       host->data_early = 0;
> >>
> >> -     count = sdhci_calc_timeout(host, data);
> >> -     sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
> >> -
> >>       if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
> >>               host->flags |= SDHCI_REQ_USE_DMA;
> >>
> >> @@ -920,7 +928,7 @@ static void sdhci_send_command(struct sdhci_host
> *host,
> >> struct mmc_command *cmd)
> >>
> >>       host->cmd = cmd;
> >>
> >> -     sdhci_prepare_data(host, cmd->data);
> >> +     sdhci_prepare_data(host, cmd);
> >>
> >>       sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
> >>
> >> @@ -1867,6 +1875,9 @@ int sdhci_add_host(struct sdhci_host *host)
> >>       if (caps & SDHCI_TIMEOUT_CLK_UNIT)
> >>               host->timeout_clk *= 1000;
> >>
> >> +     if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
> >> +             host->timeout_clk = host->clock / 1000;
> >> +
> >>       /*
> >>        * Set host parameters.
> >>        */
> >> @@ -1879,7 +1890,7 @@ int sdhci_add_host(struct sdhci_host *host)
> >>               mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
> >>
> >>       mmc->f_max = host->max_clk;
> >> -     mmc->caps |= MMC_CAP_SDIO_IRQ;
> >> +     mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE;
> >>
> >>       /*
> >>        * A controller may support 8-bit width, but the board itself
> >> --
> >> 1.7.0.4
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
  2011-04-13  1:59                                 ` Dong, Chuanxiao
@ 2011-04-13  5:44                                   ` Andrei Warkentin
  2011-04-15 21:34                                     ` Cyril Hrubis
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-13  5:44 UTC (permalink / raw)
  To: Dong, Chuanxiao, metan; +Cc: linux-mmc, arnd, cjb

On Tue, Apr 12, 2011 at 8:59 PM, Dong, Chuanxiao
<chuanxiao.dong@intel.com> wrote:

> Yes, if all the consumers of mmc_command memset the structure to 0, there will be no problem. But just reviewed the code, and found mmc_app_cmd() (in sd_ops.c) didn't memset the command structure. So I think if we can make sure all the command structures will be initialized before using it, that would be better.

I would say that CMD55 is not a command that utilizes the DAT line,
again, so not setting cmd_timeout itself is not a problem.

However, using uninitialized data is nasty, and can lead to problems
if cmd->data ever happens to be not NULL.
I'll send a patch for this tomorrow. Thanks for catching this. I'm
curious if this is the reason behind Cyril's problem.

Cyril can you try modifying mmc_app_cmd like this? Does that do
anything for you?

static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{
        int err;
        struct mmc_command cmd;

        BUG_ON(!host);
        BUG_ON(card && (card->host != host));

+      memset(&cmd, 0, sizeof(struct mmc_command));
        cmd.opcode = MMC_APP_CMD;

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
  2011-04-13  5:44                                   ` Andrei Warkentin
@ 2011-04-15 21:34                                     ` Cyril Hrubis
  0 siblings, 0 replies; 63+ messages in thread
From: Cyril Hrubis @ 2011-04-15 21:34 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: Dong, Chuanxiao, linux-mmc, arnd, cjb

Hi!
> > Yes, if all the consumers of mmc_command memset the structure to 0, there
> > will be no problem. But just reviewed the code, and found mmc_app_cmd() (in
> > sd_ops.c) didn't memset the command structure. So I think if we can make
> > sure all the command structures will be initialized before using it, that
> > would be better.
>
> I would say that CMD55 is not a command that utilizes the DAT line,
> again, so not setting cmd_timeout itself is not a problem.
> 
> However, using uninitialized data is nasty, and can lead to problems
> if cmd->data ever happens to be not NULL.
> I'll send a patch for this tomorrow. Thanks for catching this. I'm
> curious if this is the reason behind Cyril's problem.
> 
> Cyril can you try modifying mmc_app_cmd like this? Does that do
> anything for you?
> 
> static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
> {
>         int err;
>         struct mmc_command cmd;
> 
>         BUG_ON(!host);
>         BUG_ON(card && (card->host != host));
> 
> +      memset(&cmd, 0, sizeof(struct mmc_command));
>         cmd.opcode = MMC_APP_CMD;
>

Not really, it behaves same regardless the memset().

-- 
metan 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-11 21:13                           ` [patchv3 4/4] MMC: MMC boot partitions support Andrei Warkentin
  2011-04-11 22:00                             ` Chris Ball
@ 2011-04-21  1:13                             ` Chris Ball
  2011-04-21  1:30                               ` Chris Ball
  2011-04-21  4:31                               ` [patchv3 4/4] MMC: MMC boot partitions support Jaehoon Chung
  1 sibling, 2 replies; 63+ messages in thread
From: Chris Ball @ 2011-04-21  1:13 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc, arnd

Hi Andrei,

On Mon, Apr 11 2011, Andrei Warkentin wrote:
> Allows device MMC boot partitions to be accessed. MMC partitions
> are treated effectively as separate block devices on the same
> MMC card.

Booted this with a Sandisk SEM04G eMMC:

[    2.469921] mmcblk0boot0: mmc2:0001 SEM04G partition 1 1.00 MiB
[    2.475905] mmcblk0boot1: mmc2:0001 SEM04G partition 2 1.00 MiB
[    2.489403]  mmcblk0boot1: unknown partition table
[    2.495921]  mmcblk0boot0: unknown partition table

I haven't set up any boot partitions explicitly, so I guess the two 1MiB
boot partitions might be the factory-default setting.  Out of curiosity,
does that match your experience with Sandisk eMMCs? 

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-21  1:13                             ` Chris Ball
@ 2011-04-21  1:30                               ` Chris Ball
  2011-04-21  5:09                                 ` Philip Rakity
  2011-04-21  4:31                               ` [patchv3 4/4] MMC: MMC boot partitions support Jaehoon Chung
  1 sibling, 1 reply; 63+ messages in thread
From: Chris Ball @ 2011-04-21  1:30 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc, arnd

Hi,

On Wed, Apr 20 2011, Chris Ball wrote:
> On Mon, Apr 11 2011, Andrei Warkentin wrote:
>> Allows device MMC boot partitions to be accessed. MMC partitions
>> are treated effectively as separate block devices on the same
>> MMC card.
>
> Booted this with a Sandisk SEM04G eMMC:
>
> [    2.469921] mmcblk0boot0: mmc2:0001 SEM04G partition 1 1.00 MiB
> [    2.475905] mmcblk0boot1: mmc2:0001 SEM04G partition 2 1.00 MiB
> [    2.489403]  mmcblk0boot1: unknown partition table
> [    2.495921]  mmcblk0boot0: unknown partition table
>
> I haven't set up any boot partitions explicitly, so I guess the two 1MiB
> boot partitions might be the factory-default setting.  Out of curiosity,
> does that match your experience with Sandisk eMMCs? 

Also, on inserting an external SD card I see:

[    2.485079] mmcblk0: mmc2:0001 SEM04G 3.68 GiB 
[    2.489681] mmcblk0boot0: mmc2:0001 SEM04G partition 1 1.00 MiB
[    2.495681] mmcblk0boot1: mmc2:0001 SEM04G partition 2 1.00 MiB
[    2.503756]  mmcblk0: p1 p2
[    2.509303]  mmcblk0boot1: unknown partition table
[    2.515343]  mmcblk0boot0: unknown partition table
[    4.828326] EXT3-fs (mmcblk0p2): warning: maximal mount count reached, running e2fsc
k is recommended
[    4.845214] EXT3-fs (mmcblk0p2): using internal journal
[    4.845223] EXT3-fs (mmcblk0p2): recovery complete
[    4.857131] EXT3-fs (mmcblk0p2): mounted filesystem with ordered data mode
[   20.886514] mmc0: new high speed SDHC card at address d555
[   20.904282] mmcblk3: mmc0:d555 SD04G 3.79 GiB 
[   20.906926]  mmcblk3: p1

But I would have expected this to be mmcblk1 -- might the boot partitions
be using up mmcblk1/2 somehow?

Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-21  1:13                             ` Chris Ball
  2011-04-21  1:30                               ` Chris Ball
@ 2011-04-21  4:31                               ` Jaehoon Chung
  1 sibling, 0 replies; 63+ messages in thread
From: Jaehoon Chung @ 2011-04-21  4:31 UTC (permalink / raw)
  To: Chris Ball; +Cc: Andrei Warkentin, linux-mmc, arnd

Hi Chris.

Chris Ball wrote:
> Hi Andrei,
> 
> On Mon, Apr 11 2011, Andrei Warkentin wrote:
>> Allows device MMC boot partitions to be accessed. MMC partitions
>> are treated effectively as separate block devices on the same
>> MMC card.
> 
> Booted this with a Sandisk SEM04G eMMC:
> 
> [    2.469921] mmcblk0boot0: mmc2:0001 SEM04G partition 1 1.00 MiB
> [    2.475905] mmcblk0boot1: mmc2:0001 SEM04G partition 2 1.00 MiB
> [    2.489403]  mmcblk0boot1: unknown partition table
> [    2.495921]  mmcblk0boot0: unknown partition table
> 
> I haven't set up any boot partitions explicitly, so I guess the two 1MiB
> boot partitions might be the factory-default setting.  Out of curiosity,
> does that match your experience with Sandisk eMMCs? 

in my experience, Sandisk set up boot partition with each 1MiB. (default setting)

Regards,
Jaehoon Chung

> 
> - Chris.


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-21  1:30                               ` Chris Ball
@ 2011-04-21  5:09                                 ` Philip Rakity
  2011-04-21  5:22                                   ` Chris Ball
  0 siblings, 1 reply; 63+ messages in thread
From: Philip Rakity @ 2011-04-21  5:09 UTC (permalink / raw)
  To: Chris Ball; +Cc: Andrei Warkentin, linux-mmc, arnd


Chris,

I have also seen this on mmc-next.  

>> [    2.489403]  mmcblk0boot1: unknown partition table
>> [    2.495921]  mmcblk0boot0: unknown partition table


Aren't these the "hidden" partitions ?  Only available at boot time?

I need to apply my patch to reset the boot partition --  or is that now in mmc-next to see
if the problem still happens.


Philip

On Apr 20, 2011, at 6:30 PM, Chris Ball wrote:

> Hi,
> 
> On Wed, Apr 20 2011, Chris Ball wrote:
>> On Mon, Apr 11 2011, Andrei Warkentin wrote:
>>> Allows device MMC boot partitions to be accessed. MMC partitions
>>> are treated effectively as separate block devices on the same
>>> MMC card.
>> 
>> Booted this with a Sandisk SEM04G eMMC:
>> 
>> [    2.469921] mmcblk0boot0: mmc2:0001 SEM04G partition 1 1.00 MiB
>> [    2.475905] mmcblk0boot1: mmc2:0001 SEM04G partition 2 1.00 MiB
>> [    2.489403]  mmcblk0boot1: unknown partition table
>> [    2.495921]  mmcblk0boot0: unknown partition table
>> 
>> I haven't set up any boot partitions explicitly, so I guess the two 1MiB
>> boot partitions might be the factory-default setting.  Out of curiosity,
>> does that match your experience with Sandisk eMMCs? 
> 
> Also, on inserting an external SD card I see:
> 
> [    2.485079] mmcblk0: mmc2:0001 SEM04G 3.68 GiB 
> [    2.489681] mmcblk0boot0: mmc2:0001 SEM04G partition 1 1.00 MiB
> [    2.495681] mmcblk0boot1: mmc2:0001 SEM04G partition 2 1.00 MiB
> [    2.503756]  mmcblk0: p1 p2
> [    2.509303]  mmcblk0boot1: unknown partition table
> [    2.515343]  mmcblk0boot0: unknown partition table
> [    4.828326] EXT3-fs (mmcblk0p2): warning: maximal mount count reached, running e2fsc
> k is recommended
> [    4.845214] EXT3-fs (mmcblk0p2): using internal journal
> [    4.845223] EXT3-fs (mmcblk0p2): recovery complete
> [    4.857131] EXT3-fs (mmcblk0p2): mounted filesystem with ordered data mode
> [   20.886514] mmc0: new high speed SDHC card at address d555
> [   20.904282] mmcblk3: mmc0:d555 SD04G 3.79 GiB 
> [   20.906926]  mmcblk3: p1
> 
> But I would have expected this to be mmcblk1 -- might the boot partitions
> be using up mmcblk1/2 somehow?
> 
> Thanks,
> 
> - Chris.
> -- 
> Chris Ball   <cjb@laptop.org>   <http://printf.net/>
> One Laptop Per Child
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-21  5:09                                 ` Philip Rakity
@ 2011-04-21  5:22                                   ` Chris Ball
  2011-04-21  5:31                                     ` Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Chris Ball @ 2011-04-21  5:22 UTC (permalink / raw)
  To: Philip Rakity; +Cc: Andrei Warkentin, linux-mmc, arnd

Hi,

On Thu, Apr 21 2011, Philip Rakity wrote:
> Aren't these the "hidden" partitions ?  Only available at boot time?

Yes, it's the previously-hidden boot partitions -- Andrei's patch
exposes them to Linux.

> I need to apply my patch to reset the boot partition -- or is that now
> in mmc-next

Your patch is in mmc-next.

> to see if the problem still happens.

Well, there isn't a problem per se, the system still boots fine -- the
boot partitions are being exposed as the patch intends them to.  I'm
just curious whether it's normal for two 1MiB partitions to be created
as a factory default.

Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 4/4] MMC: MMC boot partitions support.
  2011-04-21  5:22                                   ` Chris Ball
@ 2011-04-21  5:31                                     ` Andrei Warkentin
  2011-04-21  6:07                                       ` [RFC] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming Andrei Warkentin
  0 siblings, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-21  5:31 UTC (permalink / raw)
  To: Chris Ball; +Cc: Philip Rakity, linux-mmc, arnd

On Thu, Apr 21, 2011 at 12:22 AM, Chris Ball <cjb@laptop.org> wrote:
> Hi,
>
> On Thu, Apr 21 2011, Philip Rakity wrote:
>> Aren't these the "hidden" partitions ?  Only available at boot time?
>
> Yes, it's the previously-hidden boot partitions -- Andrei's patch
> exposes them to Linux.
>
>> I need to apply my patch to reset the boot partition -- or is that now
>> in mmc-next
>
> Your patch is in mmc-next.
>
>> to see if the problem still happens.
>
> Well, there isn't a problem per se, the system still boots fine -- the
> boot partitions are being exposed as the patch intends them to.  I'm
> just curious whether it's normal for two 1MiB partitions to be created
> as a factory default.
>

Chris, the partitions are always present and are a feature of the card.

I ptofusely apologize for the dev_idx issue, I should have caught that
immediately. A dev_idx is till assigned even though the name doesn't
reflect the actual assigned dev_idx for hardware partitions. That
effectively means you need to track a name_idx per main mmc_blk_data
that is only used to form the naming for the device.

I will send a patch in about 30 mins...

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming.
  2011-04-21  5:31                                     ` Andrei Warkentin
@ 2011-04-21  6:07                                       ` Andrei Warkentin
  2011-04-21  8:17                                         ` Andrei Warkentin
  2011-04-22  0:20                                         ` Chris Ball
  0 siblings, 2 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-21  6:07 UTC (permalink / raw)
  To: linux-mmc; +Cc: cjb, Andrei Warkentin

With the hardware partitions support (which represent additional logical devices
present on MMC), devidx does not correspond with index used to form
/dev/mmcblkX names. So use an additional allocated index for device names.

Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 drivers/mmc/card/block.c |   24 +++++++++++++++++-------
 1 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9e30cf6..5572012 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -75,6 +75,7 @@ static int max_devices;
 
 /* 256 minors, so at most 256 separate devices */
 static DECLARE_BITMAP(dev_use, 256);
+static DECLARE_BITMAP(name_use, 256);
 
 /*
  * There is one mmc_blk_data per slot.
@@ -88,6 +89,7 @@ struct mmc_blk_data {
 	unsigned int	usage;
 	unsigned int	read_only;
 	unsigned int	part_type;
+	unsigned int	name_idx;
 
 	/*
 	 * Only set in main mmc_blk_data associated
@@ -776,6 +778,18 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
 	}
 
 	/*
+	 * !subname implies we are creating main mmc_blk_data that will be
+	 * associated with mmc_card with mmc_set_drvdata. Due to device partitions,
+	 * devidx will not coincide with a per-physical card index anymore
+	 * so we keep track of a name index.
+	 */
+	if (!subname)
+		md->name_idx = find_first_zero_bit(name_use, max_devices);
+	else
+		md->name_idx = ((struct mmc_blk_data *)
+				dev_to_disk(parent)->private_data)->name_idx;
+
+	/*
 	 * Set the read-only status based on the supported commands
 	 * and the write protect switch.
 	 */
@@ -820,13 +834,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
 	 * messages to tell when the card is present.
 	 */
 
-	if (subname)
-		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
-			 "mmcblk%d%s",
-			 mmc_get_devidx(dev_to_disk(parent)), subname);
-	else
-		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
-			 "mmcblk%d", devidx);
+	snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+		 "mmcblk%d%s", md->name_idx, subname ? subname : "");
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
 	set_capacity(md->disk, size);
@@ -953,6 +962,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
 	struct list_head *pos, *q;
 	struct mmc_blk_data *part_md;
 
+	__clear_bit(md->name_idx, name_use);
 	list_for_each_safe(pos, q, &md->part) {
 		part_md = list_entry(pos, struct mmc_blk_data, part);
 		list_del(pos);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [RFC] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming.
  2011-04-21  6:07                                       ` [RFC] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming Andrei Warkentin
@ 2011-04-21  8:17                                         ` Andrei Warkentin
  2011-04-21 14:44                                           ` Chris Ball
  2011-04-22  0:20                                         ` Chris Ball
  1 sibling, 1 reply; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-21  8:17 UTC (permalink / raw)
  To: linux-mmc; +Cc: cjb, Andrei Warkentin

On Thu, Apr 21, 2011 at 1:07 AM, Andrei Warkentin <andreiw@motorola.com> wrote:
> With the hardware partitions support (which represent additional logical devices
> present on MMC), devidx does not correspond with index used to form
> /dev/mmcblkX names. So use an additional allocated index for device names.
>
> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
> ---
>  drivers/mmc/card/block.c |   24 +++++++++++++++++-------
>  1 files changed, 17 insertions(+), 7 deletions(-)

The alternative is to borrow from a previous suggestion by Stephen
Warren, but instead of using card->host->index in place of devidx, use
card->host->index in place of an additional name_index used to form
/dev/mmcblkX device names.

Using card->host->index for devidx doesn't work when you have multiple
logical devices per host (because MMC card contains HW partitions).

Chris, unfortunately I am working OOF for next couple of days(I am
happy I took my eMMC board with me), so I was not able to test second
card (laptop only has 1 slot). Tested on your mmc tree with SDHCI and
my MMC08G card. Would you mind testing above RFC change? Sorry again
for the regression, grrrr.

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming.
  2011-04-21  8:17                                         ` Andrei Warkentin
@ 2011-04-21 14:44                                           ` Chris Ball
  0 siblings, 0 replies; 63+ messages in thread
From: Chris Ball @ 2011-04-21 14:44 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc

Hi Andrei,

On Thu, Apr 21 2011, Andrei Warkentin wrote:
> Chris, unfortunately I am working OOF for next couple of days(I am
> happy I took my eMMC board with me), so I was not able to test second
> card (laptop only has 1 slot). Tested on your mmc tree with SDHCI and
> my MMC08G card. Would you mind testing above RFC change? Sorry again
> for the regression, grrrr.

Sure, happy to test.  No need to feel too bad about the regression,
we're very early on in preparation for .40.

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming.
  2011-04-21  6:07                                       ` [RFC] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming Andrei Warkentin
  2011-04-21  8:17                                         ` Andrei Warkentin
@ 2011-04-22  0:20                                         ` Chris Ball
  2011-04-22  3:46                                           ` [PATCH] " Andrei Warkentin
  1 sibling, 1 reply; 63+ messages in thread
From: Chris Ball @ 2011-04-22  0:20 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc

Hi Andrei,

On Thu, Apr 21 2011, Andrei Warkentin wrote:
> With the hardware partitions support (which represent additional logical devices
> present on MMC), devidx does not correspond with index used to form
> /dev/mmcblkX names. So use an additional allocated index for device names.
>
> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
> ---
>  drivers/mmc/card/block.c |   24 +++++++++++++++++-------
>  1 files changed, 17 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
> index 9e30cf6..5572012 100644
> --- a/drivers/mmc/card/block.c
> +++ b/drivers/mmc/card/block.c
> @@ -75,6 +75,7 @@ static int max_devices;
>  
>  /* 256 minors, so at most 256 separate devices */
>  static DECLARE_BITMAP(dev_use, 256);
> +static DECLARE_BITMAP(name_use, 256);
>  
>  /*
>   * There is one mmc_blk_data per slot.
> @@ -88,6 +89,7 @@ struct mmc_blk_data {
>  	unsigned int	usage;
>  	unsigned int	read_only;
>  	unsigned int	part_type;
> +	unsigned int	name_idx;
>  
>  	/*
>  	 * Only set in main mmc_blk_data associated
> @@ -776,6 +778,18 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
>  	}
>  
>  	/*
> +	 * !subname implies we are creating main mmc_blk_data that will be
> +	 * associated with mmc_card with mmc_set_drvdata. Due to device partitions,
> +	 * devidx will not coincide with a per-physical card index anymore
> +	 * so we keep track of a name index.
> +	 */
> +	if (!subname)
> +		md->name_idx = find_first_zero_bit(name_use, max_devices);
> +	else
> +		md->name_idx = ((struct mmc_blk_data *)
> +				dev_to_disk(parent)->private_data)->name_idx;
> +
> +	/*
>  	 * Set the read-only status based on the supported commands
>  	 * and the write protect switch.
>  	 */
> @@ -820,13 +834,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
>  	 * messages to tell when the card is present.
>  	 */
>  
> -	if (subname)
> -		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
> -			 "mmcblk%d%s",
> -			 mmc_get_devidx(dev_to_disk(parent)), subname);
> -	else
> -		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
> -			 "mmcblk%d", devidx);
> +	snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
> +		 "mmcblk%d%s", md->name_idx, subname ? subname : "");
>  
>  	blk_queue_logical_block_size(md->queue.queue, 512);
>  	set_capacity(md->disk, size);
> @@ -953,6 +962,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
>  	struct list_head *pos, *q;
>  	struct mmc_blk_data *part_md;
>  
> +	__clear_bit(md->name_idx, name_use);
>  	list_for_each_safe(pos, q, &md->part) {
>  		part_md = list_entry(pos, struct mmc_blk_data, part);
>  		list_del(pos);

This is crashing for me on insertion of the external card after boot:

[    2.479319] mmc2: new high speed MMC card at address 0001
[    2.485055] mmcblk0: mmc2:0001 SEM04G 3.68 GiB 
[    2.489656] mmcblk0boot0: mmc2:0001 SEM04G partition 1 1.00 MiB
[    2.495850] mmcblk0boot1: mmc2:0001 SEM04G partition 2 1.00 MiB
[    2.503984]  mmcblk0: p1 p2
[    2.509273]  mmcblk0boot1: unknown partition table
[    2.515308]  mmcblk0boot0: unknown partition table
[    2.524044] psmouse.c: Failed to enable mouse on ec touchpad (phys)
[    2.532834] EXT3-fs: barriers not enabled
[    4.996102] EXT3-fs (mmcblk0p2): warning: maximal mount count reached, running e2fsck is recommended
[    5.007285] kjournald starting.  Commit interval 5 seconds
[    5.014595] EXT3-fs (mmcblk0p2): using internal journal
[    5.019791] EXT3-fs (mmcblk0p2): recovery complete
[    5.026713] EXT3-fs (mmcblk0p2): mounted filesystem with ordered data mode
[    5.026725] VFS: Mounted root (ext3 filesystem) on device 179:2.
[    5.039565] Freeing init memory: 116K

[olpc@localhost ~]$ 
[   33.642250] Unable to handle kernel NULL pointer dereference at virtual address 00000021
[   33.653175] pgd = c0004000
[   33.656119] [00000021] *pgd=00000000
[   33.659673] Internal error: Oops: 17 [#1] PREEMPT
[   33.659673] last sysfs file: /sys/devices/platform/sdhci-pxa.0/mmc_host/mmc0/mmc0:d555/serial
[   33.672798] Modules linked in:
[   33.675826] CPU: 0    Tainted: G        W    (2.6.39-rc4-00194-ge20de60-dirty #4)
[   33.675826] PC is at sysfs_create_dir+0x24/0xd4
[   33.683258] LR is at kobject_add_internal+0x134/0x224
[   33.687761] pc : [<c00f9880>]    lr : [<c01b2600>]    psr: a0000013
[   33.692773] sp : dc131db8  ip : 00000000  fp : 00000000
[   33.704168] r10: dcfe41fc  r9 : c05571e0  r8 : dc205408
[   33.704168] r7 : dcc61c68  r6 : 00000000  r5 : dcc61c68  r4 : dcf441b0
[   33.709357] r3 : dcc61c68  r2 : 00000000  r1 : 0000002f  r0 : dcf441b0
[   33.715834] Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
[   33.722316] Control: 10c5387d  Table: 1cc44019  DAC: 00000015
[   33.729568] Process kworker/u:1 (pid: 27, stack limit = 0xdc1302f8)
[   33.735271] Stack: (0xdc131db8 to 0xdc132000)
[   33.745818] 1da0:                                                       dcf441b0 0000002f
[   33.745818] 1dc0: 00000000 dc3317a0 dcf441b0 dcc61c68 dcc61c68 c01b2600 dcf441b0 0000002f
[   33.753939] 1de0: 00000000 00000001 dcf441b0 dcc61c68 00000000 dcc61c68 dc205408 c01b2a00
[   33.762063] 1e00: dcf441b0 dc131e1c dcf441b0 dcf44040 dcc61c68 c01a3a40 c04bbab4 c04d3ef1
[   33.770188] 1e20: 00000011 dcc61c00 dcf44040 00000000 dcc61c68 c01a89ac c01a79a4 dcc61c00
[   33.778311] 1e40: c05571e0 0b300018 07d8000a dcec6b60 dcec6b60 00000000 dc131e86 c036b964
[   33.786436] 1e60: 00000800 dc205400 dcec6b60 c02a3c30 dc131e86 c04fa28d dcd873f8 00000000
[   33.794560] 1e80: c0557388 2e335408 47203937 00004269 dc205408 c0557388 c01f3d8c 00000000
[   33.802685] 1ea0: 00000000 c029b51c c029b508 c01f3be4 c0557388 dc205408 dc205408 dc131ec8
[   33.818934] 1ec0: c01f3d8c c01f2994 dc070aa8 dcfe74b4 dc205408 dc205408 dc20543c dcfe4008
[   33.827056] 1ee0: 00000000 c01f3a24 dc205408 dc205410 dcfe4008 c01f322c 00000002 c01f1114
[   33.827056] 1f00: da21ecdc dc20551c da21ed38 dc205400 da21ed38 00000000 00061a80 dc205400
[   33.843305] 1f20: dc205408 00000000 00061a80 c0417c28 c05692b4 dcfe41fc 00000000 c029b898
[   33.851429] 1f40: c04ed29d 0000d555 00000002 dcfe4000 00000000 c029e9e8 dcfe4000 00ff8000
[   33.859554] 1f60: dc131f18 dcfe41fc dcfe4000 c029b144 dcfdef20 dc068a00 00000000 c029ae9c
[   33.859554] 1f80: dc068a05 c0053978 dc068a05 dcfdef20 dc130000 c05692ac c05692b4 dcfdef30
[   33.875802] 1fa0: 00000089 c05692b4 00000000 c0054450 dc03df30 dcfdef20 c0054284 00000013
[   33.883925] 1fc0: 00000000 00000000 00000000 c0057cf0 00000000 00000000 dcfdef20 00000000
[   33.892053] 1fe0: dc131fe0 dc131fe0 dc03df30 c0057c74 c002bc34 c002bc34 ffffffff ffffffff
[   33.900184] [<c00f9880>] (sysfs_create_dir+0x24/0xd4) from [<c01b2600>] (kobject_add_internal+0x134/0x224)
[   33.900184] [<c01b2600>] (kobject_add_internal+0x134/0x224) from [<c01b2a00>] (kobject_add+0x68/0x8c)
[   33.918942] [<c01b2a00>] (kobject_add+0x68/0x8c) from [<c01a3a40>] (blk_register_queue+0x48/0xa8)
[   33.927759] [<c01a3a40>] (blk_register_queue+0x48/0xa8) from [<c01a89ac>] (add_disk+0xe8/0x230)
[   33.936404] [<c01a89ac>] (add_disk+0xe8/0x230) from [<c036b964>] (mmc_add_disk+0x10/0x64)
[   33.936404] [<c036b964>] (mmc_add_disk+0x10/0x64) from [<c02a3c30>] (mmc_blk_probe+0x184/0x1f4)
[   33.953174] [<c02a3c30>] (mmc_blk_probe+0x184/0x1f4) from [<c029b51c>] (mmc_bus_probe+0x14/0x18)
[   33.953174] [<c029b51c>] (mmc_bus_probe+0x14/0x18) from [<c01f3be4>] (driver_probe_device+0x144/0x268)
[   33.961904] [<c01f3be4>] (driver_probe_device+0x144/0x268) from [<c01f2994>] (bus_for_each_drv+0x4c/0x84)
[   33.971152] [<c01f2994>] (bus_for_each_drv+0x4c/0x84) from [<c01f3a24>] (device_attach+0x64/0x90)
[   33.989466] [<c01f3a24>] (device_attach+0x64/0x90) from [<c01f322c>] (bus_probe_device+0x24/0x40)
[   33.998281] [<c01f322c>] (bus_probe_device+0x24/0x40) from [<c01f1114>] (device_add+0x3c8/0x54c)
[   34.007007] [<c01f1114>] (device_add+0x3c8/0x54c) from [<c029b898>] (mmc_add_card+0x110/0x158)
[   34.007007] [<c029b898>] (mmc_add_card+0x110/0x158) from [<c029e9e8>] (mmc_attach_sd+0x160/0x1e0)
[   34.024376] [<c029e9e8>] (mmc_attach_sd+0x160/0x1e0) from [<c029b144>] (mmc_rescan+0x2a8/0x314)
[   34.024376] [<c029b144>] (mmc_rescan+0x2a8/0x314) from [<c0053978>] (process_one_work+0x208/0x360)
[   34.041930] [<c0053978>] (process_one_work+0x208/0x360) from [<c0054450>] (worker_thread+0x1cc/0x2ec)
[   34.051097] [<c0054450>] (worker_thread+0x1cc/0x2ec) from [<c0057cf0>] (kthread+0x7c/0x84)
[   34.051097] [<c0057cf0>] (kthread+0x7c/0x84) from [<c002bc34>] (kernel_thread_exit+0x0/0x8)
[   34.059303] Code: e594300c e3530000 15936018 059f60a8 (e5d65021) 
[   34.076293] ---[ end trace 9dee957cd2bd872b ]---

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming.
  2011-04-22  0:20                                         ` Chris Ball
@ 2011-04-22  3:46                                           ` Andrei Warkentin
  2011-04-22  3:50                                             ` Andrei Warkentin
  2011-04-22 22:34                                             ` Chris Ball
  0 siblings, 2 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-22  3:46 UTC (permalink / raw)
  To: linux-mmc; +Cc: cjb, Andrei Warkentin

With the hardware partitions support (which represent additional logical devices
present on MMC), devidx does not correspond with index used to form
/dev/mmcblkX names. So use an additional allocated index for device names.

Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
---
 drivers/mmc/card/block.c |   26 +++++++++++++++++++-------
 1 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9e30cf6..92e4a00 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -75,6 +75,7 @@ static int max_devices;
 
 /* 256 minors, so at most 256 separate devices */
 static DECLARE_BITMAP(dev_use, 256);
+static DECLARE_BITMAP(name_use, 256);
 
 /*
  * There is one mmc_blk_data per slot.
@@ -88,6 +89,7 @@ struct mmc_blk_data {
 	unsigned int	usage;
 	unsigned int	read_only;
 	unsigned int	part_type;
+	unsigned int	name_idx;
 
 	/*
 	 * Only set in main mmc_blk_data associated
@@ -776,6 +778,20 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
 	}
 
 	/*
+	 * !subname implies we are creating main mmc_blk_data that will be
+	 * associated with mmc_card with mmc_set_drvdata. Due to device partitions,
+	 * devidx will not coincide with a per-physical card index anymore
+	 * so we keep track of a name index.
+	 */
+	if (!subname) {
+		md->name_idx = find_first_zero_bit(name_use, max_devices);
+		__set_bit(md->name_idx, name_use);
+	}
+	else
+		md->name_idx = ((struct mmc_blk_data *)
+				dev_to_disk(parent)->private_data)->name_idx;
+
+	/*
 	 * Set the read-only status based on the supported commands
 	 * and the write protect switch.
 	 */
@@ -820,13 +836,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
 	 * messages to tell when the card is present.
 	 */
 
-	if (subname)
-		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
-			 "mmcblk%d%s",
-			 mmc_get_devidx(dev_to_disk(parent)), subname);
-	else
-		snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
-			 "mmcblk%d", devidx);
+	snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+		 "mmcblk%d%s", md->name_idx, subname ? subname : "");
 
 	blk_queue_logical_block_size(md->queue.queue, 512);
 	set_capacity(md->disk, size);
@@ -953,6 +964,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
 	struct list_head *pos, *q;
 	struct mmc_blk_data *part_md;
 
+	__clear_bit(md->name_idx, name_use);
 	list_for_each_safe(pos, q, &md->part) {
 		part_md = list_entry(pos, struct mmc_blk_data, part);
 		list_del(pos);
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCH] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming.
  2011-04-22  3:46                                           ` [PATCH] " Andrei Warkentin
@ 2011-04-22  3:50                                             ` Andrei Warkentin
  2011-04-22 22:34                                             ` Chris Ball
  1 sibling, 0 replies; 63+ messages in thread
From: Andrei Warkentin @ 2011-04-22  3:50 UTC (permalink / raw)
  To: linux-mmc; +Cc: cjb, Andrei Warkentin

On Thu, Apr 21, 2011 at 10:46 PM, Andrei Warkentin <andreiw@motorola.com> wrote:
> With the hardware partitions support (which represent additional logical devices
> present on MMC), devidx does not correspond with index used to form
> /dev/mmcblkX names. So use an additional allocated index for device names.
>
> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>

That should be good :-/. Sorry.

A

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming.
  2011-04-22  3:46                                           ` [PATCH] " Andrei Warkentin
  2011-04-22  3:50                                             ` Andrei Warkentin
@ 2011-04-22 22:34                                             ` Chris Ball
  1 sibling, 0 replies; 63+ messages in thread
From: Chris Ball @ 2011-04-22 22:34 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc

Hi Andrei,

On Thu, Apr 21 2011, Andrei Warkentin wrote:
> With the hardware partitions support (which represent additional logical devices
> present on MMC), devidx does not correspond with index used to form
> /dev/mmcblkX names. So use an additional allocated index for device names.
>
> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>

Thanks, pushed to mmc-next for .40, looks good:

[  659.127819] mmc0: new high speed SDHC card at address d555
[  659.141704] mmcblk1: mmc0:d555 SD04G 3.79 GiB 
[  659.147453]  mmcblk1: p1

(I re-wrapped the commit message and comment to <80 chars.)

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE.
  2011-04-11 21:13                           ` [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE Andrei Warkentin
  2011-04-12  9:06                             ` Dong, Chuanxiao
@ 2011-08-10 13:30                             ` Chris Ball
  1 sibling, 0 replies; 63+ messages in thread
From: Chris Ball @ 2011-08-10 13:30 UTC (permalink / raw)
  To: Andrei Warkentin; +Cc: linux-mmc, arnd, Chuanxiao Dong

Hi Andrei,

On Mon, Apr 11 2011, Andrei Warkentin wrote:
> ERASE command needs R1B response, so fix R1B-type command
> handling for SDHCI controller. For non-DAT commands using a busy
> reponse, the cmd->cmd_timeout_ms (in ms) field is used for timeout
> calculations.
>
> Based on patch by Chuanxiao Dong <chuanxiao.dong@intel.com>
> Signed-off-by: Andrei Warkentin <andreiw@motorola.com>

Looks like this patch has been implicated in causing IO errors on
ThinkPads with a Ricoh device -- please could you take a look at
https://bugzilla.kernel.org/show_bug.cgi?id=38922 ?

Thanks,

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 63+ messages in thread

end of thread, other threads:[~2011-08-10 13:30 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-19 11:18 MMC/eMMC partitioning support Andrei Warkentin
2011-03-19 11:18 ` [RFC] MMC: MMC boot partitions support Andrei Warkentin
2011-03-19 12:13   ` Andrei Warkentin
2011-03-21 14:19   ` [PATCH] " Andrei Warkentin
2011-03-22  3:54   ` [PATCHv3] " Andrei Warkentin
2011-03-22 21:11   ` MMC partitions support (4th revision) Andrei Warkentin
2011-03-22 21:11   ` [PATCHv4] MMC: MMC boot partitions support Andrei Warkentin
2011-03-29 22:45     ` Andrei Warkentin
2011-03-30 12:03       ` Arnd Bergmann
2011-03-30 20:07         ` Andrei Warkentin
2011-03-30 22:43           ` Chris Ball
2011-03-30 22:46             ` Chris Ball
2011-03-30 23:18               ` Andrei Warkentin
2011-03-30 23:34                 ` Chris Ball
2011-03-31  6:57                   ` Andrei Warkentin
2011-03-31 11:01                     ` Arnd Bergmann
2011-03-31 19:17                       ` Andrei Warkentin
2011-03-31 19:37                         ` Chris Ball
2011-03-31 20:01                           ` Andrei Warkentin
2011-03-31 20:03                           ` Chris Ball
2011-03-31 20:01                             ` Andrei Warkentin
2011-04-01  9:23                               ` Arnd Bergmann
2011-04-01 14:52                                 ` Chris Ball
2011-04-01  9:21                         ` Arnd Bergmann
2011-03-31 11:17           ` Arnd Bergmann
2011-03-31 19:29             ` Andrei Warkentin
2011-04-01 10:38               ` Arnd Bergmann
2011-04-01 18:42                 ` Andrei Warkentin
2011-04-01 19:25                   ` Arnd Bergmann
2011-04-01 19:42                     ` Andrei Warkentin
2011-04-04 12:22                       ` [PATCH] " Andrei Warkentin
2011-04-04 11:52                         ` Andrei Warkentin
2011-04-11 21:13                           ` [patchv3 1/4] MMC: Rename erase_timeout to cmd_timeout_ms Andrei Warkentin
2011-04-11 21:13                           ` [patchv3 2/4] MMC: SDHCI R1B command handling + MMC_CAP_ERASE Andrei Warkentin
2011-04-12  9:06                             ` Dong, Chuanxiao
2011-04-12 18:05                               ` Andrei Warkentin
2011-04-13  1:59                                 ` Dong, Chuanxiao
2011-04-13  5:44                                   ` Andrei Warkentin
2011-04-15 21:34                                     ` Cyril Hrubis
2011-08-10 13:30                             ` Chris Ball
2011-04-11 21:13                           ` [patchv3 3/4] MMC: Allow setting CMD timeout for CMD6 (SWITCH) Andrei Warkentin
2011-04-11 21:13                           ` [patchv3 4/4] MMC: MMC boot partitions support Andrei Warkentin
2011-04-11 22:00                             ` Chris Ball
2011-04-11 22:10                               ` Andrei Warkentin
2011-04-11 22:22                                 ` Chris Ball
2011-04-11 22:18                                   ` Andrei Warkentin
2011-04-11 23:10                                     ` [patchv4 1/2] MMC: block.c cleanup for host claim/release Andrei Warkentin
2011-04-11 23:10                                     ` [patchv4 2/2] MMC: MMC boot partitions support Andrei Warkentin
2011-04-11 23:20                                     ` [patchv3 4/4] " Chris Ball
2011-04-11 23:24                                       ` Andrei Warkentin
2011-04-21  1:13                             ` Chris Ball
2011-04-21  1:30                               ` Chris Ball
2011-04-21  5:09                                 ` Philip Rakity
2011-04-21  5:22                                   ` Chris Ball
2011-04-21  5:31                                     ` Andrei Warkentin
2011-04-21  6:07                                       ` [RFC] MMC: Block: Ensure hardware partitions don't mess with mmcblk device naming Andrei Warkentin
2011-04-21  8:17                                         ` Andrei Warkentin
2011-04-21 14:44                                           ` Chris Ball
2011-04-22  0:20                                         ` Chris Ball
2011-04-22  3:46                                           ` [PATCH] " Andrei Warkentin
2011-04-22  3:50                                             ` Andrei Warkentin
2011-04-22 22:34                                             ` Chris Ball
2011-04-21  4:31                               ` [patchv3 4/4] MMC: MMC boot partitions support Jaehoon Chung

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.