linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/8] Introduce NVIDIA Tegra Partition Tablex
@ 2020-03-06  2:12 Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 1/8] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
                   ` (7 more replies)
  0 siblings, 8 replies; 14+ messages in thread
From: Dmitry Osipenko @ 2020-03-06  2:12 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

Some NVIDIA Tegra devices have GPT entry at a wrong location and others may
even not have it at all. So either a custom workaround for GPT parsing or
TegraPT support is needed for those devices if we want to support them in
upstream kernel. The former solution was already rejected [1], let's try
the latter.

[1] https://patchwork.ozlabs.org/patch/1240809/

Big thanks to everyone who helped with figuring out the TegraPT format!

Changelog:

v2: - Addressed v1 review comments from Stephen Warren by using BIT for
      locating BCT position in IRAM.

    - Added more validations to the TegraPT parser: partition type is
      verified, eMMC instance ID is verified.

    - TegraPT parser now doesn't touch any devices other than eMMC.

    - EKS (encrypted keys) partition is blacklisted now.

    - Implemented eMMC boot partitions scanning. These new patches are
      added in a result:

        mmc: block: Add mmc_bdev_to_part_type() helper
        mmc: block: Add mmc_bdev_to_area_type() helper
        mmc: block: Add MMC_QUIRK_RESCAN_MAIN_BLKDEV
        mmc: block: Enable partition-table scanning for boot partitions
        partitions/tegra: Implement eMMC boot partitions scanning

Dmitry Osipenko (8):
  mmc: core: Add raw_boot_mult field to mmc_ext_csd
  mmc: block: Add mmc_bdev_to_card() helper
  partitions: Introduce NVIDIA Tegra Partition Table
  mmc: block: Add mmc_bdev_to_part_type() helper
  mmc: block: Add mmc_bdev_to_area_type() helper
  mmc: block: Add MMC_QUIRK_RESCAN_MAIN_BLKDEV
  mmc: block: Enable partition-table scanning for boot partitions
  partitions/tegra: Implement eMMC boot partitions scanning

 arch/arm/mach-tegra/tegra.c   |  54 +++
 block/partitions/Kconfig      |   9 +
 block/partitions/Makefile     |   1 +
 block/partitions/check.c      |   4 +
 block/partitions/tegra.c      | 608 ++++++++++++++++++++++++++++++++++
 block/partitions/tegra.h      |  83 +++++
 drivers/mmc/core/block.c      |  85 ++++-
 drivers/mmc/core/mmc.c        |   2 +
 include/linux/mmc/blkdev.h    |  15 +
 include/linux/mmc/card.h      |   2 +
 include/soc/tegra/bootdata.h  |  46 +++
 include/soc/tegra/common.h    |   9 +
 include/soc/tegra/partition.h |  18 +
 13 files changed, 934 insertions(+), 2 deletions(-)
 create mode 100644 block/partitions/tegra.c
 create mode 100644 block/partitions/tegra.h
 create mode 100644 include/linux/mmc/blkdev.h
 create mode 100644 include/soc/tegra/bootdata.h
 create mode 100644 include/soc/tegra/partition.h

-- 
2.25.1


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

* [PATCH v2 1/8] mmc: core: Add raw_boot_mult field to mmc_ext_csd
  2020-03-06  2:12 [PATCH v2 0/8] Introduce NVIDIA Tegra Partition Tablex Dmitry Osipenko
@ 2020-03-06  2:12 ` Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 2/8] mmc: block: Add mmc_bdev_to_card() helper Dmitry Osipenko
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Dmitry Osipenko @ 2020-03-06  2:12 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

In order to support parsing of NVIDIA Tegra Partition Table format, we
need to know the BOOT_SIZE_MULT value of the Extended CSD register because
NVIDIA's bootloader 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.

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 c2abd417a84a..ec91d503bc73 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -417,6 +417,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 cf3780a6ccc4..90b1d83ce675 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -108,6 +108,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.25.1


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

* [PATCH v2 2/8] mmc: block: Add mmc_bdev_to_card() helper
  2020-03-06  2:12 [PATCH v2 0/8] Introduce NVIDIA Tegra Partition Tablex Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 1/8] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
