diff options
author | Johan Rudholm <johan.rudholm@stericsson.com> | 2011-12-02 02:51:06 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-01-11 23:58:43 -0500 |
commit | add710eaa88606de8ba98a014d37178579e6dbaf (patch) | |
tree | 2d719508cabd213d5923cef95fdd3d6c9c40d977 /drivers/mmc/card | |
parent | 92df954df3422a7dcf99eea34cf4cb68bb06ea08 (diff) |
mmc: boot partition ro lock support
Enable boot partitions to be read-only locked until next power on via
a sysfs entry. There will be one sysfs entry for each boot partition:
/sys/block/mmcblkXbootY/ro_lock_until_next_power_on
Each boot partition is locked by writing 1 to its file.
Signed-off-by: Johan Rudholm <johan.rudholm@stericsson.com>
Signed-off-by: John Beckett <john.beckett@stericsson.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/card')
-rw-r--r-- | drivers/mmc/card/block.c | 121 |
1 files changed, 113 insertions, 8 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index ad0fb8d74dda..0c959c96005e 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c | |||
@@ -107,6 +107,8 @@ struct mmc_blk_data { | |||
107 | */ | 107 | */ |
108 | unsigned int part_curr; | 108 | unsigned int part_curr; |
109 | struct device_attribute force_ro; | 109 | struct device_attribute force_ro; |
110 | struct device_attribute power_ro_lock; | ||
111 | int area_type; | ||
110 | }; | 112 | }; |
111 | 113 | ||
112 | static DEFINE_MUTEX(open_lock); | 114 | static DEFINE_MUTEX(open_lock); |
@@ -165,6 +167,70 @@ static void mmc_blk_put(struct mmc_blk_data *md) | |||
165 | mutex_unlock(&open_lock); | 167 | mutex_unlock(&open_lock); |
166 | } | 168 | } |
167 | 169 | ||
170 | static ssize_t power_ro_lock_show(struct device *dev, | ||
171 | struct device_attribute *attr, char *buf) | ||
172 | { | ||
173 | int ret; | ||
174 | struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); | ||
175 | struct mmc_card *card = md->queue.card; | ||
176 | int locked = 0; | ||
177 | |||
178 | if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN) | ||
179 | locked = 2; | ||
180 | else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN) | ||
181 | locked = 1; | ||
182 | |||
183 | ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); | ||
184 | |||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static ssize_t power_ro_lock_store(struct device *dev, | ||
189 | struct device_attribute *attr, const char *buf, size_t count) | ||
190 | { | ||
191 | int ret; | ||
192 | struct mmc_blk_data *md, *part_md; | ||
193 | struct mmc_card *card; | ||
194 | unsigned long set; | ||
195 | |||
196 | if (kstrtoul(buf, 0, &set)) | ||
197 | return -EINVAL; | ||
198 | |||
199 | if (set != 1) | ||
200 | return count; | ||
201 | |||
202 | md = mmc_blk_get(dev_to_disk(dev)); | ||
203 | card = md->queue.card; | ||
204 | |||
205 | mmc_claim_host(card->host); | ||
206 | |||
207 | ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, | ||
208 | card->ext_csd.boot_ro_lock | | ||
209 | EXT_CSD_BOOT_WP_B_PWR_WP_EN, | ||
210 | card->ext_csd.part_time); | ||
211 | if (ret) | ||
212 | pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret); | ||
213 | else | ||
214 | card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; | ||
215 | |||
216 | mmc_release_host(card->host); | ||
217 | |||
218 | if (!ret) { | ||
219 | pr_info("%s: Locking boot partition ro until next power on\n", | ||
220 | md->disk->disk_name); | ||
221 | set_disk_ro(md->disk, 1); | ||
222 | |||
223 | list_for_each_entry(part_md, &md->part, part) | ||
224 | if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) { | ||
225 | pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name); | ||
226 | set_disk_ro(part_md->disk, 1); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | mmc_blk_put(md); | ||
231 | return count; | ||
232 | } | ||
233 | |||
168 | static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, | 234 | static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, |
169 | char *buf) | 235 | char *buf) |
170 | { | 236 | { |
@@ -1347,7 +1413,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, | |||
1347 | struct device *parent, | 1413 | struct device *parent, |
1348 | sector_t size, | 1414 | sector_t size, |
1349 | bool default_ro, | 1415 | bool default_ro, |
1350 | const char *subname) | 1416 | const char *subname, |
1417 | int area_type) | ||
1351 | { | 1418 | { |
1352 | struct mmc_blk_data *md; | 1419 | struct mmc_blk_data *md; |
1353 | int devidx, ret; | 1420 | int devidx, ret; |
@@ -1372,11 +1439,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, | |||
1372 | if (!subname) { | 1439 | if (!subname) { |
1373 | md->name_idx = find_first_zero_bit(name_use, max_devices); | 1440 | md->name_idx = find_first_zero_bit(name_use, max_devices); |
1374 | __set_bit(md->name_idx, name_use); | 1441 | __set_bit(md->name_idx, name_use); |
1375 | } | 1442 | } else |
1376 | else | ||
1377 | md->name_idx = ((struct mmc_blk_data *) | 1443 | md->name_idx = ((struct mmc_blk_data *) |
1378 | dev_to_disk(parent)->private_data)->name_idx; | 1444 | dev_to_disk(parent)->private_data)->name_idx; |
1379 | 1445 | ||
1446 | md->area_type = area_type; | ||
1447 | |||
1380 | /* | 1448 | /* |
1381 | * Set the read-only status based on the supported commands | 1449 | * Set the read-only status based on the supported commands |
1382 | * and the write protect switch. | 1450 | * and the write protect switch. |
@@ -1470,7 +1538,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) | |||
1470 | size = card->csd.capacity << (card->csd.read_blkbits - 9); | 1538 | size = card->csd.capacity << (card->csd.read_blkbits - 9); |
1471 | } | 1539 | } |
1472 | 1540 | ||
1473 | md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL); | 1541 | md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL, |
1542 | MMC_BLK_DATA_AREA_MAIN); | ||
1474 | return md; | 1543 | return md; |
1475 | } | 1544 | } |
1476 | 1545 | ||
@@ -1479,13 +1548,14 @@ static int mmc_blk_alloc_part(struct mmc_card *card, | |||
1479 | unsigned int part_type, | 1548 | unsigned int part_type, |
1480 | sector_t size, | 1549 | sector_t size, |
1481 | bool default_ro, | 1550 | bool default_ro, |
1482 | const char *subname) | 1551 | const char *subname, |
1552 | int area_type) | ||
1483 | { | 1553 | { |
1484 | char cap_str[10]; | 1554 | char cap_str[10]; |
1485 | struct mmc_blk_data *part_md; | 1555 | struct mmc_blk_data *part_md; |
1486 | 1556 | ||
1487 | part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro, | 1557 | part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro, |
1488 | subname); | 1558 | subname, area_type); |
1489 | if (IS_ERR(part_md)) | 1559 | if (IS_ERR(part_md)) |
1490 | return PTR_ERR(part_md); | 1560 | return PTR_ERR(part_md); |
1491 | part_md->part_type = part_type; | 1561 | part_md->part_type = part_type; |
@@ -1518,7 +1588,8 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) | |||
1518 | card->part[idx].part_cfg, | 1588 | card->part[idx].part_cfg, |
1519 | card->part[idx].size >> 9, | 1589 | card->part[idx].size >> 9, |
1520 | card->part[idx].force_ro, | 1590 | card->part[idx].force_ro, |
1521 | card->part[idx].name); | 1591 | card->part[idx].name, |
1592 | card->part[idx].area_type); | ||
1522 | if (ret) | 1593 | if (ret) |
1523 | return ret; | 1594 | return ret; |
1524 | } | 1595 | } |
@@ -1547,9 +1618,16 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) | |||
1547 | 1618 | ||
1548 | static void mmc_blk_remove_req(struct mmc_blk_data *md) | 1619 | static void mmc_blk_remove_req(struct mmc_blk_data *md) |
1549 | { | 1620 | { |
1621 | struct mmc_card *card; | ||
1622 | |||
1550 | if (md) { | 1623 | if (md) { |
1624 | card = md->queue.card; | ||
1551 | if (md->disk->flags & GENHD_FL_UP) { | 1625 | if (md->disk->flags & GENHD_FL_UP) { |
1552 | device_remove_file(disk_to_dev(md->disk), &md->force_ro); | 1626 | device_remove_file(disk_to_dev(md->disk), &md->force_ro); |
1627 | if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && | ||
1628 | card->ext_csd.boot_ro_lockable) | ||
1629 | device_remove_file(disk_to_dev(md->disk), | ||
1630 | &md->power_ro_lock); | ||
1553 | 1631 | ||
1554 | /* Stop new requests from getting into the queue */ | 1632 | /* Stop new requests from getting into the queue */ |
1555 | del_gendisk(md->disk); | 1633 | del_gendisk(md->disk); |
@@ -1578,6 +1656,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card, | |||
1578 | static int mmc_add_disk(struct mmc_blk_data *md) | 1656 | static int mmc_add_disk(struct mmc_blk_data *md) |
1579 | { | 1657 | { |
1580 | int ret; | 1658 | int ret; |
1659 | struct mmc_card *card = md->queue.card; | ||
1581 | 1660 | ||
1582 | add_disk(md->disk); | 1661 | add_disk(md->disk); |
1583 | md->force_ro.show = force_ro_show; | 1662 | md->force_ro.show = force_ro_show; |
@@ -1587,7 +1666,33 @@ static int mmc_add_disk(struct mmc_blk_data *md) | |||
1587 | md->force_ro.attr.mode = S_IRUGO | S_IWUSR; | 1666 | md->force_ro.attr.mode = S_IRUGO | S_IWUSR; |
1588 | ret = device_create_file(disk_to_dev(md->disk), &md->force_ro); | 1667 | ret = device_create_file(disk_to_dev(md->disk), &md->force_ro); |
1589 | if (ret) | 1668 | if (ret) |
1590 | del_gendisk(md->disk); | 1669 | goto force_ro_fail; |
1670 | |||
1671 | if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && | ||
1672 | card->ext_csd.boot_ro_lockable) { | ||
1673 | mode_t mode; | ||
1674 | |||
1675 | if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS) | ||
1676 | mode = S_IRUGO; | ||
1677 | else | ||
1678 | mode = S_IRUGO | S_IWUSR; | ||
1679 | |||
1680 | md->power_ro_lock.show = power_ro_lock_show; | ||
1681 | md->power_ro_lock.store = power_ro_lock_store; | ||
1682 | md->power_ro_lock.attr.mode = mode; | ||
1683 | md->power_ro_lock.attr.name = | ||
1684 | "ro_lock_until_next_power_on"; | ||
1685 | ret = device_create_file(disk_to_dev(md->disk), | ||
1686 | &md->power_ro_lock); | ||
1687 | if (ret) | ||
1688 | goto power_ro_lock_fail; | ||
1689 | } | ||
1690 | return ret; | ||
1691 | |||
1692 | power_ro_lock_fail: | ||
1693 | device_remove_file(disk_to_dev(md->disk), &md->force_ro); | ||
1694 | force_ro_fail: | ||
1695 | del_gendisk(md->disk); | ||
1591 | 1696 | ||
1592 | return ret; | 1697 | return ret; |
1593 | } | 1698 | } |