aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrei Warkentin <andreiw@motorola.com>2011-04-11 19:10:25 -0400
committerChris Ball <cjb@laptop.org>2011-05-24 21:01:21 -0400
commit371a689f64b0da140c3bcd3f55305ffa1c3a58ef (patch)
treec0dff82d668378d395cb22ce33cd93e6dafef9eb
parent1a258db6f396e26c2c00b19c0107a891895d4584 (diff)
mmc: MMC boot partitions support.
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> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--Documentation/mmc/00-INDEX2
-rw-r--r--Documentation/mmc/mmc-dev-attrs.txt10
-rw-r--r--Documentation/mmc/mmc-dev-parts.txt27
-rw-r--r--drivers/mmc/card/block.c274
-rw-r--r--drivers/mmc/core/mmc.c22
-rw-r--r--include/linux/mmc/card.h4
-rw-r--r--include/linux/mmc/mmc.h8
7 files changed, 305 insertions, 42 deletions
diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX
index fca586f5b853..93dd7a714075 100644
--- a/Documentation/mmc/00-INDEX
+++ b/Documentation/mmc/00-INDEX
@@ -2,3 +2,5 @@
2 - this file 2 - this file
3mmc-dev-attrs.txt 3mmc-dev-attrs.txt
4 - info on SD and MMC device attributes 4 - info on SD and MMC device attributes
5mmc-dev-parts.txt
6 - info on SD and MMC device partitions
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index ff2bd685bced..8898a95b41e5 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -1,3 +1,13 @@
1SD and MMC Block Device Attributes
2==================================
3
4These attributes are defined for the block devices associated with the
5SD or MMC device.
6
7The following attributes are read/write.
8
9 force_ro Enforce read-only access even if write protect switch is off.
10
1SD and MMC Device Attributes 11SD and MMC Device Attributes
2============================ 12============================
3 13
diff --git a/Documentation/mmc/mmc-dev-parts.txt b/Documentation/mmc/mmc-dev-parts.txt
new file mode 100644
index 000000000000..2db28b8e662f
--- /dev/null
+++ b/Documentation/mmc/mmc-dev-parts.txt
@@ -0,0 +1,27 @@
1SD and MMC Device Partitions
2============================
3
4Device partitions are additional logical block devices present on the
5SD/MMC device.
6
7As of this writing, MMC boot partitions as supported and exposed as
8/dev/mmcblkXboot0 and /dev/mmcblkXboot1, where X is the index of the
9parent /dev/mmcblkX.
10
11MMC Boot Partitions
12===================
13
14Read and write access is provided to the two MMC boot partitions. Due to
15the sensitive nature of the boot partition contents, which often store
16a bootloader or bootloader configuration tables crucial to booting the
17platform, write access is disabled by default to reduce the chance of
18accidental bricking.
19
20To enable write access to /dev/mmcblkXbootY, disable the forced read-only
21access with:
22
23echo 0 > /sys/block/mmcblkXbootY/force_ro
24
25To re-enable read-only access:
26
27echo 1 > /sys/block/mmcblkXbootY/force_ro
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 3e9082b729ff..1e6bd910e79e 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -76,9 +76,19 @@ struct mmc_blk_data {
76 spinlock_t lock; 76 spinlock_t lock;
77 struct gendisk *disk; 77 struct gendisk *disk;
78 struct mmc_queue queue; 78 struct mmc_queue queue;
79 struct list_head part;
79 80
80 unsigned int usage; 81 unsigned int usage;
81 unsigned int read_only; 82 unsigned int read_only;
83 unsigned int part_type;
84
85 /*
86 * Only set in main mmc_blk_data associated
87 * with mmc_card with mmc_set_drvdata, and keeps
88 * track of the current selected device partition.
89 */
90 unsigned int part_curr;
91 struct device_attribute force_ro;
82}; 92};
83 93
84static DEFINE_MUTEX(open_lock); 94static DEFINE_MUTEX(open_lock);
@@ -101,17 +111,22 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
101 return md; 111 return md;
102} 112}
103 113
114static inline int mmc_get_devidx(struct gendisk *disk)
115{
116 int devmaj = MAJOR(disk_devt(disk));
117 int devidx = MINOR(disk_devt(disk)) / perdev_minors;
118
119 if (!devmaj)
120 devidx = disk->first_minor / perdev_minors;
121 return devidx;
122}
123
104static void mmc_blk_put(struct mmc_blk_data *md) 124static void mmc_blk_put(struct mmc_blk_data *md)
105{ 125{
106 mutex_lock(&open_lock); 126 mutex_lock(&open_lock);
107 md->usage--; 127 md->usage--;
108 if (md->usage == 0) { 128 if (md->usage == 0) {
109 int devmaj = MAJOR(disk_devt(md->disk)); 129 int devidx = mmc_get_devidx(md->disk);
110 int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
111
112 if (!devmaj)
113 devidx = md->disk->first_minor / perdev_minors;
114
115 blk_cleanup_queue(md->queue.queue); 130 blk_cleanup_queue(md->queue.queue);
116 131
117 __clear_bit(devidx, dev_use); 132 __clear_bit(devidx, dev_use);
@@ -122,6 +137,38 @@ static void mmc_blk_put(struct mmc_blk_data *md)
122 mutex_unlock(&open_lock); 137 mutex_unlock(&open_lock);
123} 138}
124 139
140static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
141 char *buf)
142{
143 int ret;
144 struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
145
146 ret = snprintf(buf, PAGE_SIZE, "%d",
147 get_disk_ro(dev_to_disk(dev)) ^
148 md->read_only);
149 mmc_blk_put(md);
150 return ret;
151}
152
153static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
154 const char *buf, size_t count)
155{
156 int ret;
157 char *end;
158 struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
159 unsigned long set = simple_strtoul(buf, &end, 0);
160 if (end == buf) {
161 ret = -EINVAL;
162 goto out;
163 }
164
165 set_disk_ro(dev_to_disk(dev), set || md->read_only);
166 ret = count;
167out:
168 mmc_blk_put(md);
169 return ret;
170}
171
125static int mmc_blk_open(struct block_device *bdev, fmode_t mode) 172static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
126{ 173{
127 struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk); 174 struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -176,6 +223,29 @@ struct mmc_blk_request {
176 struct mmc_data data; 223 struct mmc_data data;
177}; 224};
178 225
226static inline int mmc_blk_part_switch(struct mmc_card *card,
227 struct mmc_blk_data *md)
228{
229 int ret;
230 struct mmc_blk_data *main_md = mmc_get_drvdata(card);
231 if (main_md->part_curr == md->part_type)
232 return 0;
233
234 if (mmc_card_mmc(card)) {
235 card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
236 card->ext_csd.part_config |= md->part_type;
237
238 ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
239 EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
240 card->ext_csd.part_time);
241 if (ret)
242 return ret;
243}
244
245 main_md->part_curr = md->part_type;
246 return 0;
247}
248
179static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) 249static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
180{ 250{
181 int err; 251 int err;
@@ -620,6 +690,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
620 struct mmc_card *card = md->queue.card; 690 struct mmc_card *card = md->queue.card;
621 691
622 mmc_claim_host(card->host); 692 mmc_claim_host(card->host);
693 ret = mmc_blk_part_switch(card, md);
694 if (ret) {
695 ret = 0;
696 goto out;
697 }
623 698
624 if (req->cmd_flags & REQ_DISCARD) { 699 if (req->cmd_flags & REQ_DISCARD) {
625 if (req->cmd_flags & REQ_SECURE) 700 if (req->cmd_flags & REQ_SECURE)
@@ -632,6 +707,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
632 ret = mmc_blk_issue_rw_rq(mq, req); 707 ret = mmc_blk_issue_rw_rq(mq, req);
633 } 708 }
634 709
710out:
635 mmc_release_host(card->host); 711 mmc_release_host(card->host);
636 return ret; 712 return ret;
637} 713}
@@ -642,7 +718,11 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
642 !(card->csd.cmdclass & CCC_BLOCK_WRITE); 718 !(card->csd.cmdclass & CCC_BLOCK_WRITE);
643} 719}
644 720
645static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) 721static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
722 struct device *parent,
723 sector_t size,
724 bool default_ro,
725 const char *subname)
646{ 726{
647 struct mmc_blk_data *md; 727 struct mmc_blk_data *md;
648 int devidx, ret; 728 int devidx, ret;
@@ -658,7 +738,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
658 goto out; 738 goto out;
659 } 739 }
660 740
661
662 /* 741 /*
663 * Set the read-only status based on the supported commands 742 * Set the read-only status based on the supported commands
664 * and the write protect switch. 743 * and the write protect switch.
@@ -672,6 +751,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
672 } 751 }
673 752
674 spin_lock_init(&md->lock); 753 spin_lock_init(&md->lock);
754 INIT_LIST_HEAD(&md->part);
675 md->usage = 1; 755 md->usage = 1;
676 756
677 ret = mmc_init_queue(&md->queue, card, &md->lock); 757 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)
686 md->disk->fops = &mmc_bdops; 766 md->disk->fops = &mmc_bdops;
687 md->disk->private_data = md; 767 md->disk->private_data = md;
688 md->disk->queue = md->queue.queue; 768 md->disk->queue = md->queue.queue;
689 md->disk->driverfs_dev = &card->dev; 769 md->disk->driverfs_dev = parent;
690 set_disk_ro(md->disk, md->read_only); 770 set_disk_ro(md->disk, md->read_only || default_ro);
691 if (REL_WRITES_SUPPORTED(card)) 771 if (REL_WRITES_SUPPORTED(card))
692 blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA); 772 blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
693 773
@@ -703,33 +783,97 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
703 * messages to tell when the card is present. 783 * messages to tell when the card is present.
704 */ 784 */
705 785
706 snprintf(md->disk->disk_name, sizeof(md->disk->disk_name), 786 if (subname)
707 "mmcblk%d", devidx); 787 snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
788 "mmcblk%d%s",
789 mmc_get_devidx(dev_to_disk(parent)), subname);
790 else
791 snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
792 "mmcblk%d", devidx);
708 793
709 blk_queue_logical_block_size(md->queue.queue, 512); 794 blk_queue_logical_block_size(md->queue.queue, 512);
795 set_capacity(md->disk, size);
796 return md;
797
798 err_putdisk:
799 put_disk(md->disk);
800 err_kfree:
801 kfree(md);
802 out:
803 return ERR_PTR(ret);
804}
805
806static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
807{
808 sector_t size;
809 struct mmc_blk_data *md;
710 810
711 if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { 811 if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
712 /* 812 /*
713 * The EXT_CSD sector count is in number or 512 byte 813 * The EXT_CSD sector count is in number or 512 byte
714 * sectors. 814 * sectors.
715 */ 815 */
716 set_capacity(md->disk, card->ext_csd.sectors); 816 size = card->ext_csd.sectors;
717 } else { 817 } else {
718 /* 818 /*
719 * The CSD capacity field is in units of read_blkbits. 819 * The CSD capacity field is in units of read_blkbits.
720 * set_capacity takes units of 512 bytes. 820 * set_capacity takes units of 512 bytes.
721 */ 821 */
722 set_capacity(md->disk, 822 size = card->csd.capacity << (card->csd.read_blkbits - 9);
723 card->csd.capacity << (card->csd.read_blkbits - 9));
724 } 823 }
824
825 md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
725 return md; 826 return md;
827}
726 828
727 err_putdisk: 829static int mmc_blk_alloc_part(struct mmc_card *card,
728 put_disk(md->disk); 830 struct mmc_blk_data *md,
729 err_kfree: 831 unsigned int part_type,
730 kfree(md); 832 sector_t size,
731 out: 833 bool default_ro,
732 return ERR_PTR(ret); 834 const char *subname)
835{
836 char cap_str[10];
837 struct mmc_blk_data *part_md;
838
839 part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
840 subname);
841 if (IS_ERR(part_md))
842 return PTR_ERR(part_md);
843 part_md->part_type = part_type;
844 list_add(&part_md->part, &md->part);
845
846 string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
847 cap_str, sizeof(cap_str));
848 printk(KERN_INFO "%s: %s %s partition %u %s\n",
849 part_md->disk->disk_name, mmc_card_id(card),
850 mmc_card_name(card), part_md->part_type, cap_str);
851 return 0;
852}
853
854static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
855{
856 int ret = 0;
857
858 if (!mmc_card_mmc(card))
859 return 0;
860
861 if (card->ext_csd.boot_size) {
862 ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0,
863 card->ext_csd.boot_size >> 9,
864 true,
865 "boot0");
866 if (ret)
867 return ret;
868 ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT1,
869 card->ext_csd.boot_size >> 9,
870 true,
871 "boot1");
872 if (ret)
873 return ret;
874 }
875
876 return ret;
733} 877}
734 878
735static int 879static int
@@ -750,9 +894,54 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
750 return 0; 894 return 0;
751} 895}
752 896
897static void mmc_blk_remove_req(struct mmc_blk_data *md)
898{
899 if (md) {
900 if (md->disk->flags & GENHD_FL_UP) {
901 device_remove_file(disk_to_dev(md->disk), &md->force_ro);
902
903 /* Stop new requests from getting into the queue */
904 del_gendisk(md->disk);
905 }
906
907 /* Then flush out any already in there */
908 mmc_cleanup_queue(&md->queue);
909 mmc_blk_put(md);
910 }
911}
912
913static void mmc_blk_remove_parts(struct mmc_card *card,
914 struct mmc_blk_data *md)
915{
916 struct list_head *pos, *q;
917 struct mmc_blk_data *part_md;
918
919 list_for_each_safe(pos, q, &md->part) {
920 part_md = list_entry(pos, struct mmc_blk_data, part);
921 list_del(pos);
922 mmc_blk_remove_req(part_md);
923 }
924}
925
926static int mmc_add_disk(struct mmc_blk_data *md)
927{
928 int ret;
929
930 add_disk(md->disk);
931 md->force_ro.show = force_ro_show;
932 md->force_ro.store = force_ro_store;
933 md->force_ro.attr.name = "force_ro";
934 md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
935 ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
936 if (ret)
937 del_gendisk(md->disk);
938
939 return ret;
940}
941
753static int mmc_blk_probe(struct mmc_card *card) 942static int mmc_blk_probe(struct mmc_card *card)
754{ 943{
755 struct mmc_blk_data *md; 944 struct mmc_blk_data *md, *part_md;
756 int err; 945 int err;
757 char cap_str[10]; 946 char cap_str[10];
758 947
@@ -776,14 +965,22 @@ static int mmc_blk_probe(struct mmc_card *card)
776 md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), 965 md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
777 cap_str, md->read_only ? "(ro)" : ""); 966 cap_str, md->read_only ? "(ro)" : "");
778 967
968 if (mmc_blk_alloc_parts(card, md))
969 goto out;
970
779 mmc_set_drvdata(card, md); 971 mmc_set_drvdata(card, md);
780 add_disk(md->disk); 972 if (mmc_add_disk(md))
973 goto out;
974
975 list_for_each_entry(part_md, &md->part, part) {
976 if (mmc_add_disk(part_md))
977 goto out;
978 }
781 return 0; 979 return 0;
782 980
783 out: 981 out:
784 mmc_cleanup_queue(&md->queue); 982 mmc_blk_remove_parts(card, md);
785 mmc_blk_put(md); 983 mmc_blk_remove_req(md);
786
787 return err; 984 return err;
788} 985}
789 986
@@ -791,36 +988,43 @@ static void mmc_blk_remove(struct mmc_card *card)
791{ 988{
792 struct mmc_blk_data *md = mmc_get_drvdata(card); 989 struct mmc_blk_data *md = mmc_get_drvdata(card);
793 990
794 if (md) { 991 mmc_blk_remove_parts(card, md);
795 /* Stop new requests from getting into the queue */ 992 mmc_blk_remove_req(md);
796 del_gendisk(md->disk);
797
798 /* Then flush out any already in there */
799 mmc_cleanup_queue(&md->queue);
800
801 mmc_blk_put(md);
802 }
803 mmc_set_drvdata(card, NULL); 993 mmc_set_drvdata(card, NULL);
804} 994}
805 995
806#ifdef CONFIG_PM 996#ifdef CONFIG_PM
807static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state) 997static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
808{ 998{
999 struct mmc_blk_data *part_md;
809 struct mmc_blk_data *md = mmc_get_drvdata(card); 1000 struct mmc_blk_data *md = mmc_get_drvdata(card);
810 1001
811 if (md) { 1002 if (md) {
812 mmc_queue_suspend(&md->queue); 1003 mmc_queue_suspend(&md->queue);
1004 list_for_each_entry(part_md, &md->part, part) {
1005 mmc_queue_suspend(&part_md->queue);
1006 }
813 } 1007 }
814 return 0; 1008 return 0;
815} 1009}
816 1010
817static int mmc_blk_resume(struct mmc_card *card) 1011static int mmc_blk_resume(struct mmc_card *card)
818{ 1012{
1013 struct mmc_blk_data *part_md;
819 struct mmc_blk_data *md = mmc_get_drvdata(card); 1014 struct mmc_blk_data *md = mmc_get_drvdata(card);
820 1015
821 if (md) { 1016 if (md) {
822 mmc_blk_set_blksize(md, card); 1017 mmc_blk_set_blksize(md, card);
1018
1019 /*
1020 * Resume involves the card going into idle state,
1021 * so current partition is always the main one.
1022 */
1023 md->part_curr = md->part_type;
823 mmc_queue_resume(&md->queue); 1024 mmc_queue_resume(&md->queue);
1025 list_for_each_entry(part_md, &md->part, part) {
1026 mmc_queue_resume(&part_md->queue);
1027 }
824 } 1028 }
825 return 0; 1029 return 0;
826} 1030}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 396cb23625d2..a2c795e8f9dd 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)
288 288
289 if (card->ext_csd.rev >= 3) { 289 if (card->ext_csd.rev >= 3) {
290 u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; 290 u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
291 card->ext_csd.bootconfig = ext_csd[EXT_CSD_BOOT_CONFIG]; 291 card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
292
293 /* EXT_CSD value is in units of 10ms, but we store in ms */
294 card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
292 295
293 /* Sleep / awake timeout in 100ns units */ 296 /* Sleep / awake timeout in 100ns units */
294 if (sa_shift > 0 && sa_shift <= 0x17) 297 if (sa_shift > 0 && sa_shift <= 0x17)
@@ -302,6 +305,12 @@ static int mmc_read_ext_csd(struct mmc_card *card)
302 ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10; 305 ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
303 306
304 card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C]; 307 card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C];
308
309 /*
310 * There are two boot regions of equal size, defined in
311 * multiples of 128K.
312 */
313 card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
305 } 314 }
306 315
307 if (card->ext_csd.rev >= 4) { 316 if (card->ext_csd.rev >= 4) {
@@ -576,10 +585,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
576 /* 585 /*
577 * Ensure eMMC user default partition is enabled 586 * Ensure eMMC user default partition is enabled
578 */ 587 */
579 if (card->ext_csd.bootconfig & 0x7) { 588 if (card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK) {
580 card->ext_csd.bootconfig &= ~0x7; 589 card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
581 mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_CONFIG, 590 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,
582 card->ext_csd.bootconfig, 0); 591 card->ext_csd.part_config,
592 card->ext_csd.part_time);
593 if (err && err != -EBADMSG)
594 goto free_card;
583 } 595 }
584 596
585 /* 597 /*
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 937f852cf01e..0c7a58b14343 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -48,7 +48,8 @@ struct mmc_ext_csd {
48 u8 sec_feature_support; 48 u8 sec_feature_support;
49 u8 rel_sectors; 49 u8 rel_sectors;
50 u8 rel_param; 50 u8 rel_param;
51 u8 bootconfig; 51 u8 part_config;
52 unsigned int part_time; /* Units: ms */
52 unsigned int sa_timeout; /* Units: 100ns */ 53 unsigned int sa_timeout; /* Units: 100ns */
53 unsigned int hs_max_dtr; 54 unsigned int hs_max_dtr;
54 unsigned int sectors; 55 unsigned int sectors;
@@ -61,6 +62,7 @@ struct mmc_ext_csd {
61 bool enhanced_area_en; /* enable bit */ 62 bool enhanced_area_en; /* enable bit */
62 unsigned long long enhanced_area_offset; /* Units: Byte */ 63 unsigned long long enhanced_area_offset; /* Units: Byte */
63 unsigned int enhanced_area_size; /* Units: KB */ 64 unsigned int enhanced_area_size; /* Units: KB */
65 unsigned int boot_size; /* in bytes */
64}; 66};
65 67
66struct sd_scr { 68struct sd_scr {
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 390aa6eef676..373b2bf5e5b5 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -257,19 +257,21 @@ struct _mmc_csd {
257#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ 257#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
258#define EXT_CSD_WR_REL_PARAM 166 /* RO */ 258#define EXT_CSD_WR_REL_PARAM 166 /* RO */
259#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ 259#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
260#define EXT_CSD_BOOT_CONFIG 179 /* R/W */ 260#define EXT_CSD_PART_CONFIG 179 /* R/W */
261#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ 261#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
262#define EXT_CSD_BUS_WIDTH 183 /* R/W */ 262#define EXT_CSD_BUS_WIDTH 183 /* R/W */
263#define EXT_CSD_HS_TIMING 185 /* R/W */ 263#define EXT_CSD_HS_TIMING 185 /* R/W */
264#define EXT_CSD_REV 192 /* RO */ 264#define EXT_CSD_REV 192 /* RO */
265#define EXT_CSD_STRUCTURE 194 /* RO */ 265#define EXT_CSD_STRUCTURE 194 /* RO */
266#define EXT_CSD_CARD_TYPE 196 /* RO */ 266#define EXT_CSD_CARD_TYPE 196 /* RO */
267#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
267#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ 268#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
268#define EXT_CSD_S_A_TIMEOUT 217 /* RO */ 269#define EXT_CSD_S_A_TIMEOUT 217 /* RO */
269#define EXT_CSD_REL_WR_SEC_C 222 /* RO */ 270#define EXT_CSD_REL_WR_SEC_C 222 /* RO */
270#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ 271#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
271#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */ 272#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */
272#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ 273#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */
274#define EXT_CSD_BOOT_MULT 226 /* RO */
273#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */ 275#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */
274#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */ 276#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */
275#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ 277#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
@@ -281,6 +283,10 @@ struct _mmc_csd {
281 283
282#define EXT_CSD_WR_REL_PARAM_EN (1<<2) 284#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
283 285
286#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
287#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
288#define EXT_CSD_PART_CONFIG_ACC_BOOT1 (0x2)
289
284#define EXT_CSD_CMD_SET_NORMAL (1<<0) 290#define EXT_CSD_CMD_SET_NORMAL (1<<0)
285#define EXT_CSD_CMD_SET_SECURE (1<<1) 291#define EXT_CSD_CMD_SET_SECURE (1<<1)
286#define EXT_CSD_CMD_SET_CPSECURE (1<<2) 292#define EXT_CSD_CMD_SET_CPSECURE (1<<2)