@ 2020-03-06  2:12 ` Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 3/8] partitions: Introduce NVIDIA Tegra Partition Table Dmitry Osipenko
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Dmitry Osipenko @ 2020-03-06  2:12 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

NVIDIA Tegra Partition Table takes into account MMC card's BOOT_SIZE_MULT
parameter, and thus, the partition parser needs to retrieve that EXT_CSD
value from the block device. There are also some other parts of struct
mmc_card that are needed for the partition parser in order to calculate
the eMMC offset and verify different things. This patch introduces new
helper which takes block device for the input argument and returns the
corresponding MMC card.

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 7634894df853..36d84a8e182c 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -40,6 +40,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>
@@ -306,6 +307,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.25.1


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

* [PATCH v2 3/8] partitions: Introduce NVIDIA Tegra Partition Table
  2020-03-06  2:12 [PATCH v2 0/8] Introduce NVIDIA Tegra Partition Tablex Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 1/8] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 2/8] mmc: block: Add mmc_bdev_to_card() helper Dmitry Osipenko
@ 2020-03-06  2:12 ` Dmitry Osipenko
  2020-03-06  2:22   ` Randy Dunlap
  2020-03-08 23:30   ` kbuild test robot
  2020-03-06  2:12 ` [PATCH v2 4/8] mmc: block: Add mmc_bdev_to_part_type() helper Dmitry Osipenko
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 14+ messages in thread
From: Dmitry Osipenko @ 2020-03-06  2:12 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

All NVIDIA Tegra devices use a special partition table format for the
internal storage partitioning. Most of Tegra devices have GPT partition
in addition to TegraPT, but some older Android consumer-grade devices do
not or GPT is placed in a wrong sector, and thus, the TegraPT is needed
in order to support these devices properly in the upstream kernel. This
patch adds support for NVIDIA Tegra Partition Table format that is used
at least by all NVIDIA Tegra20 and Tegra30 devices.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 arch/arm/mach-tegra/tegra.c   |  54 ++++
 block/partitions/Kconfig      |   9 +
 block/partitions/Makefile     |   1 +
 block/partitions/check.c      |   4 +
 block/partitions/tegra.c      | 510 ++++++++++++++++++++++++++++++++++
 block/partitions/tegra.h      |  83 ++++++
 include/soc/tegra/bootdata.h  |  46 +++
 include/soc/tegra/common.h    |   9 +
 include/soc/tegra/partition.h |  18 ++
 9 files changed, 734 insertions(+)
 create mode 100644 block/partitions/tegra.c
 create mode 100644 block/partitions/tegra.h
 create mode 100644 include/soc/tegra/bootdata.h
 create mode 100644 include/soc/tegra/partition.h

diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index eeacff626546..fc3b5013f7a9 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -28,7 +28,9 @@
 
 #include <linux/firmware/trusted_foundations.h>
 
+#include <soc/tegra/bootdata.h>
 #include <soc/tegra/fuse.h>
+#include <soc/tegra/partition.h>
 #include <soc/tegra/pmc.h>
 
 #include <asm/firmware.h>
@@ -62,9 +64,61 @@ u32 tegra_uart_config[3] = {
 	0,
 };
 
+static void __init tegra_boot_config_table_init(void)
+{
+	struct tegra30_boot_config_table __iomem *t30_bct;
+	struct tegra20_boot_config_table __iomem *t20_bct;
+	struct tegra20_boot_info_table   __iomem *t20_bit;
+	u32 iram_end   = TEGRA_IRAM_BASE + TEGRA_IRAM_SIZE;
+	u32 iram_start = TEGRA_IRAM_BASE;
+	u32 pt_addr, pt_size, bct_size;
+
+	t20_bit = IO_ADDRESS(TEGRA_IRAM_BASE);
+
+	if (of_machine_is_compatible("nvidia,tegra20")) {
+		bct_size = sizeof(*t20_bct);
+
+		if (t20_bit->bct_size != bct_size ||
+		    t20_bit->bct_ptr < iram_start ||
+		    t20_bit->bct_ptr > iram_end - bct_size)
+			return;
+
+		t20_bct = IO_ADDRESS(t20_bit->bct_ptr);
+
+		if (t20_bct->boot_data_version != TEGRA_BOOTDATA_VERSION_T20)
+			return;
+
+		pt_addr = t20_bct->partition_table_logical_sector_address;
+		pt_size = t20_bct->partition_table_num_logical_sectors;
+
+	} else if (of_machine_is_compatible("nvidia,tegra30")) {
+		bct_size = sizeof(*t30_bct);
+
+		if (t20_bit->bct_size != bct_size ||
+		    t20_bit->bct_ptr < iram_start ||
+		    t20_bit->bct_ptr > iram_end - bct_size)
+			return;
+
+		t30_bct = IO_ADDRESS(t20_bit->bct_ptr);
+
+		if (t30_bct->boot_data_version != TEGRA_BOOTDATA_VERSION_T30)
+			return;
+
+		pt_addr = t30_bct->partition_table_logical_sector_address;
+		pt_size = t30_bct->partition_table_num_logical_sectors;
+	} else {
+		return;
+	}
+
+	pr_info("%s: BCT found in IRAM\n", __func__);
+
+	tegra_partition_table_setup(pt_addr, pt_size);
+}
+
 static void __init tegra_init_early(void)
 {
 	of_register_trusted_foundations();
+	tegra_boot_config_table_init();
 	tegra_cpu_reset_handler_init();
 	call_firmware_op(l2x0_init);
 }
diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
index 702689a628f0..d3c5c6ad6d58 100644
--- a/block/partitions/Kconfig
+++ b/block/partitions/Kconfig
@@ -268,3 +268,12 @@ 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 ARCH_TEGRA || COMPILE_TEST
+	select MMC_BLOCK
+	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 2f276b677c81..807319883a18 100644
--- a/block/partitions/Makefile
+++ b/block/partitions/Makefile
@@ -21,3 +21,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.c b/block/partitions/check.c
index ffe408fead0c..91268773b6ce 100644
--- a/block/partitions/check.c
+++ b/block/partitions/check.c
@@ -36,6 +36,7 @@
 #include "karma.h"
 #include "sysv68.h"
 #include "cmdline.h"
+#include "tegra.h"
 
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
 
@@ -108,6 +109,9 @@ static int (*check_part[])(struct parsed_partitions *) = {
 #endif
 #ifdef CONFIG_SYSV68_PARTITION
 	sysv68_partition,
+#endif
+#ifdef CONFIG_TEGRA_PARTITION
+	tegra_partition,
 #endif
 	NULL
 };
diff --git a/block/partitions/tegra.c b/block/partitions/tegra.c
new file mode 100644
index 000000000000..6f150a7e3275
--- /dev/null
+++ b/block/partitions/tegra.c
@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVIDIA Tegra Partition Table
+ *
+ * Copyright (C) 2020 GRATE-DRIVER project
+ * Copyright (C) 2020 Dmitry Osipenko <digetx@gmail.com>
+ *
+ * Credits for the partition table format:
+ *
+ *   Andrey Danin <danindrey@mail.ru>       (Toshiba AC100 TegraPT format)
+ *   Gilles Grandou <gilles@grandou.net>    (Toshiba AC100 TegraPT format)
+ *   Ryan Grachek <ryan@edited.us>          (Google TV "Molly" TegraPT format)
+ *   Stephen Warren <swarren@wwwdotorg.org> (Useful suggestions about eMMC/etc)
+ */
+
+#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/slab.h>
+#include <linux/string.h>
+
+#include <linux/mmc/blkdev.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <soc/tegra/common.h>
+#include <soc/tegra/partition.h>
+
+#include "check.h"
+#include "tegra.h"
+
+#define TEGRA_PT_SECTOR_SZ	(TEGRA_PT_LOGICAL_SECTOR_SIZE / SECTOR_SIZE)
+#define TEGRA_PT_SECTOR(s)	(TEGRA_PT_SECTOR_SZ * (s))
+
+#define TEGRA_PT_INFO(ptp, fmt, ...)					\
+	pr_info("%s: " fmt,						\
+		(ptp)->state->bdev->bd_disk->disk_name, ##__VA_ARGS__)
+
+#define TEGRA_PT_ERR(ptp, fmt, ...)					\
+	pr_err("%s: " fmt,						\
+		(ptp)->state->bdev->bd_disk->disk_name, ##__VA_ARGS__)
+
+#define TEGRA_PT_PARSE_ERR(ptp, fmt, ...)				\
+	TEGRA_PT_ERR(ptp, "sector %llu: invalid " fmt,			\
+		     (ptp)->sector, ##__VA_ARGS__)
+
+struct tegra_partition_table_parser {
+	struct tegra_partition_table *pt;
+	struct parsed_partitions *state;
+	bool pt_entry_checked;
+	sector_t sector;
+	int boot_offset;
+	u32 dev_instance;
+	u32 dev_id;
+};
+
+union tegra_partition_table_u {
+	struct tegra_partition_table pt;
+	u8 pt_parts[TEGRA_PT_SECTOR_SZ][SECTOR_SIZE];
+};
+
+struct tegra_partition_type {
+	unsigned int type;
+	char *name;
+};
+
+static sector_t tegra_pt_sector_address;
+static sector_t tegra_pt_sectors_num;
+
+void tegra_partition_table_setup(sector_t logical_sector_address,
+				 sector_t logical_sectors_num)
+{
+	tegra_pt_sector_address = TEGRA_PT_SECTOR(logical_sector_address);
+	tegra_pt_sectors_num    = TEGRA_PT_SECTOR(logical_sectors_num);
+
+	pr_info("initialized to sector = %llu sectors_num = %llu\n",
+		tegra_pt_sector_address, tegra_pt_sectors_num);
+}
+
+/*
+ * Some partitions are very sensitive, changing data on them may brick device.
+ *
+ * For more details about partitions see:
+ *
+ *  "https://docs.nvidia.com/jetson/l4t/Tegra Linux Driver Package Development Guide/part_config.html"
+ */
+static const char * const partitions_blacklist[] = {
+	"BCT", "EBT", "EKS", "GP1", "GPT", "MBR", "PT",
+};
+
+static bool tegra_partition_name_match(struct tegra_partition *p,
+				       const char *name)
+{
+	return !strncmp(p->partition_name, name, TEGRA_PT_NAME_SIZE);
+}
+
+static bool tegra_partition_skip(struct tegra_partition *p,
+				 struct tegra_partition_table_parser *ptp,
+				 sector_t sector)
+{
+	unsigned int i;
+
+	/* skip eMMC boot partitions */
+	if (sector < ptp->boot_offset)
+		return true;
+
+	for (i = 0; i < ARRAY_SIZE(partitions_blacklist); i++) {
+		if (tegra_partition_name_match(p, partitions_blacklist[i]))
+			return true;
+	}
+
+	return false;
+}
+
+static const struct tegra_partition_type tegra_partition_expected_types[] = {
+	{ .type = TEGRA_PT_PART_TYPE_BCT,	.name = "BCT", },
+	{ .type = TEGRA_PT_PART_TYPE_EBT,	.name = "EBT", },
+	{ .type = TEGRA_PT_PART_TYPE_PT,	.name = "PT",  },
+	{ .type = TEGRA_PT_PART_TYPE_GP1,	.name = "GP1", },
+	{ .type = TEGRA_PT_PART_TYPE_GPT,	.name = "GPT", },
+	{ .type = TEGRA_PT_PART_TYPE_GENERIC,	.name = NULL,  },
+};
+
+static int tegra_partition_type_valid(struct tegra_partition_table_parser *ptp,
+				      struct tegra_partition *p)
+{
+	const struct tegra_partition_type *ptype;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_partition_expected_types); i++) {
+		ptype = &tegra_partition_expected_types[i];
+
+		if (ptype->name && !tegra_partition_name_match(p, ptype->name))
+			continue;
+
+		if (p->part_info.partition_type == ptype->type)
+			return 0;
+
+		/*
+		 * Unsure about all possible types, let's emit error and
+		 * allow to continue for now.
+		 */
+		if (!ptype->name)
+			return 1;
+	}
+
+	return -1;
+}
+
+static bool tegra_partition_valid(struct tegra_partition_table_parser *ptp,
+				  struct tegra_partition *p,
+				  struct tegra_partition *prev,
+				  sector_t sector,
+				  sector_t size)
+{
+	struct tegra_partition_info *prev_pi = &prev->part_info;
+	sector_t sect_end = TEGRA_PT_SECTOR(prev_pi->logical_sector_address +
+					    prev_pi->logical_sectors_num);
+	char *type, name[2][TEGRA_PT_NAME_SIZE + 1];
+	int err;
+
+	strscpy(name[0], p->partition_name,    sizeof(name[0]));
+	strscpy(name[1], prev->partition_name, sizeof(name[1]));
+
+	/* validate expected partition name/type */
+	err = tegra_partition_type_valid(ptp, p);
+	if (err) {
+		TEGRA_PT_PARSE_ERR(ptp, "partition_type: [%s] partition_type=%u\n",
+				   name[0], p->part_info.partition_type);
+		if (err < 0)
+			return false;
+	}
+
+	/* validate partition table BCT addresses */
+	if (tegra_partition_name_match(p, "PT")) {
+		if (sector != tegra_pt_sector_address &&
+		    size   != tegra_pt_sectors_num) {
+			TEGRA_PT_PARSE_ERR(ptp, "PT location: sector=%llu size=%llu\n",
+					   sector, size);
+			return false;
+		}
+
+		if (ptp->pt_entry_checked) {
+			TEGRA_PT_PARSE_ERR(ptp, "(duplicated) PT\n");
+			return false;
+		}
+
+		ptp->pt_entry_checked = true;
+	}
+
+	if (sector + size < sector) {
+		TEGRA_PT_PARSE_ERR(ptp, "size: [%s] integer overflow sector=%llu size=%llu\n",
+				   name[0], sector, size);
+		return false;
+	}
+
+	/* validate allocation_policy=sequential (absolute unsupported) */
+	if (p != prev && sect_end > sector) {
+		TEGRA_PT_PARSE_ERR(ptp, "allocation_policy: [%s] end=%llu [%s] sector=%llu size=%llu\n",
+				   name[1], sect_end, name[0], sector, size);
+		return false;
+	}
+
+	if (ptp->dev_instance != p->mount_info.device_instance) {
+		TEGRA_PT_PARSE_ERR(ptp, "device_instance: [%s] device_instance=%u|%u\n",
+				   name[0], ptp->dev_instance,
+				   p->mount_info.device_instance);
+		return false;
+	}
+
+	if (ptp->dev_id != p->mount_info.device_id) {
+		TEGRA_PT_PARSE_ERR(ptp, "device_id: [%s] device_id=%u|%u\n",
+				   name[0], ptp->dev_id,
+				   p->mount_info.device_id);
+		return false;
+	}
+
+	if (p->partition_id > 127) {
+		TEGRA_PT_PARSE_ERR(ptp, "partition_id: [%s] partition_id=%u\n",
+				   name[0], p->partition_id);
+		return false;
+	}
+
+	sect_end = get_capacity(ptp->state->bdev->bd_disk);
+
+	/* eMMC boot partitions are below ptp->boot_offset */
+	if (sector < ptp->boot_offset) {
+		sect_end += ptp->boot_offset;
+		type = "boot";
+	} else {
+		sector -= ptp->boot_offset;
+		type = "main";
+	}
+
+	/* validate size */
+	if (!size || sector + size > sect_end) {
+		TEGRA_PT_PARSE_ERR(ptp, "size: [%s] %s partition boot_offt=%d end=%llu sector=%llu size=%llu\n",
+				   name[0], type, ptp->boot_offset, sect_end,
+				   sector, size);
+		return false;
+	}
+
+	return true;
+}
+
+static bool tegra_partitions_parse(struct tegra_partition_table_parser *ptp,
+				   bool check_only)
+{
+	struct parsed_partitions *state = ptp->state;
+	struct tegra_partition_table *pt = ptp->pt;
+	sector_t sector, size;
+	int i, slot = 1;
+
+	ptp->pt_entry_checked = false;
+
+	for (i = 0; i < pt->secure.num_partitions; i++) {
+		struct tegra_partition *p = &pt->partitions[i];
+		struct tegra_partition *prev = &pt->partitions[max(i - 1, 0)];
+		struct tegra_partition_info *pi = &p->part_info;
+
+		if (slot == state->limit && !check_only)
+			break;
+
+		sector = TEGRA_PT_SECTOR(pi->logical_sector_address);
+		size   = TEGRA_PT_SECTOR(pi->logical_sectors_num);
+
+		if (!tegra_partition_valid(ptp, p, prev, sector, size))
+			return false;
+
+		if (check_only ||
+		    tegra_partition_skip(p, ptp, sector))
+			continue;
+
+		put_partition(state, slot++, sector - ptp->boot_offset, size);
+	}
+
+	if (!ptp->pt_entry_checked) {
+		TEGRA_PT_PARSE_ERR(ptp, "PT: table entry not found\n");
+		return false;
+	}
+
+	return true;
+}
+
+static bool
+tegra_partition_table_parsed(struct tegra_partition_table_parser *ptp)
+{
+	if (ptp->pt->secure.num_partitions == 0 ||
+	    ptp->pt->secure.num_partitions > TEGRA_PT_MAX_PARTITIONS) {
+		TEGRA_PT_PARSE_ERR(ptp, "num_partitions=%u\n",
+				   ptp->pt->secure.num_partitions);
+		return false;
+	}
+
+	return tegra_partitions_parse(ptp, true) &&
+	       tegra_partitions_parse(ptp, false);
+}
+
+static int
+tegra_partition_table_insec_hdr_valid(struct tegra_partition_table_parser *ptp)
+{
+	if (ptp->pt->insecure.magic   != TEGRA_PT_MAGIC ||
+	    ptp->pt->insecure.version != TEGRA_PT_VERSION) {
+		TEGRA_PT_PARSE_ERR(ptp, "insecure header: magic=0x%llx ver=0x%x\n",
+				   ptp->pt->insecure.magic,
+				   ptp->pt->insecure.version);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+tegra_partition_table_sec_hdr_valid(struct tegra_partition_table_parser *ptp)
+{
+	size_t pt_size = ptp->pt->secure.num_partitions;
+
+	pt_size *= sizeof(ptp->pt->partitions[0]);
+	pt_size += TEGRA_PT_HEADER_SZ;
+
+	if (ptp->pt->secure.magic   != TEGRA_PT_MAGIC ||
+	    ptp->pt->secure.version != TEGRA_PT_VERSION ||
+	    ptp->pt->secure.length  != ptp->pt->insecure.length ||
+	    ptp->pt->secure.length  < pt_size) {
+		TEGRA_PT_PARSE_ERR(ptp, "secure header: magic=0x%llx ver=0x%x length=%u|%u|%zu\n",
+				   ptp->pt->secure.magic,
+				   ptp->pt->secure.version,
+				   ptp->pt->secure.length,
+				   ptp->pt->insecure.length,
+				   pt_size);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+tegra_partition_table_unencrypted(struct tegra_partition_table_parser *ptp)
+{
+	/* AES IV, all zeros if unencrypted */
+	if (ptp->pt->secure.random_data[0] || ptp->pt->secure.random_data[1] ||
+	    ptp->pt->secure.random_data[2] || ptp->pt->secure.random_data[3]) {
+		pr_err_once("encrypted partition table unsupported\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static const u32 tegra20_sdhci_bases[TEGRA_PT_SDHCI_DEVICE_INSTANCES] = {
+	0xc8000000, 0xc8000200, 0xc8000400, 0xc8000600,
+};
+
+static const u32 tegra30_sdhci_bases[TEGRA_PT_SDHCI_DEVICE_INSTANCES] = {
+	0x78000000, 0x78000200, 0x78000400, 0x78000600,
+};
+
+static const struct of_device_id tegra_sdhci_match[] = {
+	{ .compatible = "nvidia,tegra20-sdhci", .data = tegra20_sdhci_bases, },
+	{ .compatible = "nvidia,tegra30-sdhci", .data = tegra30_sdhci_bases, },
+	{}
+};
+
+static int
+tegra_partition_table_emmc_boot_offset(struct tegra_partition_table_parser *ptp)
+{
+	struct mmc_card *card = mmc_bdev_to_card(ptp->state->bdev);
+	const struct of_device_id *matched;
+	const u32 *sdhci_bases;
+	u32 sdhci_base;
+	unsigned int i;
+	int err;
+
+	/* filter out unexpected/untested boot sources */
+	if (!card || card->ext_csd.rev < 3 ||
+	    !mmc_card_is_blockaddr(card) ||
+	     mmc_card_is_removable(card->host))
+		return -1;
+
+	/* skip everything unrelated to Tegra eMMC */
+	matched = of_match_node(tegra_sdhci_match, card->host->parent->of_node);
+	if (!matched)
+		return -1;
+
+	sdhci_bases = matched->data;
+
+	/* figure out SDHCI instance ID by the base address */
+	err = of_property_read_u32_index(card->host->parent->of_node,
+					 "reg", 0, &sdhci_base);
+	if (err)
+		return -1;
+
+	for (i = 0; i < TEGRA_PT_SDHCI_DEVICE_INSTANCES; i++) {
+		if (sdhci_base == sdhci_bases[i])
+			break;
+	}
+
+	if (i == TEGRA_PT_SDHCI_DEVICE_INSTANCES)
+		return -1;
+
+	ptp->dev_id       = TEGRA_PT_SDHCI_DEVICE_ID;
+	ptp->dev_instance = i;
+
+	/*
+	 * 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 /
+	       SECTOR_SIZE * MMC_NUM_BOOT_PARTITION;
+}
+
+static int tegra_read_partition_table(struct tegra_partition_table_parser *ptp)
+{
+	union tegra_partition_table_u *ptu = (typeof(ptu))ptp->pt;
+	unsigned int i;
+	Sector sect;
+	void *part;
+
+	for (i = 0; i < ARRAY_SIZE(ptu->pt_parts); i++) {
+		/*
+		 * Partition table takes at maximum 4096 bytes, but
+		 * read_part_sector() guarantees only that SECTOR_SIZE will
+		 * be read at minimum.
+		 */
+		part = read_part_sector(ptp->state, ptp->sector + i, &sect);
+		if (!part) {
+			TEGRA_PT_ERR(ptp, "failed to read sector %llu\n",
+				     ptp->sector + i);
+			return 0;
+		}
+
+		memcpy(ptu->pt_parts[i], part, SECTOR_SIZE);
+		put_dev_sector(sect);
+	}
+
+	return 1;
+}
+
+int tegra_partition(struct parsed_partitions *state)
+{
+	struct tegra_partition_table_parser ptp = { .state = state };
+	sector_t end_sector;
+	int ret = 0;
+
+	if (!soc_is_tegra())
+		return 0;
+
+	ptp.boot_offset = tegra_partition_table_emmc_boot_offset(&ptp);
+	if (ptp.boot_offset < 0)
+		return 0;
+
+	if (tegra_pt_sector_address < ptp.boot_offset) {
+		TEGRA_PT_INFO(&ptp,
+			      "scanning eMMC boot partitions unimplemented\n");
+		return 0;
+	}
+
+	ptp.pt = kmalloc(sizeof(*ptp.pt), GFP_KERNEL);
+	if (!ptp.pt)
+		return 0;
+
+	ptp.sector = tegra_pt_sector_address - ptp.boot_offset;
+	end_sector = ptp.sector + tegra_pt_sectors_num;
+
+	/*
+	 * Partition table is duplicated till the end_sector.
+	 * If first table is corrupted, we will try next.
+	 */
+	while (ptp.sector < end_sector) {
+		ret = tegra_read_partition_table(&ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_insec_hdr_valid(&ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_unencrypted(&ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_sec_hdr_valid(&ptp);
+		if (!ret)
+			goto next_sector;
+
+		ret = tegra_partition_table_parsed(&ptp);
+		if (ret)
+			break;
+next_sector:
+		ptp.sector += TEGRA_PT_SECTOR_SZ;
+	}
+
+	if (ret == 1)
+		strlcat(state->pp_buf, "\n", PAGE_SIZE);
+
+	kfree(ptp.pt);
+
+	return ret;
+}
diff --git a/block/partitions/tegra.h b/block/partitions/tegra.h
new file mode 100644
index 000000000000..f76a84dedfc6
--- /dev/null
+++ b/block/partitions/tegra.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __FS_PART_TEGRA_H__
+#define __FS_PART_TEGRA_H__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#define TEGRA_PT_MAGIC				0xffffffff8f9e8d8bULL
+#define TEGRA_PT_VERSION			0x100
+#define TEGRA_PT_LOGICAL_SECTOR_SIZE		4096
+#define TEGRA_PT_AES_HASH_SIZE			4
+#define TEGRA_PT_NAME_SIZE			4
+
+#define TEGRA_PT_SDHCI_DEVICE_ID		18
+#define TEGRA_PT_SDHCI_DEVICE_INSTANCES		4
+
+#define TEGRA_PT_PART_TYPE_BCT			1
+#define TEGRA_PT_PART_TYPE_EBT			2
+#define TEGRA_PT_PART_TYPE_PT			3
+#define TEGRA_PT_PART_TYPE_GENERIC		6
+#define TEGRA_PT_PART_TYPE_GP1			9
+#define TEGRA_PT_PART_TYPE_GPT			10
+
+#define TEGRA_PT_HEADER_SZ						\
+	(sizeof(struct tegra_partition_header_insecure) +		\
+	 sizeof(struct tegra_partition_header_secure))			\
+
+#define TEGRA_PT_MAX_PARTITIONS						\
+	((TEGRA_PT_LOGICAL_SECTOR_SIZE - TEGRA_PT_HEADER_SZ) /		\
+	 sizeof(struct tegra_partition))
+
+struct tegra_partition_mount_info {
+	u32 device_id;
+	u32 device_instance;
+	u32 device_attr;
+	u8  mount_path[TEGRA_PT_NAME_SIZE];
+	u32 file_system_type;
+	u32 file_system_attr;
+} __packed;
+
+struct tegra_partition_info {
+	u32 partition_attr;
+	u32 __pad1;
+	u64 logical_sector_address;
+	u64 logical_sectors_num;
+	u64 __pad2[2];
+	u32 partition_type;
+	u32 __pad3;
+} __packed;
+
+struct tegra_partition {
+	u32 partition_id;
+	u8  partition_name[TEGRA_PT_NAME_SIZE];
+	struct tegra_partition_mount_info mount_info;
+	struct tegra_partition_info part_info;
+} __packed;
+
+struct tegra_partition_header_insecure {
+	u64 magic;
+	u32 version;
+	u32 length;
+	u32 signature[TEGRA_PT_AES_HASH_SIZE];
+} __packed;
+
+struct tegra_partition_header_secure {
+	u32 random_data[TEGRA_PT_AES_HASH_SIZE];
+	u64 magic;
+	u32 version;
+	u32 length;
+	u32 num_partitions;
+	u32 __pad;
+} __packed;
+
+struct tegra_partition_table {
+	struct tegra_partition_header_insecure insecure;
+	struct tegra_partition_header_secure secure;
+	struct tegra_partition partitions[TEGRA_PT_MAX_PARTITIONS];
+} __packed;
+
+int tegra_partition(struct parsed_partitions *state);
+
+#endif /* __FS_PART_TEGRA_H__ */
diff --git a/include/soc/tegra/bootdata.h b/include/soc/tegra/bootdata.h
new file mode 100644
index 000000000000..7be207cb2519
--- /dev/null
+++ b/include/soc/tegra/bootdata.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_TEGRA_BOOTDATA_H__
+#define __SOC_TEGRA_BOOTDATA_H__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#define TEGRA_BOOTDATA_VERSION_T20	NVBOOT_BOOTDATA_VERSION(0x2, 0x1)
+#define TEGRA_BOOTDATA_VERSION_T30	NVBOOT_BOOTDATA_VERSION(0x3, 0x1)
+
+#define NVBOOT_BOOTDATA_VERSION(a, b)	((((a) & 0xffff) << 16) | \
+					  ((b) & 0xffff))
+#define NVBOOT_CMAC_AES_HASH_LENGTH	4
+
+struct tegra20_boot_info_table {
+	u32 unused_data1[14];
+	u32 bct_size;
+	u32 bct_ptr;
+} __packed;
+
+struct tegra20_boot_config_table {
+	u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 random_aes_blk[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 boot_data_version;
+	u32 unused_data1[712];
+	u32 unused_consumer_data1;
+	u16 partition_table_logical_sector_address;
+	u16 partition_table_num_logical_sectors;
+	u32 unused_consumer_data[294];
+	u32 unused_data[3];
+} __packed;
+
+struct tegra30_boot_config_table {
+	u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 random_aes_blk[NVBOOT_CMAC_AES_HASH_LENGTH];
+	u32 boot_data_version;
+	u32 unused_data1[1016];
+	u32 unused_consumer_data1;
+	u16 partition_table_logical_sector_address;
+	u16 partition_table_num_logical_sectors;
+	u32 unused_consumer_data[502];
+	u32 unused_data[3];
+} __packed;
+
+#endif /* __SOC_TEGRA_BOOTDATA_H__ */
diff --git a/include/soc/tegra/common.h b/include/soc/tegra/common.h
index 98027a76ce3d..744280ecab5f 100644
--- a/include/soc/tegra/common.h
+++ b/include/soc/tegra/common.h
@@ -6,6 +6,15 @@
 #ifndef __SOC_TEGRA_COMMON_H__
 #define __SOC_TEGRA_COMMON_H__
 
+#include <linux/types.h>
+
+#ifdef CONFIG_ARCH_TEGRA
 bool soc_is_tegra(void);
+#else
+static inline bool soc_is_tegra(void)
+{
+	return false;
+}
+#endif
 
 #endif /* __SOC_TEGRA_COMMON_H__ */
diff --git a/include/soc/tegra/partition.h b/include/soc/tegra/partition.h
new file mode 100644
index 000000000000..9a7cbc20dbff
--- /dev/null
+++ b/include/soc/tegra/partition.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_TEGRA_PARTITION_H__
+#define __SOC_TEGRA_PARTITION_H__
+
+#include <linux/types.h>
+
+#ifdef CONFIG_TEGRA_PARTITION
+void tegra_partition_table_setup(sector_t logical_sector_address,
+				 sector_t logical_sectors_num);
+#else
+static inline void tegra_partition_table_setup(sector_t logical_sector_address,
+					       sector_t logical_sectors_num)
+{
+}
+#endif
+
+#endif /* __SOC_TEGRA_PARTITION_H__ */
-- 
2.25.1


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

* [PATCH v2 4/8] mmc: block: Add mmc_bdev_to_part_type() helper
  2020-03-06  2:12 [PATCH v2 0/8] Introduce NVIDIA Tegra Partition Tablex Dmitry Osipenko
                   ` (2 preceding siblings ...)
  2020-03-06  2:12 ` [PATCH v2 3/8] partitions: Introduce NVIDIA Tegra Partition Table Dmitry Osipenko
@ 2020-03-06  2:12 ` Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 5/8] mmc: block: Add mmc_bdev_to_area_type() helper Dmitry Osipenko
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Dmitry Osipenko @ 2020-03-06  2:12 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

