* [PATCH v3 1/3] mmc: core: Add raw_boot_mult field to mmc_ext_csd
2021-07-31 18:56 [PATCH v3 0/3] Support EFI partition on NVIDIA Tegra devices Dmitry Osipenko
@ 2021-07-31 18:56 ` Dmitry Osipenko
2021-07-31 18:56 ` [PATCH v3 2/3] mmc: block: Add mmc_bdev_to_card() helper Dmitry Osipenko
2021-07-31 18:56 ` [PATCH v3 3/3] partitions/efi: Support NVIDIA Tegra devices Dmitry Osipenko
2 siblings, 0 replies; 4+ messages in thread
From: Dmitry Osipenko @ 2021-07-31 18:56 UTC (permalink / raw)
To: Jens Axboe, Thierry Reding, Jonathan Hunter,
Michał Mirosław, David Heidelberg, Peter Geis,
Ulf Hansson, Adrian Hunter, Christoph Hellwig, Davidlohr Bueso,
Ion Agorria, Svyatoslav Ryhel
Cc: linux-tegra, linux-block, linux-efi
Bootloader of NVIDIA Tegra devices linearizes the boot0/boot1/main
partitions into a single virtual space, and thus, all partition addresses
are shifted by the size of boot0 + boot1 partitions. The offset needs to
be known in order to find the EFI entry on EMMC storage of Tegra devices.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
drivers/mmc/core/mmc.c | 2 ++
include/linux/mmc/card.h | 1 +
2 files changed, 3 insertions(+)
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];
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 74e6c0624d27..37f975875102 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -109,6 +109,7 @@ struct mmc_ext_csd {
u8 raw_hc_erase_gap_size; /* 221 */
u8 raw_erase_timeout_mult; /* 223 */
u8 raw_hc_erase_grp_size; /* 224 */
+ u8 raw_boot_mult; /* 226 */
u8 raw_sec_trim_mult; /* 229 */
u8 raw_sec_erase_mult; /* 230 */
u8 raw_sec_feature_support;/* 231 */
--
2.32.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v3 2/3] mmc: block: Add mmc_bdev_to_card() helper
2021-07-31 18:56 [PATCH v3 0/3] Support EFI partition on NVIDIA Tegra devices Dmitry Osipenko
2021-07-31 18:56 ` [PATCH v3 1/3] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
@ 2021-07-31 18:56 ` Dmitry Osipenko
2021-07-31 18:56 ` [PATCH v3 3/3] partitions/efi: Support NVIDIA Tegra devices Dmitry Osipenko
2 siblings, 0 replies; 4+ messages in thread
From: Dmitry Osipenko @ 2021-07-31 18:56 UTC (permalink / raw)
To: Jens Axboe, Thierry Reding, Jonathan Hunter,
Michał Mirosław, David Heidelberg, Peter Geis,
Ulf Hansson, Adrian Hunter, Christoph Hellwig, Davidlohr Bueso,
Ion Agorria, Svyatoslav Ryhel
Cc: linux-tegra, linux-block, linux-efi
Add mmc_bdev_to_card() helper which is needed for checking EMMC
parameters by partition table parser in order to find EFI entry
on NVIDIA Tegra devices.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
drivers/mmc/core/block.c | 15 +++++++++++++++
include/linux/mmc/blkdev.h | 13 +++++++++++++
2 files changed, 28 insertions(+)
create mode 100644 include/linux/mmc/blkdev.h
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index ce8aed562929..93ca25e97259 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -42,6 +42,7 @@
#include <linux/debugfs.h>
#include <linux/mmc/ioctl.h>
+#include <linux/mmc/blkdev.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
@@ -313,6 +314,20 @@ static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
return ret;
}
+struct mmc_card *mmc_bdev_to_card(struct block_device *bdev)
+{
+ struct mmc_blk_data *md;
+
+ if (bdev->bd_disk->major != MMC_BLOCK_MAJOR)
+ return NULL;
+
+ md = mmc_blk_get(bdev->bd_disk);
+ if (!md)
+ return NULL;
+
+ return md->queue.card;
+}
+
static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
diff --git a/include/linux/mmc/blkdev.h b/include/linux/mmc/blkdev.h
new file mode 100644
index 000000000000..67608c58de70
--- /dev/null
+++ b/include/linux/mmc/blkdev.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * linux/include/linux/mmc/blkdev.h
+ */
+#ifndef LINUX_MMC_BLOCK_DEVICE_H
+#define LINUX_MMC_BLOCK_DEVICE_H
+
+struct block_device;
+struct mmc_card;
+
+struct mmc_card *mmc_bdev_to_card(struct block_device *bdev);
+
+#endif /* LINUX_MMC_BLOCK_DEVICE_H */
--
2.32.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v3 3/3] partitions/efi: Support NVIDIA Tegra devices
2021-07-31 18:56 [PATCH v3 0/3] Support EFI partition on NVIDIA Tegra devices Dmitry Osipenko
2021-07-31 18:56 ` [PATCH v3 1/3] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
2021-07-31 18:56 ` [PATCH v3 2/3] mmc: block: Add mmc_bdev_to_card() helper Dmitry Osipenko
@ 2021-07-31 18:56 ` Dmitry Osipenko
2 siblings, 0 replies; 4+ messages in thread
From: Dmitry Osipenko @ 2021-07-31 18:56 UTC (permalink / raw)
To: Jens Axboe, Thierry Reding, Jonathan Hunter,
Michał Mirosław, David Heidelberg, Peter Geis,
Ulf Hansson, Adrian Hunter, Christoph Hellwig, Davidlohr Bueso,
Ion Agorria, Svyatoslav Ryhel
Cc: linux-tegra, linux-block, linux-efi
NVIDIA Tegra consumer devices have EMMC storage that has GPT entry at a
non-standard location. Support looking up GPT entry at a special sector
to enable such devices.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
block/partitions/Kconfig | 8 ++++
block/partitions/Makefile | 1 +
block/partitions/check.h | 2 +
block/partitions/core.c | 3 ++
block/partitions/efi.c | 9 ++++
block/partitions/tegra.c | 86 +++++++++++++++++++++++++++++++++++++++
6 files changed, 109 insertions(+)
create mode 100644 block/partitions/tegra.c
diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
index 278593b8e4e9..5db25e7efbb7 100644
--- a/block/partitions/Kconfig
+++ b/block/partitions/Kconfig
@@ -267,3 +267,11 @@ config CMDLINE_PARTITION
help
Say Y here if you want to read the partition table from bootargs.
The format for the command line is just like mtdparts.
+
+config TEGRA_PARTITION
+ bool "NVIDIA Tegra Partition support" if PARTITION_ADVANCED
+ default y if ARCH_TEGRA
+ depends on EFI_PARTITION && MMC_BLOCK && (ARCH_TEGRA || COMPILE_TEST)
+ help
+ Say Y here if you would like to be able to read the hard disk
+ partition table format used by NVIDIA Tegra machines.
diff --git a/block/partitions/Makefile b/block/partitions/Makefile
index a7f05cdb02a8..83cb70c6d08d 100644
--- a/block/partitions/Makefile
+++ b/block/partitions/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_IBM_PARTITION) += ibm.o
obj-$(CONFIG_EFI_PARTITION) += efi.o
obj-$(CONFIG_KARMA_PARTITION) += karma.o
obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
+obj-$(CONFIG_TEGRA_PARTITION) += tegra.o
diff --git a/block/partitions/check.h b/block/partitions/check.h
index c577e9ee67f0..5fcc85087465 100644
--- a/block/partitions/check.h
+++ b/block/partitions/check.h
@@ -22,6 +22,7 @@ struct parsed_partitions {
int limit;
bool access_beyond_eod;
char *pp_buf;
+ sector_t force_gpt_sector;
};
typedef struct {
@@ -67,4 +68,5 @@ int osf_partition(struct parsed_partitions *state);
int sgi_partition(struct parsed_partitions *state);
int sun_partition(struct parsed_partitions *state);
int sysv68_partition(struct parsed_partitions *state);
+int tegra_partition_forced_gpt(struct parsed_partitions *state);
int ultrix_partition(struct parsed_partitions *state);
diff --git a/block/partitions/core.c b/block/partitions/core.c
index fb3a556cacce..2fb6db3134ee 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -82,6 +82,9 @@ static int (*check_part[])(struct parsed_partitions *) = {
#endif
#ifdef CONFIG_SYSV68_PARTITION
sysv68_partition,
+#endif
+#ifdef CONFIG_TEGRA_PARTITION
+ tegra_partition_forced_gpt,
#endif
NULL
};
diff --git a/block/partitions/efi.c b/block/partitions/efi.c
index e2716792ecc1..093b084d002f 100644
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -621,6 +621,15 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
if (!good_agpt && force_gpt)
good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes);
+ /*
+ * The force_gpt_sector is used by NVIDIA Tegra partition parser in
+ * order to convey a non-standard location of the GPT entry for lookup.
+ * By default force_gpt_sector is set to 0 and has no effect.
+ */
+ if (!good_agpt && force_gpt && state->force_gpt_sector)
+ good_agpt = is_gpt_valid(state, state->force_gpt_sector,
+ &agpt, &aptes);
+
/* The obviously unsuccessful case */
if (!good_pgpt && !good_agpt)
goto fail;
diff --git a/block/partitions/tegra.c b/block/partitions/tegra.c
new file mode 100644
index 000000000000..d8801a885a62
--- /dev/null
+++ b/block/partitions/tegra.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "tegra-partition: " fmt
+
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/sizes.h>
+
+#include <linux/mmc/blkdev.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <soc/tegra/common.h>
+
+#include "check.h"
+
+#define TEGRA_PT_ERR(_state, fmt, ...) \
+ pr_debug("%s: " fmt, \
+ (_state)->bdev->bd_disk->disk_name, ##__VA_ARGS__)
+
+static const struct of_device_id tegra_sdhci_match[] = {
+ { .compatible = "nvidia,tegra20-sdhci", },
+ { .compatible = "nvidia,tegra30-sdhci", },
+ { .compatible = "nvidia,tegra114-sdhci", },
+ { .compatible = "nvidia,tegra124-sdhci", },
+ {}
+};
+
+static int
+tegra_partition_table_emmc_boot_offset(struct parsed_partitions *state)
+{
+ struct mmc_card *card = mmc_bdev_to_card(state->bdev);
+
+ /* filter out unrelated and untested boot sources */
+ if (!card || card->ext_csd.rev < 3 ||
+ !mmc_card_is_blockaddr(card) ||
+ mmc_card_is_removable(card->host) ||
+ bdev_logical_block_size(state->bdev) != SZ_512 ||
+ !of_match_node(tegra_sdhci_match, card->host->parent->of_node)) {
+ TEGRA_PT_ERR(state, "unexpected boot source\n");
+ return -1;
+ }
+
+ /*
+ * 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
+ *
+ * This function returns number of sectors occupied by the both boot
+ * partitions.
+ */
+ return card->ext_csd.raw_boot_mult * SZ_128K /
+ SZ_512 * MMC_NUM_BOOT_PARTITION;
+}
+
+int tegra_partition_forced_gpt(struct parsed_partitions *state)
+{
+ int ret, boot_offset;
+
+ if (!soc_is_tegra())
+ return 0;
+
+ boot_offset = tegra_partition_table_emmc_boot_offset(state);
+ if (boot_offset < 0)
+ return 0;
+
+ /*
+ * The fixed GPT entry address is calculated like this:
+ *
+ * gpt_sector = ext_csd.sectors_num - ext_csd.boot_sectors_num - 1
+ *
+ * This algorithm is defined by NVIDIA and used by Android devices.
+ */
+ state->force_gpt_sector = get_capacity(state->bdev->bd_disk);
+ state->force_gpt_sector -= boot_offset + 1;
+
+ ret = efi_partition(state);
+ state->force_gpt_sector = 0;
+
+ return ret;
+}
--
2.32.0
^ permalink raw reply related [flat|nested] 4+ messages in thread