diff options
author | Dmitry Osipenko <digetx@gmail.com> | 2021-08-20 03:45:35 +0300 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2021-08-24 10:09:06 -0600 |
commit | dc913385dd74e625271482c30aefedd1e5af7b8c (patch) | |
tree | 4e9a7960d600179c7799501d4f89de4ebea2c9e1 /drivers/mmc/core | |
parent | 466d9c4904deb25e2e8dcd29d3a998f4e3fa7c17 (diff) | |
download | lwn-dc913385dd74e625271482c30aefedd1e5af7b8c.tar.gz lwn-dc913385dd74e625271482c30aefedd1e5af7b8c.zip |
mmc: block: Support alternative_gpt_sector() operation
Support generic alternative_gpt_sector() block device operation.
It calculates location of GPT entry for eMMC of NVIDIA Tegra Android
devices. Add new MMC_CAP2_ALT_GPT_TEGRA flag that enables scanning of
alternative GPT sector and add raw_boot_mult field to mmc_ext_csd
which allows to get size of the boot partitions that is needed for
the calculation.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://lore.kernel.org/r/20210820004536.15791-4-digetx@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r-- | drivers/mmc/core/block.c | 21 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 35 | ||||
-rw-r--r-- | drivers/mmc/core/core.h | 2 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 2 |
4 files changed, 60 insertions, 0 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 4c11f171e56d..6a15fdf6e5f2 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -831,6 +831,26 @@ static int mmc_blk_compat_ioctl(struct block_device *bdev, fmode_t mode, } #endif +static int mmc_blk_alternative_gpt_sector(struct gendisk *disk, + sector_t *sector) +{ + struct mmc_blk_data *md; + int ret; + + md = mmc_blk_get(disk); + if (!md) + return -EINVAL; + + if (md->queue.card) + ret = mmc_card_alternative_gpt_sector(md->queue.card, sector); + else + ret = -ENODEV; + + mmc_blk_put(md); + + return ret; +} + static const struct block_device_operations mmc_bdops = { .open = mmc_blk_open, .release = mmc_blk_release, @@ -840,6 +860,7 @@ static const struct block_device_operations mmc_bdops = { #ifdef CONFIG_COMPAT .compat_ioctl = mmc_blk_compat_ioctl, #endif + .alternative_gpt_sector = mmc_blk_alternative_gpt_sector, }; static int mmc_blk_part_switch_pre(struct mmc_card *card, diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 95fedcf56e4a..605f5e8648c1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2149,6 +2149,41 @@ int mmc_detect_card_removed(struct mmc_host *host) } EXPORT_SYMBOL(mmc_detect_card_removed); +int mmc_card_alternative_gpt_sector(struct mmc_card *card, sector_t *gpt_sector) +{ + unsigned int boot_sectors_num; + + if ((!(card->host->caps2 & MMC_CAP2_ALT_GPT_TEGRA))) + return -EOPNOTSUPP; + + /* filter out unrelated cards */ + if (card->ext_csd.rev < 3 || + !mmc_card_mmc(card) || + !mmc_card_is_blockaddr(card) || + mmc_card_is_removable(card->host)) + return -ENOENT; + + /* + * eMMC storage has two special boot partitions in addition to the + * main one. NVIDIA's bootloader linearizes eMMC boot0->boot1->main + * accesses, this means that the partition table addresses are shifted + * by the size of boot partitions. In accordance with the eMMC + * specification, the boot partition size is calculated as follows: + * + * boot partition size = 128K byte x BOOT_SIZE_MULT + * + * Calculate number of sectors occupied by the both boot partitions. + */ + boot_sectors_num = card->ext_csd.raw_boot_mult * SZ_128K / + SZ_512 * MMC_NUM_BOOT_PARTITION; + + /* Defined by NVIDIA and used by Android devices. */ + *gpt_sector = card->ext_csd.sectors - boot_sectors_num - 1; + + return 0; +} +EXPORT_SYMBOL(mmc_card_alternative_gpt_sector); + void mmc_rescan(struct work_struct *work) { struct mmc_host *host = diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 0c4de2030b3f..7931a4f0137d 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -119,6 +119,8 @@ void mmc_release_host(struct mmc_host *host); void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx); void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx); +int mmc_card_alternative_gpt_sector(struct mmc_card *card, sector_t *sector); + /** * mmc_claim_host - exclusively claim a host * @host: mmc host to claim diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 838726b68ff3..29e58ffae379 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -418,6 +418,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.raw_hc_erase_grp_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; + card->ext_csd.raw_boot_mult = + ext_csd[EXT_CSD_BOOT_MULT]; if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; |