NVIDIA Tegra Partition Table parser needs to know eMMC boot partition ID
that is associated with the block device in order to validate and parse
partition table properly. This patch adds new mmc_bdev_to_part_type()
helper which takes block device for the input and returns a corresponding
MMC card partition ID (part_type).

This is needed by tegra-partition parser in order to distinguish boot0
eMMC partition from boot1.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/mmc/core/block.c   | 16 ++++++++++++++++
 include/linux/mmc/blkdev.h |  1 +
 2 files changed, 17 insertions(+)

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 36d84a8e182c..2cee57c7388d 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -321,6 +321,22 @@ struct mmc_card *mmc_bdev_to_card(struct block_device *bdev)
 	return md->queue.card;
 }
 
+int mmc_bdev_to_part_type(struct block_device *bdev)
+{
+	struct mmc_blk_data *md;
+	struct mmc_card *card;
+
+	card = mmc_bdev_to_card(bdev);
+	if (!card)
+		return -EINVAL;
+
+	md = mmc_blk_get(bdev->bd_disk);
+	if (!md)
+		return -EINVAL;
+
+	return md->part_type;
+}
+
 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
index 67608c58de70..24e73ac02b4b 100644
--- a/include/linux/mmc/blkdev.h
+++ b/include/linux/mmc/blkdev.h
@@ -9,5 +9,6 @@ struct block_device;
 struct mmc_card;
 
 struct mmc_card *mmc_bdev_to_card(struct block_device *bdev);
