linux-efi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Support EFI partition on NVIDIA Tegra devices
@ 2021-07-31 18:36 Dmitry Osipenko
  2021-07-31 18:36 ` [PATCH v2 1/3] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Dmitry Osipenko @ 2021-07-31 18:36 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Ulf Hansson, Adrian Hunter, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso, Ion Agorria, Svyatoslav Ryhel
  Cc: linux-tegra, linux-block, linux-efi

This series adds the most minimal EFI partition support for NVIDIA Tegra
consumer devices, like Android tablets and game consoles, making theirs
EMMC accessible out-of-the-box using downstream bootloader and mainline
Linux kernel.  EMMC now works on Acer A500 tablet and Ouya game console
that are already well supported in mainline and internal storage is the
only biggest thing left to support.

Changelog:

v2: - This is continuation of [1] where Davidlohr Bueso suggested that it
      should be better to avoid supporting in mainline the custom gpt_sector
      kernel cmdline parameter that downstream Android kernels use.  We can
      do this for the devices that are already mainlined, so I dropped the
      cmdline from the v2 and left only the variant with a fixed GPT address.

[1] https://lore.kernel.org/linux-efi/20210327212100.3834-3-digetx@gmail.com/T/

Dmitry Osipenko (3):
  mmc: core: Add raw_boot_mult field to mmc_ext_csd
  mmc: block: Add mmc_bdev_to_card() helper
  partitions/efi: Support NVIDIA Tegra devices

 block/partitions/Kconfig   |  8 ++++
 block/partitions/Makefile  |  1 +
 block/partitions/check.h   |  2 +
 block/partitions/core.c    |  3 ++
 block/partitions/efi.c     | 18 ++++++++
 block/partitions/tegra.c   | 86 ++++++++++++++++++++++++++++++++++++++
 drivers/mmc/core/block.c   | 15 +++++++
 drivers/mmc/core/mmc.c     |  2 +
 include/linux/mmc/blkdev.h | 13 ++++++
 include/linux/mmc/card.h   |  1 +
 10 files changed, 149 insertions(+)
 create mode 100644 block/partitions/tegra.c
 create mode 100644 include/linux/mmc/blkdev.h

-- 
2.32.0


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

* [PATCH v2 1/3] mmc: core: Add raw_boot_mult field to mmc_ext_csd
  2021-07-31 18:36 [PATCH v2 0/3] Support EFI partition on NVIDIA Tegra devices Dmitry Osipenko
@ 2021-07-31 18:36 ` Dmitry Osipenko
  2021-07-31 18:36 ` [PATCH v2 2/3] mmc: block: Add mmc_bdev_to_card() helper Dmitry Osipenko
  2021-07-31 18:36 ` [PATCH v2 3/3] partitions/efi: Support NVIDIA Tegra devices Dmitry Osipenko
  2 siblings, 0 replies; 5+ messages in thread
From: Dmitry Osipenko @ 2021-07-31 18:36 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Ulf Hansson, Adrian Hunter, Christoph Hellwig, Ard Biesheuvel,
	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	[flat|nested] 5+ messages in thread

* [PATCH v2 2/3] mmc: block: Add mmc_bdev_to_card() helper
  2021-07-31 18:36 [PATCH v2 0/3] Support EFI partition on NVIDIA Tegra devices Dmitry Osipenko
  2021-07-31 18:36 ` [PATCH v2 1/3] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
@ 2021-07-31 18:36 ` Dmitry Osipenko
  2021-07-31 18:36 ` [PATCH v2 3/3] partitions/efi: Support NVIDIA Tegra devices Dmitry Osipenko
  2 siblings, 0 replies; 5+ messages in thread
From: Dmitry Osipenko @ 2021-07-31 18:36 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Ulf Hansson, Adrian Hunter, Christoph Hellwig, Ard Biesheuvel,
	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	[flat|nested] 5+ messages in thread

* [PATCH v2 3/3] partitions/efi: Support NVIDIA Tegra devices
  2021-07-31 18:36 [PATCH v2 0/3] Support EFI partition on NVIDIA Tegra devices Dmitry Osipenko
  2021-07-31 18:36 ` [PATCH v2 1/3] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
  2021-07-31 18:36 ` [PATCH v2 2/3] mmc: block: Add mmc_bdev_to_card() helper Dmitry Osipenko
@ 2021-07-31 18:36 ` Dmitry Osipenko
  2021-07-31 18:46   ` Dmitry Osipenko
  2 siblings, 1 reply; 5+ messages in thread
From: Dmitry Osipenko @ 2021-07-31 18:36 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Ulf Hansson, Adrian Hunter, Christoph Hellwig, Ard Biesheuvel,
	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    | 18 ++++++++
 block/partitions/tegra.c  | 86 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 118 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..dced55c0d2e1 100644
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -98,6 +98,15 @@ static int force_gpt;
 static int __init
 force_gpt_fn(char *str)
 {
+	/*
+	 * This check allows to properly parse cmdline variants like
+	 * "gpt gpt_sector=<sector>" and "gpt_sector=<sector> gpt" since
+	 * "gpt" overlaps with the "gpt_sector=", see tegra_gpt_sector_fn().
+	 * The argument is absent for a boolean cmdline option.
+	 */
+	if (strlen(str))
+		return 0;
+
 	force_gpt = 1;
 	return 1;
 }
@@ -621,6 +630,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	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 3/3] partitions/efi: Support NVIDIA Tegra devices
  2021-07-31 18:36 ` [PATCH v2 3/3] partitions/efi: Support NVIDIA Tegra devices Dmitry Osipenko
@ 2021-07-31 18:46   ` Dmitry Osipenko
  0 siblings, 0 replies; 5+ messages in thread
From: Dmitry Osipenko @ 2021-07-31 18:46 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Ulf Hansson, Adrian Hunter, Christoph Hellwig, Ard Biesheuvel,
	Davidlohr Bueso, Ion Agorria, Svyatoslav Ryhel
  Cc: linux-tegra, linux-block, linux-efi

31.07.2021 21:36, Dmitry Osipenko пишет:
> diff --git a/block/partitions/efi.c b/block/partitions/efi.c
> index e2716792ecc1..dced55c0d2e1 100644
> --- a/block/partitions/efi.c
> +++ b/block/partitions/efi.c
> @@ -98,6 +98,15 @@ static int force_gpt;
>  static int __init
>  force_gpt_fn(char *str)
>  {
> +	/*
> +	 * This check allows to properly parse cmdline variants like
> +	 * "gpt gpt_sector=<sector>" and "gpt_sector=<sector> gpt" since
> +	 * "gpt" overlaps with the "gpt_sector=", see tegra_gpt_sector_fn().
> +	 * The argument is absent for a boolean cmdline option.
> +	 */
> +	if (strlen(str))
> +		return 0;

This is not needed anymore in this patch, I noticed it only once v2 was
already sent out. Will correct it in v3.

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

end of thread, other threads:[~2021-07-31 18:46 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-31 18:36 [PATCH v2 0/3] Support EFI partition on NVIDIA Tegra devices Dmitry Osipenko
2021-07-31 18:36 ` [PATCH v2 1/3] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
2021-07-31 18:36 ` [PATCH v2 2/3] mmc: block: Add mmc_bdev_to_card() helper Dmitry Osipenko
2021-07-31 18:36 ` [PATCH v2 3/3] partitions/efi: Support NVIDIA Tegra devices Dmitry Osipenko
2021-07-31 18:46   ` Dmitry Osipenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).