+int mmc_bdev_to_part_type(struct block_device *bdev);
 
 #endif /* LINUX_MMC_BLOCK_DEVICE_H */
-- 
2.25.1


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

* [PATCH v2 5/8] mmc: block: Add mmc_bdev_to_area_type() helper
  2020-03-06  2:12 [PATCH v2 0/8] Introduce NVIDIA Tegra Partition Tablex Dmitry Osipenko
                   ` (3 preceding siblings ...)
  2020-03-06  2:12 ` [PATCH v2 4/8] mmc: block: Add mmc_bdev_to_part_type() helper Dmitry Osipenko
@ 2020-03-06  2:12 ` Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 6/8] mmc: block: Add MMC_QUIRK_RESCAN_MAIN_BLKDEV Dmitry Osipenko
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Dmitry Osipenko @ 2020-03-06  2:12 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

NVIDIA Tegra Partition Table parser needs to know eMMC partition type
in order to validate and parse partition table properly. This patch adds
new mmc_bdev_to_area_type() helper which takes block device for the input
and returns a corresponding MMC card partition type.

This allows tegra-partition parser to distinguish boot eMMC partition from
the main eMMC partition.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/mmc/core/block.c   | 16 ++++++++++++++++
 include/linux/mmc/blkdev.h |  1 +
 2 files changed, 17 insertions(+)

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 2cee57c7388d..ec69b613ee92 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -337,6 +337,22 @@ int mmc_bdev_to_part_type(struct block_device *bdev)
 	return md->part_type;
 }
 
+int mmc_bdev_to_area_type(struct block_device *bdev)
+{
+	struct mmc_blk_data *md;
+	struct mmc_card *card;
+
+	card = mmc_bdev_to_card(bdev);
+	if (!card)
+		return -EINVAL;
+
+	md = mmc_blk_get(bdev->bd_disk);
+	if (!md)
+		return -EINVAL;
+
+	return md->area_type;
+}
+
 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
index 24e73ac02b4b..5fa5ef35ac25 100644
--- a/include/linux/mmc/blkdev.h
+++ b/include/linux/mmc/blkdev.h
@@ -10,5 +10,6 @@ struct mmc_card;
 
 struct mmc_card *mmc_bdev_to_card(struct block_device *bdev);
 int mmc_bdev_to_part_type(struct block_device *bdev);
+int mmc_bdev_to_area_type(struct block_device *bdev);
 
 #endif /* LINUX_MMC_BLOCK_DEVICE_H */
-- 
2.25.1


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

* [PATCH v2 6/8] mmc: block: Add MMC_QUIRK_RESCAN_MAIN_BLKDEV
  2020-03-06  2:12 [PATCH v2 0/8] Introduce NVIDIA Tegra Partition Tablex Dmitry Osipenko
                   ` (4 preceding siblings ...)
  2020-03-06  2:12 ` [PATCH v2 5/8] mmc: block: Add mmc_bdev_to_area_type() helper Dmitry Osipenko
@ 2020-03-06  2:12 ` Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 7/8] mmc: block: Enable partition-table scanning for boot partitions Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 8/8] partitions/tegra: Implement eMMC boot partitions scanning Dmitry Osipenko
  7 siblings, 0 replies; 14+ messages in thread
From: Dmitry Osipenko @ 2020-03-06  2:12 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

NVIDIA Tegra Partition Table location isn't restricted by the main eMMC
partition. This patch introduces new MMC-card quirk which is needed by
some NVIDIA Tegra devices in order to set up partition table if it is
stored on a eMMC boot partition.

The tegra-partition parser will read out FS partition table from the eMMC
boot partition and stash it for the main eMMC partition. In this case
block device of the main eMMC partition needs to be re-scanned in order
to assign the stashed partition table to the main MMC block device by
tegra-partition parser.

This patch adds new MMC card flag that is applied by tegra-partition
parser to the scanned MMC card if partition table is found on a boot
eMMC partition. This flag tells MMC_BLOCK core that main MMC partition
needs to be re-scanned once all block devices of the MMC card are
instantiated.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/mmc/core/block.c | 31 +++++++++++++++++++++++++++++++
 include/linux/mmc/card.h |  1 +
 2 files changed, 32 insertions(+)

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index ec69b613ee92..2c2bec114fd6 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -2955,6 +2955,27 @@ static void mmc_blk_remove_debugfs(struct mmc_card *card,
 
 #endif /* CONFIG_DEBUG_FS */
 
+static int mmc_blk_rescan_disk(struct mmc_blk_data *md)
+{
+	struct block_device *bdev;
+
+	bdev = blkdev_get_by_dev(disk_devt(md->disk), FMODE_READ | FMODE_EXCL,
+				 md);
+	if (IS_ERR(bdev)) {
+		pr_err("%s: %s: failed to get block device\n",
+		       __func__, md->disk->disk_name);
+		return PTR_ERR(bdev);
+	}
+
+	mutex_lock(&bdev->bd_mutex);
+	bdev_disk_changed(bdev, false);
+	mutex_unlock(&bdev->bd_mutex);
+
+	blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
+
+	return 0;
+}
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
 	struct mmc_blk_data *md, *part_md;
@@ -2998,6 +3019,16 @@ static int mmc_blk_probe(struct mmc_card *card)
 			goto out;
 	}
 
+	/*
+	 * Quirk for NVIDIA Tegra devices that store FS partition table
+	 * on a boot partition.  Tegra-partition scanner found partition
+	 * table on a boot MMC partition and stashed it for the main MMC
+	 * partition if MMC_QUIRK_RESCAN_MAIN_BLKDEV is set, and thus,
+	 * the main partition needs to be re-scanned.
+	 */
+	if (card->quirks & MMC_QUIRK_RESCAN_MAIN_BLKDEV)
+		mmc_blk_rescan_disk(md);
+
 	/* Add two debugfs entries */
 	mmc_blk_add_debugfs(card, md);
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 90b1d83ce675..550d50e57cc4 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -270,6 +270,7 @@ struct mmc_card {
 #define MMC_QUIRK_BROKEN_IRQ_POLLING	(1<<11)	/* Polling SDIO_CCCR_INTx could create a fake interrupt */
 #define MMC_QUIRK_TRIM_BROKEN	(1<<12)		/* Skip trim */
 #define MMC_QUIRK_BROKEN_HPI	(1<<13)		/* Disable broken HPI support */
+#define MMC_QUIRK_RESCAN_MAIN_BLKDEV	(1<<14)	/* Main partition needs to be re-scanned after instantiating all partitions */
 
 	bool			reenable_cmdq;	/* Re-enable Command Queue */
 
-- 
2.25.1


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

* [PATCH v2 7/8] mmc: block: Enable partition-table scanning for boot partitions
  2020-03-06  2:12 [PATCH v2 0/8] Introduce NVIDIA Tegra Partition Tablex Dmitry Osipenko
                   ` (5 preceding siblings ...)
  2020-03-06  2:12 ` [PATCH v2 6/8] mmc: block: Add MMC_QUIRK_RESCAN_MAIN_BLKDEV Dmitry Osipenko
@ 2020-03-06  2:12 ` Dmitry Osipenko
  2020-03-06  2:12 ` [PATCH v2 8/8] partitions/tegra: Implement eMMC boot partitions scanning Dmitry Osipenko
  7 siblings, 0 replies; 14+ messages in thread
From: Dmitry Osipenko @ 2020-03-06  2:12 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

Some NVIDIA Tegra devices store partition table on a boot eMMC partition,
and thus, boot partitions need to be scanned. This patch enables scanning
of the boot MMC partitions. Please note that boot partitions will be
scanned-only, i.e. the scanned boot partitions will be kept hidden.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/mmc/core/block.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 2c2bec114fd6..b834c830e19a 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -2410,9 +2410,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
 	md->parent = parent;
 	set_disk_ro(md->disk, md->read_only || default_ro);
 	md->disk->flags = GENHD_FL_EXT_DEVT;
+
 	if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
-		md->disk->flags |= GENHD_FL_NO_PART_SCAN
-				   | GENHD_FL_SUPPRESS_PARTITION_INFO;
+		md->disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
+
+	if (area_type & MMC_BLK_DATA_AREA_RPMB)
+		md->disk->flags |= GENHD_FL_NO_PART_SCAN;
 
 	/*
 	 * As discussed on lkml, GENHD_FL_REMOVABLE should:
-- 
2.25.1


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

* [PATCH v2 8/8] partitions/tegra: Implement eMMC boot partitions scanning
  2020-03-06  2:12 [PATCH v2 0/8] Introduce NVIDIA Tegra Partition Tablex Dmitry Osipenko
                   ` (6 preceding siblings ...)
  2020-03-06  2:12 ` [PATCH v2 7/8] mmc: block: Enable partition-table scanning for boot partitions Dmitry Osipenko
@ 2020-03-06  2:12 ` Dmitry Osipenko
  2020-03-06 11:00   ` kbuild test robot
  2020-03-09  5:56   ` kbuild test robot
  7 siblings, 2 replies; 14+ messages in thread
From: Dmitry Osipenko @ 2020-03-06  2:12 UTC (permalink / raw)
  To: Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

Some NVIDIA Tegra devices store partition table on eMMC boot partition.
In order to support this case, the tegra-partition parser will read out
partition table from a boot partition and stash it for the main eMMC
partition.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 block/partitions/tegra.c | 122 +++++++++++++++++++++++++++++++++++----
 1 file changed, 110 insertions(+), 12 deletions(-)

diff --git a/block/partitions/tegra.c b/block/partitions/tegra.c
index 6f150a7e3275..153928eef60b 100644
--- a/block/partitions/tegra.c
+++ b/block/partitions/tegra.c
@@ -25,6 +25,7 @@
 #include <linux/mmc/blkdev.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
 
 #include <soc/tegra/common.h>
 #include <soc/tegra/partition.h>
@@ -50,7 +51,10 @@
 struct tegra_partition_table_parser {
 	struct tegra_partition_table *pt;
 	struct parsed_partitions *state;
+	struct mmc_card *card;
 	bool pt_entry_checked;
+	unsigned int boot_id;
+	bool snapshot_mode;
 	sector_t sector;
 	int boot_offset;
 	u32 dev_instance;
@@ -67,6 +71,7 @@ struct tegra_partition_type {
 	char *name;
 };
 
+static struct tegra_partition_table *scratch_pt;
 static sector_t tegra_pt_sector_address;
 static sector_t tegra_pt_sectors_num;
 
@@ -224,6 +229,10 @@ static bool tegra_partition_valid(struct tegra_partition_table_parser *ptp,
 		return false;
 	}
 
+	/* size will be validated when ptp->snapshot_mode=false */
+	if (ptp->snapshot_mode && size)
+		return true;
+
 	sect_end = get_capacity(ptp->state->bdev->bd_disk);
 
 	/* eMMC boot partitions are below ptp->boot_offset */
@@ -369,6 +378,7 @@ tegra_partition_table_emmc_boot_offset(struct tegra_partition_table_parser *ptp)
 {
 	struct mmc_card *card = mmc_bdev_to_card(ptp->state->bdev);
 	const struct of_device_id *matched;
+	int part_type, area_type;
 	const u32 *sdhci_bases;
 	u32 sdhci_base;
 	unsigned int i;
@@ -404,6 +414,32 @@ tegra_partition_table_emmc_boot_offset(struct tegra_partition_table_parser *ptp)
 	ptp->dev_id       = TEGRA_PT_SDHCI_DEVICE_ID;
 	ptp->dev_instance = i;
 
+	area_type = mmc_bdev_to_area_type(ptp->state->bdev);
+
+	if (WARN_ON(area_type < 0))
+		return -1;
+
+	switch (area_type) {
+	case MMC_BLK_DATA_AREA_BOOT:
+		part_type = mmc_bdev_to_part_type(ptp->state->bdev);
+
+		if (WARN_ON(part_type < 0))
+			return -1;
+
+		ptp->boot_id = part_type - EXT_CSD_PART_CONFIG_ACC_BOOT0;
+		ptp->snapshot_mode = true;
+		break;
+
+	case MMC_BLK_DATA_AREA_MAIN:
+		break;
+
+	default:
+		TEGRA_PT_ERR(ptp, "unexpected area_type: %u\n", area_type);
+		return -1;
+	}
+
+	ptp->card = card;
+
 	/*
 	 * eMMC storage has two special boot partitions in addition to the
 	 * main one.  NVIDIA's bootloader linearizes eMMC boot0->boot1->main
@@ -427,6 +463,9 @@ static int tegra_read_partition_table(struct tegra_partition_table_parser *ptp)
 	Sector sect;
 	void *part;
 
+	if (scratch_pt)
+		return 1;
+
 	for (i = 0; i < ARRAY_SIZE(ptu->pt_parts); i++) {
 		/*
 		 * Partition table takes at maximum 4096 bytes, but
@@ -449,29 +488,77 @@ static int tegra_read_partition_table(struct tegra_partition_table_parser *ptp)
 
 int tegra_partition(struct parsed_partitions *state)
 {
-	struct tegra_partition_table_parser ptp = { .state = state };
+	struct tegra_partition_table_parser ptp = { 0 };
 	sector_t end_sector;
 	int ret = 0;
 
 	if (!soc_is_tegra())
 		return 0;
 
+	ptp.state = state;
+
 	ptp.boot_offset = tegra_partition_table_emmc_boot_offset(&ptp);
 	if (ptp.boot_offset < 0)
 		return 0;
 
-	if (tegra_pt_sector_address < ptp.boot_offset) {
-		TEGRA_PT_INFO(&ptp,
-			      "scanning eMMC boot partitions unimplemented\n");
-		return 0;
-	}
+	/*
+	 * Some devices store partition table on boot MMC partition.
+	 * In this case a "snapshot mode" will be used, which will
+	 * only read->check->store partition table, the stored table
+	 * will be used for the main MMC partition later on.
+	 */
+	if (ptp.snapshot_mode) {
+		sector_t boot_start, boot_end, boot_size;
 
-	ptp.pt = kmalloc(sizeof(*ptp.pt), GFP_KERNEL);
-	if (!ptp.pt)
-		return 0;
+		/* partition is already snapshoted, no need to proceed */
+		if (scratch_pt)
+			return 0;
+
+		boot_size  = ptp.boot_offset / MMC_NUM_BOOT_PARTITION;
+		boot_start = ptp.boot_id * boot_size;
+		boot_end   = boot_start + boot_size;
+
+		/*
+		 * Bail out if partition table isn't located here, at this MMC
+		 * partition.
+		 */
+		if (tegra_pt_sector_address < boot_start ||
+		    tegra_pt_sector_address >= boot_end)
+			return 0;
+
+		ptp.boot_offset = boot_start;
+
+		/*
+		 * Note that mmc_blk_probe() always registers boot partitions
+		 * after the main and we rely on this feature, otherwise
+		 * scratch_pt won't be released (although this is not a big
+		 * deal).
+		 */
+		ptp.pt = kmalloc(sizeof(*ptp.pt), GFP_KERNEL);
+		if (!ptp.pt)
+			return 0;
+
+		ptp.sector = tegra_pt_sector_address - ptp.boot_offset;
+		end_sector = ptp.sector + tegra_pt_sectors_num;
 
-	ptp.sector = tegra_pt_sector_address - ptp.boot_offset;
-	end_sector = ptp.sector + tegra_pt_sectors_num;
+	} else if (scratch_pt) {
+		TEGRA_PT_INFO(&ptp, "using stashed partition table\n");
+
+		ptp.pt     = scratch_pt;
+		ptp.sector = 0;
+		end_sector = 1;
+
+	} else {
+		if (tegra_pt_sector_address < ptp.boot_offset)
+			return 0;
+
+		ptp.pt = kmalloc(sizeof(*ptp.pt), GFP_KERNEL);
+		if (!ptp.pt)
+			return 0;
+
+		ptp.sector = tegra_pt_sector_address - ptp.boot_offset;
+		end_sector = ptp.sector + tegra_pt_sectors_num;
+	}
 
 	/*
 	 * Partition table is duplicated till the end_sector.
@@ -501,9 +588,20 @@ int tegra_partition(struct parsed_partitions *state)
 		ptp.sector += TEGRA_PT_SECTOR_SZ;
 	}
 
-	if (ret == 1)
+	if (ret == 1) {
+		if (ptp.snapshot_mode) {
+			ptp.card->quirks |= MMC_QUIRK_RESCAN_MAIN_BLKDEV;
+			scratch_pt = ptp.pt;
+
+			TEGRA_PT_INFO(&ptp, "stashed partition table\n");
+
+			return 0;
+		}
+
 		strlcat(state->pp_buf, "\n", PAGE_SIZE);
+	}
 
+	scratch_pt = NULL;
 	kfree(ptp.pt);
 
 	return ret;
-- 
2.25.1


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

* Re: [PATCH v2 3/8] partitions: Introduce NVIDIA Tegra Partition Table
  2020-03-06  2:12 ` [PATCH v2 3/8] partitions: Introduce NVIDIA Tegra Partition Table Dmitry Osipenko
@ 2020-03-06  2:22   ` Randy Dunlap
  2020-03-06  2:30     ` Dmitry Osipenko
  2020-03-08 23:30   ` kbuild test robot
  1 sibling, 1 reply; 14+ messages in thread
From: Randy Dunlap @ 2020-03-06  2:22 UTC (permalink / raw)
  To: Dmitry Osipenko, Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

On 3/5/20 6:12 PM, Dmitry Osipenko wrote:
> All NVIDIA Tegra devices use a special partition table format for the
> internal storage partitioning. Most of Tegra devices have GPT partition
> in addition to TegraPT, but some older Android consumer-grade devices do
> not or GPT is placed in a wrong sector, and thus, the TegraPT is needed
> in order to support these devices properly in the upstream kernel. This
> patch adds support for NVIDIA Tegra Partition Table format that is used
> at least by all NVIDIA Tegra20 and Tegra30 devices.
> 
> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> ---
>  arch/arm/mach-tegra/tegra.c   |  54 ++++
>  block/partitions/Kconfig      |   9 +
>  block/partitions/Makefile     |   1 +
>  block/partitions/check.c      |   4 +
>  block/partitions/tegra.c      | 510 ++++++++++++++++++++++++++++++++++
>  block/partitions/tegra.h      |  83 ++++++
>  include/soc/tegra/bootdata.h  |  46 +++
>  include/soc/tegra/common.h    |   9 +
>  include/soc/tegra/partition.h |  18 ++
>  9 files changed, 734 insertions(+)
>  create mode 100644 block/partitions/tegra.c
>  create mode 100644 block/partitions/tegra.h
>  create mode 100644 include/soc/tegra/bootdata.h
>  create mode 100644 include/soc/tegra/partition.h

Hi Dmitry,


> diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
> index 702689a628f0..d3c5c6ad6d58 100644
> --- a/block/partitions/Kconfig
> +++ b/block/partitions/Kconfig
> @@ -268,3 +268,12 @@ 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 ARCH_TEGRA || COMPILE_TEST
> +	select MMC_BLOCK

You shouldn't select MMC_BLOCK unless MMC is already enabled,
so this entire config should depend on MMC also.
As is, without MMC set/enabled, it should give you a kconfig warning.

(no, you should not also select MMC here.)

(This is just based on reading the patch--I haven't tested it
with CONFIG_MMC not set/enabled.  Have you?)


> +	help
> +	  Say Y here if you would like to be able to read the hard disk
> +	  partition table format used by NVIDIA Tegra machines.

Thanks.
-- 
~Randy


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

* Re: [PATCH v2 3/8] partitions: Introduce NVIDIA Tegra Partition Table
  2020-03-06  2:22   ` Randy Dunlap
@ 2020-03-06  2:30     ` Dmitry Osipenko
  0 siblings, 0 replies; 14+ messages in thread
From: Dmitry Osipenko @ 2020-03-06  2:30 UTC (permalink / raw)
  To: Randy Dunlap, Jens Axboe, Thierry Reding, Jonathan Hunter,
	Michał Mirosław, David Heidelberg, Peter Geis,
	Stephen Warren, Nicolas Chauvet, Ulf Hansson, Adrian Hunter,
	Billy Laws
  Cc: linux-tegra, linux-block, Andrey Danin, Gilles Grandou,
	Ryan Grachek, linux-mmc, linux-kernel

06.03.2020 05:22, Randy Dunlap пишет:
> On 3/5/20 6:12 PM, Dmitry Osipenko wrote:
>> All NVIDIA Tegra devices use a special partition table format for the
>> internal storage partitioning. Most of Tegra devices have GPT partition
>> in addition to TegraPT, but some older Android consumer-grade devices do
>> not or GPT is placed in a wrong sector, and thus, the TegraPT is needed
>> in order to support these devices properly in the upstream kernel. This
>> patch adds support for NVIDIA Tegra Partition Table format that is used
>> at least by all NVIDIA Tegra20 and Tegra30 devices.
>>
>> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
>> ---
>>  arch/arm/mach-tegra/tegra.c   |  54 ++++
>>  block/partitions/Kconfig      |   9 +
>>  block/partitions/Makefile     |   1 +
>>  block/partitions/check.c      |   4 +
>>  block/partitions/tegra.c      | 510 ++++++++++++++++++++++++++++++++++
>>  block/partitions/tegra.h      |  83 ++++++
>>  include/soc/tegra/bootdata.h  |  46 +++
>>  include/soc/tegra/common.h    |   9 +
>>  include/soc/tegra/partition.h |  18 ++
>>  9 files changed, 734 insertions(+)
>>  create mode 100644 block/partitions/tegra.c
>>  create mode 100644 block/partitions/tegra.h
>>  create mode 100644 include/soc/tegra/bootdata.h
>>  create mode 100644 include/soc/tegra/partition.h
> 
> Hi Dmitry,
> 
> 
>> diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
>> index 702689a628f0..d3c5c6ad6d58 100644
>> --- a/block/partitions/Kconfig
>> +++ b/block/partitions/Kconfig
>> @@ -268,3 +268,12 @@ 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 ARCH_TEGRA || COMPILE_TEST
>> +	select MMC_BLOCK
> 
> You shouldn't select MMC_BLOCK unless MMC is already enabled,
> so this entire config should depend on MMC also.
> As is, without MMC set/enabled, it should give you a kconfig warning.
> 
> (no, you should not also select MMC here.)
> 
> (This is just based on reading the patch--I haven't tested it
> with CONFIG_MMC not set/enabled.  Have you?)

Hello Randy,

I haven't tested it with the disabled CONFIG_MMC, that's a good
suggestion. I'll take it into account in a v3, thank you.

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

* Re: [PATCH v2 8/8] partitions/tegra: Implement eMMC boot partitions scanning
  2020-03-06  2:12 ` [PATCH v2 8/8] partitions/tegra: Implement eMMC boot partitions scanning Dmitry Osipenko
@ 2020-03-06 11:00   ` kbuild test robot
  2020-03-09  5:56   ` kbuild test robot
  1 sibling, 0 replies; 14+ messages in thread
From: kbuild test robot @ 2020-03-06 11:00 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: kbuild-all, Jens Axboe, linux-tegra, linux-block, Andrey Danin,
	Gilles Grandou, Ryan Grachek, linux-mmc, linux-kernel

Hi Dmitry,

I love your patch! Perhaps something to improve:

[auto build test WARNING on tegra/for-next]
[also build test WARNING on block/for-next linus/master v5.6-rc4 next-20200305]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Dmitry-Osipenko/Introduce-NVIDIA-Tegra-Partition-Tablex/20200306-124106
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.1-174-g094d5a94-dirty
        make ARCH=x86_64 allmodconfig
        make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)

>> block/partitions/tegra.c:491:53: sparse: sparse: Using plain integer as NULL pointer

vim +491 block/partitions/tegra.c

   488	
   489	int tegra_partition(struct parsed_partitions *state)
   490	{
 > 491		struct tegra_partition_table_parser ptp = { 0 };

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

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

* Re: [PATCH v2 3/8] partitions: Introduce NVIDIA Tegra Partition Table
  2020-03-06  2:12 ` [PATCH v2 3/8] partitions: Introduce NVIDIA Tegra Partition Table Dmitry Osipenko
  2020-03-06  2:22   ` Randy Dunlap
@ 2020-03-08 23:30   ` kbuild test robot
  1 sibling, 0 replies; 14+ messages in thread
From: kbuild test robot @ 2020-03-08 23:30 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: kbuild-all, Jens Axboe, linux-tegra, linux-block, Andrey Danin,
	Gilles Grandou, Ryan Grachek, linux-mmc, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3848 bytes --]

Hi Dmitry,

I love your patch! Yet something to improve:

[auto build test ERROR on tegra/for-next]
[also build test ERROR on block/for-next linus/master v5.6-rc4 next-20200306]
[cannot apply to ulf.hansson-mmc/next]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Dmitry-Osipenko/Introduce-NVIDIA-Tegra-Partition-Tablex/20200306-124106
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next
config: arm64-randconfig-a001-20200308 (attached as .config)
compiler: aarch64-linux-gcc (GCC) 7.5.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.5.0 make.cross ARCH=arm64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   block/partitions/tegra.o: In function `tegra_partition_table_emmc_boot_offset':
>> block/partitions/tegra.c:370: undefined reference to `mmc_bdev_to_card'
   block/partitions/tegra.c:370:(.text+0x66c): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `mmc_bdev_to_card'
>> block/partitions/tegra.c:379: undefined reference to `mmc_card_is_blockaddr'
   block/partitions/tegra.c:379:(.text+0x69c): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `mmc_card_is_blockaddr'

vim +370 block/partitions/tegra.c

   366	
   367	static int
   368	tegra_partition_table_emmc_boot_offset(struct tegra_partition_table_parser *ptp)
   369	{
 > 370		struct mmc_card *card = mmc_bdev_to_card(ptp->state->bdev);
   371		const struct of_device_id *matched;
   372		const u32 *sdhci_bases;
   373		u32 sdhci_base;
   374		unsigned int i;
   375		int err;
   376	
   377		/* filter out unexpected/untested boot sources */
   378		if (!card || card->ext_csd.rev < 3 ||
 > 379		    !mmc_card_is_blockaddr(card) ||
   380		     mmc_card_is_removable(card->host))
   381			return -1;
   382	
   383		/* skip everything unrelated to Tegra eMMC */
   384		matched = of_match_node(tegra_sdhci_match, card->host->parent->of_node);
   385		if (!matched)
   386			return -1;
   387	
   388		sdhci_bases = matched->data;
   389	
   390		/* figure out SDHCI instance ID by the base address */
   391		err = of_property_read_u32_index(card->host->parent->of_node,
   392						 "reg", 0, &sdhci_base);
   393		if (err)
   394			return -1;
   395	
   396		for (i = 0; i < TEGRA_PT_SDHCI_DEVICE_INSTANCES; i++) {
   397			if (sdhci_base == sdhci_bases[i])
   398				break;
   399		}
   400	
   401		if (i == TEGRA_PT_SDHCI_DEVICE_INSTANCES)
   402			return -1;
   403	
   404		ptp->dev_id       = TEGRA_PT_SDHCI_DEVICE_ID;
   405		ptp->dev_instance = i;
   406	
   407		/*
   408		 * eMMC storage has two special boot partitions in addition to the
   409		 * main one.  NVIDIA's bootloader linearizes eMMC boot0->boot1->main
   410		 * accesses, this means that the partition table addresses are shifted
   411		 * by the size of boot partitions.  In accordance with the eMMC
   412		 * specification, the boot partition size is calculated as follows:
   413		 *
   414		 *	boot partition size = 128K byte x BOOT_SIZE_MULT
   415		 *
   416		 * This function returns number of sectors occupied by the both boot
   417		 * partitions.
   418		 */
   419		return card->ext_csd.raw_boot_mult * SZ_128K /
   420		       SECTOR_SIZE * MMC_NUM_BOOT_PARTITION;
   421	}
   422	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 33642 bytes --]

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

* Re: [PATCH v2 8/8] partitions/tegra: Implement eMMC boot partitions scanning
  2020-03-06  2:12 ` [PATCH v2 8/8] partitions/tegra: Implement eMMC boot partitions scanning Dmitry Osipenko
  2020-03-06 11:00   ` kbuild test robot
@ 2020-03-09  5:56   ` kbuild test robot
  1 sibling, 0 replies; 14+ messages in thread
From: kbuild test robot @ 2020-03-09  5:56 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: kbuild-all, Jens Axboe, linux-tegra, linux-block, Andrey Danin,
	Gilles Grandou, Ryan Grachek, linux-mmc, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 5007 bytes --]

Hi Dmitry,

I love your patch! Yet something to improve:

[auto build test ERROR on tegra/for-next]
[also build test ERROR on block/for-next linus/master v5.6-rc5 next-20200306]
[cannot apply to ulf.hansson-mmc/next]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Dmitry-Osipenko/Introduce-NVIDIA-Tegra-Partition-Tablex/20200306-124106
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next
config: arm64-randconfig-a001-20200308 (attached as .config)
compiler: aarch64-linux-gcc (GCC) 7.5.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.5.0 make.cross ARCH=arm64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   block/partitions/tegra.o: In function `tegra_partition_table_emmc_boot_offset':
   block/partitions/tegra.c:379: undefined reference to `mmc_bdev_to_card'
   block/partitions/tegra.c:379:(.text+0x674): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `mmc_bdev_to_card'
   block/partitions/tegra.c:389: undefined reference to `mmc_card_is_blockaddr'
   block/partitions/tegra.c:389:(.text+0x6a4): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `mmc_card_is_blockaddr'
>> block/partitions/tegra.c:424: undefined reference to `mmc_bdev_to_part_type'
   block/partitions/tegra.c:424:(.text+0x748): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `mmc_bdev_to_part_type'
>> block/partitions/tegra.c:417: undefined reference to `mmc_bdev_to_area_type'
   block/partitions/tegra.c:417:(.text+0xbec): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `mmc_bdev_to_area_type'

vim +424 block/partitions/tegra.c

   375	
   376	static int
   377	tegra_partition_table_emmc_boot_offset(struct tegra_partition_table_parser *ptp)
   378	{
   379		struct mmc_card *card = mmc_bdev_to_card(ptp->state->bdev);
   380		const struct of_device_id *matched;
   381		int part_type, area_type;
   382		const u32 *sdhci_bases;
   383		u32 sdhci_base;
   384		unsigned int i;
   385		int err;
   386	
   387		/* filter out unexpected/untested boot sources */
   388		if (!card || card->ext_csd.rev < 3 ||
   389		    !mmc_card_is_blockaddr(card) ||
   390		     mmc_card_is_removable(card->host))
   391			return -1;
   392	
   393		/* skip everything unrelated to Tegra eMMC */
   394		matched = of_match_node(tegra_sdhci_match, card->host->parent->of_node);
   395		if (!matched)
   396			return -1;
   397	
   398		sdhci_bases = matched->data;
   399	
   400		/* figure out SDHCI instance ID by the base address */
   401		err = of_property_read_u32_index(card->host->parent->of_node,
   402						 "reg", 0, &sdhci_base);
   403		if (err)
   404			return -1;
   405	
   406		for (i = 0; i < TEGRA_PT_SDHCI_DEVICE_INSTANCES; i++) {
   407			if (sdhci_base == sdhci_bases[i])
   408				break;
   409		}
   410	
   411		if (i == TEGRA_PT_SDHCI_DEVICE_INSTANCES)
   412			return -1;
   413	
   414		ptp->dev_id       = TEGRA_PT_SDHCI_DEVICE_ID;
   415		ptp->dev_instance = i;
   416	
 > 417		area_type = mmc_bdev_to_area_type(ptp->state->bdev);
   418	
   419		if (WARN_ON(area_type < 0))
   420			return -1;
   421	
   422		switch (area_type) {
   423		case MMC_BLK_DATA_AREA_BOOT:
 > 424			part_type = mmc_bdev_to_part_type(ptp->state->bdev);
   425	
   426			if (WARN_ON(part_type < 0))
   427				return -1;
   428	
   429			ptp->boot_id = part_type - EXT_CSD_PART_CONFIG_ACC_BOOT0;
   430			ptp->snapshot_mode = true;
   431			break;
   432	
   433		case MMC_BLK_DATA_AREA_MAIN:
   434			break;
   435	
   436		default:
   437			TEGRA_PT_ERR(ptp, "unexpected area_type: %u\n", area_type);
   438			return -1;
   439		}
   440	
   441		ptp->card = card;
   442	
   443		/*
   444		 * eMMC storage has two special boot partitions in addition to the
   445		 * main one.  NVIDIA's bootloader linearizes eMMC boot0->boot1->main
   446		 * accesses, this means that the partition table addresses are shifted
   447		 * by the size of boot partitions.  In accordance with the eMMC
   448		 * specification, the boot partition size is calculated as follows:
   449		 *
   450		 *	boot partition size = 128K byte x BOOT_SIZE_MULT
   451		 *
   452		 * This function returns number of sectors occupied by the both boot
   453		 * partitions.
   454		 */
   455		return card->ext_csd.raw_boot_mult * SZ_128K /
   456		       SECTOR_SIZE * MMC_NUM_BOOT_PARTITION;
   457	}
   458	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 33642 bytes --]

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

end of thread, other threads:[~2020-03-09  5:57 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-06  2:12 [PATCH v2 0/8] Introduce NVIDIA Tegra Partition Tablex Dmitry Osipenko
2020-03-06  2:12 ` [PATCH v2 1/8] mmc: core: Add raw_boot_mult field to mmc_ext_csd Dmitry Osipenko
2020-03-06  2:12 ` [PATCH v2 2/8] mmc: block: Add mmc_bdev_to_card() helper Dmitry Osipenko
2020-03-06  2:12 ` [PATCH v2 3/8] partitions: Introduce NVIDIA Tegra Partition Table Dmitry Osipenko
2020-03-06  2:22   ` Randy Dunlap
2020-03-06  2:30     ` Dmitry Osipenko
2020-03-08 23:30   ` kbuild test robot
2020-03-06  2:12 ` [PATCH v2 4/8] mmc: block: Add mmc_bdev_to_part_type() helper Dmitry Osipenko
2020-03-06  2:12 ` [PATCH v2 5/8] mmc: block: Add mmc_bdev_to_area_type() helper Dmitry Osipenko
2020-03-06  2:12 ` [PATCH v2 6/8] mmc: block: Add MMC_QUIRK_RESCAN_MAIN_BLKDEV Dmitry Osipenko
2020-03-06  2:12 ` [PATCH v2 7/8] mmc: block: Enable partition-table scanning for boot partitions Dmitry Osipenko
2020-03-06  2:12 ` [PATCH v2 8/8] partitions/tegra: Implement eMMC boot partitions scanning Dmitry Osipenko
2020-03-06 11:00   ` kbuild test robot
2020-03-09  5:56   ` kbuild test robot

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).