generic: 6.12: update block NVMEM driver

Update block NVMEM driver based on backported OF partition support.

Note the different MMC card DT binding compared to the previous
downstream solution: Instead of having a 'partitions' subnode inside
a 'block' node, the 'partitions' node now resides directly under the
node representing the card.

In order to make references to the 'boot0' or 'boot1' hw partitions
you will have to define 'partitions-boot0' or 'partitions-boot1', and
move the NVMEM layout into a partition (you may, of course, use
'fixed-partitions' for that, and cover the whole device, if needed).

See also https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/mmc/mmc-card.yaml?h=v6.13

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
Daniel Golle 2025-05-07 03:58:17 +01:00
parent 2ce11c911d
commit fa0f130764
14 changed files with 810 additions and 515 deletions

View file

@ -0,0 +1,123 @@
From decc6959a423c8617e87244fd269129fc4e7d0e6 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Mon, 7 Oct 2024 23:36:14 +0100
Subject: [PATCH 1/8] block: allow setting partition of_node
Allow partition parsers to set the Device Tree node for a partition by
introducing of_put_partition() and extending struct parsed_partitions
accordingly.
As the partition information is preallocated independently of the actual
number of partitions the additional pointer takes about 2 kiB of allocated
memory which is worth avoiding in case CONFIG_OF is not set. This is
achieved by only adding the corresponding field to the struct in case
CONFIG_OF is set using #ifdef'ery.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
block/partitions/check.h | 16 +++++++++++++++-
block/partitions/core.c | 14 +++++++++++---
2 files changed, 26 insertions(+), 4 deletions(-)
--- a/block/partitions/check.h
+++ b/block/partitions/check.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/pagemap.h>
#include <linux/blkdev.h>
+#include <linux/of.h>
#include "../blk.h"
/*
@@ -16,6 +17,9 @@ struct parsed_partitions {
int flags;
bool has_info;
struct partition_meta_info info;
+#ifdef CONFIG_OF
+ struct device_node *np;
+#endif
} *parts;
int next;
int limit;
@@ -34,18 +38,28 @@ static inline void put_dev_sector(Sector
}
static inline void
-put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
+of_put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size,
+ struct device_node *np)
{
if (n < p->limit) {
char tmp[1 + BDEVNAME_SIZE + 10 + 1];
p->parts[n].from = from;
p->parts[n].size = size;
+#ifdef CONFIG_OF
+ p->parts[n].np = np;
+#endif
snprintf(tmp, sizeof(tmp), " %s%d", p->name, n);
strlcat(p->pp_buf, tmp, PAGE_SIZE);
}
}
+static inline void
+put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
+{
+ of_put_partition(p, n, from, size, NULL);
+}
+
/* detection routines go here in alphabetical order: */
int adfspart_check_ADFS(struct parsed_partitions *state);
int adfspart_check_CUMANA(struct parsed_partitions *state);
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -9,6 +9,7 @@
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/vmalloc.h>
+#include <linux/device.h>
#include <linux/raid/detect.h>
#include "check.h"
@@ -290,7 +291,8 @@ static const DEVICE_ATTR(whole_disk, 044
*/
static struct block_device *add_partition(struct gendisk *disk, int partno,
sector_t start, sector_t len, int flags,
- struct partition_meta_info *info)
+ struct partition_meta_info *info,
+ struct device_node *np)
{
dev_t devt = MKDEV(0, 0);
struct device *ddev = disk_to_dev(disk);
@@ -339,6 +341,7 @@ static struct block_device *add_partitio
pdev->class = &block_class;
pdev->type = &part_type;
pdev->parent = ddev;
+ device_set_node(pdev, of_fwnode_handle(np));
/* in consecutive minor range? */
if (bdev_partno(bdev) < disk->minors) {
@@ -445,7 +448,7 @@ int bdev_add_partition(struct gendisk *d
}
part = add_partition(disk, partno, start, length,
- ADDPART_FLAG_NONE, NULL);
+ ADDPART_FLAG_NONE, NULL, NULL);
ret = PTR_ERR_OR_ZERO(part);
out:
mutex_unlock(&disk->open_mutex);
@@ -559,8 +562,13 @@ static bool blk_add_partition(struct gen
size = get_capacity(disk) - from;
}
+#ifdef CONFIG_OF
part = add_partition(disk, p, from, size, state->parts[p].flags,
- &state->parts[p].info);
+ &state->parts[p].info, state->parts[p].np);
+#else
+ part = add_partition(disk, p, from, size, state->parts[p].flags,
+ &state->parts[p].info, NULL);
+#endif
if (IS_ERR(part)) {
if (PTR_ERR(part) != -ENXIO) {
printk(KERN_ERR " %s: p%d could not be added: %pe\n",

View file

@ -1,120 +0,0 @@
From 3245921a87154bdfbe7a55d743ea62dd559a8fb0 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:13:09 +0100
Subject: [PATCH 1/9] dt-bindings: block: add basic bindings for block devices
Add bindings for block devices which are used to allow referencing
nvmem bits on them.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
.../bindings/block/block-device.yaml | 22 ++++++++
.../devicetree/bindings/block/partition.yaml | 51 +++++++++++++++++++
.../devicetree/bindings/block/partitions.yaml | 20 ++++++++
3 files changed, 93 insertions(+)
create mode 100644 Documentation/devicetree/bindings/block/block-device.yaml
create mode 100644 Documentation/devicetree/bindings/block/partition.yaml
create mode 100644 Documentation/devicetree/bindings/block/partitions.yaml
--- /dev/null
+++ b/Documentation/devicetree/bindings/block/block-device.yaml
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/block/block-device.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: block storage device
+
+description: |
+ This binding is generic and describes a block-oriented storage device.
+
+maintainers:
+ - Daniel Golle <daniel@makrotopia.org>
+
+properties:
+ partitions:
+ $ref: /schemas/block/partitions.yaml
+
+ nvmem-layout:
+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
+
+unevaluatedProperties: false
--- /dev/null
+++ b/Documentation/devicetree/bindings/block/partition.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/block/partition.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Partition on a block device
+
+description: |
+ This binding describes a partition on a block device.
+ Partitions may be matched by a combination of partition number, name,
+ and UUID.
+
+maintainers:
+ - Daniel Golle <daniel@makrotopia.org>
+
+properties:
+ $nodename:
+ pattern: '^block-partition-.+$'
+
+ partnum:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Matches partition by number if present.
+
+ partname:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ Matches partition by PARTNAME if present.
+
+ partuuid:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ Matches partition by PARTUUID if present.
+
+ nvmem-layout:
+ $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
+ description:
+ This container may reference an NVMEM layout parser.
+
+anyOf:
+ - required:
+ - partnum
+
+ - required:
+ - partname
+
+ - required:
+ - partuuid
+
+unevaluatedProperties: false
--- /dev/null
+++ b/Documentation/devicetree/bindings/block/partitions.yaml
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/block/partitions.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Partitions on block devices
+
+description: |
+ This binding is generic and describes the content of the partitions container
+ node.
+
+maintainers:
+ - Daniel Golle <daniel@makrotopia.org>
+
+patternProperties:
+ "^block-partition-.+$":
+ $ref: partition.yaml
+
+unevaluatedProperties: false

View file

@ -0,0 +1,25 @@
From 5d265996597a6b0d654bbeda1bc3bae197061de7 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Mon, 7 Oct 2024 23:43:32 +0100
Subject: [PATCH 2/8] block: partitions: of: assign Device Tree node to
partition
Assign partition of_node so other drivers are able to identify a
partition by its Device Tree node.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
block/partitions/of.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/block/partitions/of.c
+++ b/block/partitions/of.c
@@ -48,7 +48,7 @@ static void add_of_partition(struct pars
u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE;
u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE;
- put_partition(state, slot, offset, size);
+ of_put_partition(state, slot, offset, size, np);
if (of_property_read_bool(np, "read-only"))
state->parts[slot].flags |= ADDPART_FLAG_READONLY;

View file

@ -1,135 +0,0 @@
From patchwork Tue Jul 30 19:25:59 2024
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
X-Patchwork-Id: 13747816
Date: Tue, 30 Jul 2024 20:25:59 +0100
From: Daniel Golle <daniel@makrotopia.org>
To: Rob Herring <robh@kernel.org>, Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>, Jens Axboe <axboe@kernel.dk>,
Daniel Golle <daniel@makrotopia.org>, Christian Brauner <brauner@kernel.org>,
Al Viro <viro@zeniv.linux.org.uk>, Li Lingfeng <lilingfeng3@huawei.com>,
Ming Lei <ming.lei@redhat.com>, Christian Heusel <christian@heusel.eu>,
=?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= <rafal@milecki.pl>,
Felix Fietkau <nbd@nbd.name>, John Crispin <john@phrozen.org>,
Chad Monroe <chad.monroe@adtran.com>, Yangyu Chen <cyy@cyyself.name>,
Tianling Shen <cnsztl@immortalwrt.org>, Chuanhong Guo <gch981213@gmail.com>,
Chen Minqiang <ptpt52@gmail.com>, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-block@vger.kernel.org
Subject: [PATCH v5 2/4] block: partitions: populate fwnode
Message-ID:
<3051ac090ad3b3e2f5adb6b67c923261ead729a5.1722365899.git.daniel@makrotopia.org>
References: <cover.1722365899.git.daniel@makrotopia.org>
Precedence: bulk
X-Mailing-List: linux-block@vger.kernel.org
List-Id: <linux-block.vger.kernel.org>
List-Subscribe: <mailto:linux-block+subscribe@vger.kernel.org>
List-Unsubscribe: <mailto:linux-block+unsubscribe@vger.kernel.org>
MIME-Version: 1.0
Content-Disposition: inline
In-Reply-To: <cover.1722365899.git.daniel@makrotopia.org>
Assign matching firmware nodes to block partitions in order to allow
them to be referenced e.g. as NVMEM providers.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
block/partitions/core.c | 72 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -10,6 +10,8 @@
#include <linux/ctype.h>
#include <linux/vmalloc.h>
#include <linux/raid/detect.h>
+#include <linux/property.h>
+
#include "check.h"
static int (*const check_part[])(struct parsed_partitions *) = {
@@ -284,6 +286,74 @@ static ssize_t whole_disk_show(struct de
}
static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL);
+static bool part_meta_match(const char *attr, const char *member, size_t length)
+{
+ /* check if length of attr exceeds specified maximum length */
+ if (strnlen(attr, length) == length)
+ return false;
+
+ /* return true if strings match */
+ return !strncmp(attr, member, length);
+}
+
+static struct fwnode_handle *find_partition_fwnode(struct block_device *bdev)
+{
+ struct fwnode_handle *fw_parts, *fw_part;
+ struct device *ddev = disk_to_dev(bdev->bd_disk);
+ const char *partname, *uuid;
+ u32 partno;
+ bool got_uuid, got_partname, got_partno;
+
+ fw_parts = device_get_named_child_node(ddev, "partitions");
+ if (!fw_parts)
+ return NULL;
+
+ fwnode_for_each_child_node(fw_parts, fw_part) {
+ got_uuid = false;
+ got_partname = false;
+ got_partno = false;
+ /*
+ * In case 'uuid' is defined in the partitions firmware node
+ * require partition meta info being present and the specified
+ * uuid to match.
+ */
+ got_uuid = !fwnode_property_read_string(fw_part, "uuid", &uuid);
+ if (got_uuid && (!bdev->bd_meta_info ||
+ !part_meta_match(uuid, bdev->bd_meta_info->uuid,
+ PARTITION_META_INFO_UUIDLTH)))
+ continue;
+
+ /*
+ * In case 'partname' is defined in the partitions firmware node
+ * require partition meta info being present and the specified
+ * volname to match.
+ */
+ got_partname = !fwnode_property_read_string(fw_part, "partname",
+ &partname);
+ if (got_partname && (!bdev->bd_meta_info ||
+ !part_meta_match(partname,
+ bdev->bd_meta_info->volname,
+ PARTITION_META_INFO_VOLNAMELTH)))
+ continue;
+
+ /*
+ * In case 'partno' is defined in the partitions firmware node
+ * the specified partno needs to match.
+ */
+ got_partno = !fwnode_property_read_u32(fw_part, "partno", &partno);
+ if (got_partno && bdev_partno(bdev) != partno)
+ continue;
+
+ /* Skip if no matching criteria is present in firmware node */
+ if (!got_uuid && !got_partname && !got_partno)
+ continue;
+
+ return fw_part;
+ }
+
+ return NULL;
+}
+
/*
* Must be called either with open_mutex held, before a disk can be opened or
* after all disk users are gone.
@@ -358,6 +428,8 @@ static struct block_device *add_partitio
goto out_put;
}
+ device_set_node(pdev, find_partition_fwnode(bdev));
+
/* delay uevent until 'holders' subdir is created */
dev_set_uevent_suppress(pdev, 1);
err = device_add(pdev);

View file

@ -0,0 +1,498 @@
From d4e82837c8b86ff2c21fa923271908988bc72faa Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Mon, 7 Oct 2024 23:22:53 +0100
Subject: [PATCH 3/8] partitions/efi: apply Linux code style
Fix (mostly white space related) coding style issues in
block/partitions/efi.c by use of clang-format.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
block/partitions/efi.c | 235 +++++++++++++++++++++--------------------
1 file changed, 121 insertions(+), 114 deletions(-)
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -95,15 +95,13 @@
* the partition tables happens after init too.
*/
static int force_gpt;
-static int __init
-force_gpt_fn(char *str)
+static int __init force_gpt_fn(char *str)
{
force_gpt = 1;
return 1;
}
__setup("gpt", force_gpt_fn);
-
/**
* efi_crc32() - EFI version of crc32 function
* @buf: buffer to calculate crc32 of
@@ -116,8 +114,7 @@ __setup("gpt", force_gpt_fn);
* Note, the EFI Specification, v1.02, has a reference to
* Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
*/
-static inline u32
-efi_crc32(const void *buf, unsigned long len)
+static inline u32 efi_crc32(const void *buf, unsigned long len)
{
return (crc32(~0L, buf, len) ^ ~0L);
}
@@ -134,7 +131,8 @@ efi_crc32(const void *buf, unsigned long
static u64 last_lba(struct gendisk *disk)
{
return div_u64(bdev_nr_bytes(disk->part0),
- queue_logical_block_size(disk->queue)) - 1ULL;
+ queue_logical_block_size(disk->queue)) -
+ 1ULL;
}
static inline int pmbr_part_valid(gpt_mbr_record *part)
@@ -195,7 +193,7 @@ static int is_pmbr_valid(legacy_mbr *mbr
check_hybrid:
for (i = 0; i < 4; i++)
if ((mbr->partition_record[i].os_type !=
- EFI_PMBR_OSTYPE_EFI_GPT) &&
+ EFI_PMBR_OSTYPE_EFI_GPT) &&
(mbr->partition_record[i].os_type != 0x00))
ret = GPT_MBR_HYBRID;
@@ -213,10 +211,11 @@ check_hybrid:
*/
if (ret == GPT_MBR_PROTECTIVE) {
sz = le32_to_cpu(mbr->partition_record[part].size_in_lba);
- if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF)
- pr_debug("GPT: mbr size in lba (%u) different than whole disk (%u).\n",
- sz, min_t(uint32_t,
- total_sectors - 1, 0xFFFFFFFF));
+ if (sz != (uint32_t)total_sectors - 1 && sz != 0xFFFFFFFF)
+ pr_debug(
+ "GPT: mbr size in lba (%u) different than whole disk (%u).\n",
+ sz,
+ min_t(uint32_t, total_sectors - 1, 0xFFFFFFFF));
}
done:
return ret;
@@ -232,15 +231,14 @@ done:
* Description: Reads @count bytes from @state->disk into @buffer.
* Returns number of bytes read on success, 0 on error.
*/
-static size_t read_lba(struct parsed_partitions *state,
- u64 lba, u8 *buffer, size_t count)
+static size_t read_lba(struct parsed_partitions *state, u64 lba, u8 *buffer,
+ size_t count)
{
size_t totalreadcount = 0;
- sector_t n = lba *
- (queue_logical_block_size(state->disk->queue) / 512);
+ sector_t n = lba * (queue_logical_block_size(state->disk->queue) / 512);
if (!buffer || lba > last_lba(state->disk))
- return 0;
+ return 0;
while (count) {
int copied = 512;
@@ -253,7 +251,7 @@ static size_t read_lba(struct parsed_par
memcpy(buffer, data, copied);
put_dev_sector(sect);
buffer += copied;
- totalreadcount +=copied;
+ totalreadcount += copied;
count -= copied;
}
return totalreadcount;
@@ -278,17 +276,17 @@ static gpt_entry *alloc_read_gpt_entries
return NULL;
count = (size_t)le32_to_cpu(gpt->num_partition_entries) *
- le32_to_cpu(gpt->sizeof_partition_entry);
+ le32_to_cpu(gpt->sizeof_partition_entry);
if (!count)
return NULL;
pte = kmalloc(count, GFP_KERNEL);
if (!pte)
return NULL;
- if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba),
- (u8 *) pte, count) < count) {
+ if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba), (u8 *)pte,
+ count) < count) {
kfree(pte);
- pte=NULL;
+ pte = NULL;
return NULL;
}
return pte;
@@ -313,9 +311,9 @@ static gpt_header *alloc_read_gpt_header
if (!gpt)
return NULL;
- if (read_lba(state, lba, (u8 *) gpt, ssz) < ssz) {
+ if (read_lba(state, lba, (u8 *)gpt, ssz) < ssz) {
kfree(gpt);
- gpt=NULL;
+ gpt = NULL;
return NULL;
}
@@ -354,8 +352,9 @@ static int is_gpt_valid(struct parsed_pa
/* Check the GUID Partition Table header size is too big */
if (le32_to_cpu((*gpt)->header_size) >
- queue_logical_block_size(state->disk->queue)) {
- pr_debug("GUID Partition Table Header size is too large: %u > %u\n",
+ queue_logical_block_size(state->disk->queue)) {
+ pr_debug(
+ "GUID Partition Table Header size is too large: %u > %u\n",
le32_to_cpu((*gpt)->header_size),
queue_logical_block_size(state->disk->queue));
goto fail;
@@ -363,16 +362,17 @@ static int is_gpt_valid(struct parsed_pa
/* Check the GUID Partition Table header size is too small */
if (le32_to_cpu((*gpt)->header_size) < sizeof(gpt_header)) {
- pr_debug("GUID Partition Table Header size is too small: %u < %zu\n",
- le32_to_cpu((*gpt)->header_size),
- sizeof(gpt_header));
+ pr_debug(
+ "GUID Partition Table Header size is too small: %u < %zu\n",
+ le32_to_cpu((*gpt)->header_size), sizeof(gpt_header));
goto fail;
}
/* Check the GUID Partition Table CRC */
origcrc = le32_to_cpu((*gpt)->header_crc32);
(*gpt)->header_crc32 = 0;
- crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size));
+ crc = efi_crc32((const unsigned char *)(*gpt),
+ le32_to_cpu((*gpt)->header_size));
if (crc != origcrc) {
pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n",
@@ -396,20 +396,25 @@ static int is_gpt_valid(struct parsed_pa
lastlba = last_lba(state->disk);
if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) {
pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n",
- (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba),
+ (unsigned long long)le64_to_cpu(
+ (*gpt)->first_usable_lba),
(unsigned long long)lastlba);
goto fail;
}
if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) {
pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n",
- (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
+ (unsigned long long)le64_to_cpu(
+ (*gpt)->last_usable_lba),
(unsigned long long)lastlba);
goto fail;
}
- if (le64_to_cpu((*gpt)->last_usable_lba) < le64_to_cpu((*gpt)->first_usable_lba)) {
+ if (le64_to_cpu((*gpt)->last_usable_lba) <
+ le64_to_cpu((*gpt)->first_usable_lba)) {
pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n",
- (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
- (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba));
+ (unsigned long long)le64_to_cpu(
+ (*gpt)->last_usable_lba),
+ (unsigned long long)le64_to_cpu(
+ (*gpt)->first_usable_lba));
goto fail;
}
/* Check that sizeof_partition_entry has the correct value */
@@ -420,10 +425,11 @@ static int is_gpt_valid(struct parsed_pa
/* Sanity check partition table size */
pt_size = (u64)le32_to_cpu((*gpt)->num_partition_entries) *
- le32_to_cpu((*gpt)->sizeof_partition_entry);
+ le32_to_cpu((*gpt)->sizeof_partition_entry);
if (pt_size > KMALLOC_MAX_SIZE) {
- pr_debug("GUID Partition Table is too large: %llu > %lu bytes\n",
- (unsigned long long)pt_size, KMALLOC_MAX_SIZE);
+ pr_debug(
+ "GUID Partition Table is too large: %llu > %lu bytes\n",
+ (unsigned long long)pt_size, KMALLOC_MAX_SIZE);
goto fail;
}
@@ -431,7 +437,7 @@ static int is_gpt_valid(struct parsed_pa
goto fail;
/* Check the GUID Partition Entry Array CRC */
- crc = efi_crc32((const unsigned char *) (*ptes), pt_size);
+ crc = efi_crc32((const unsigned char *)(*ptes), pt_size);
if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
pr_debug("GUID Partition Entry Array CRC check failed.\n");
@@ -441,10 +447,10 @@ static int is_gpt_valid(struct parsed_pa
/* We're done, all's well */
return 1;
- fail_ptes:
+fail_ptes:
kfree(*ptes);
*ptes = NULL;
- fail:
+fail:
kfree(*gpt);
*gpt = NULL;
return 0;
@@ -457,12 +463,11 @@ static int is_gpt_valid(struct parsed_pa
*
* Description: returns 1 if valid, 0 on error.
*/
-static inline int
-is_pte_valid(const gpt_entry *pte, const u64 lastlba)
+static inline int is_pte_valid(const gpt_entry *pte, const u64 lastlba)
{
if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
- le64_to_cpu(pte->starting_lba) > lastlba ||
- le64_to_cpu(pte->ending_lba) > lastlba)
+ le64_to_cpu(pte->starting_lba) > lastlba ||
+ le64_to_cpu(pte->ending_lba) > lastlba)
return 0;
return 1;
}
@@ -477,8 +482,7 @@ is_pte_valid(const gpt_entry *pte, const
* and prints warnings on discrepancies.
*
*/
-static void
-compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
+static void compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
{
int error_found = 0;
if (!pgpt || !agpt)
@@ -486,31 +490,32 @@ compare_gpts(gpt_header *pgpt, gpt_heade
if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
pr_warn("GPT:Primary header LBA != Alt. header alternate_lba\n");
pr_warn("GPT:%lld != %lld\n",
- (unsigned long long)le64_to_cpu(pgpt->my_lba),
- (unsigned long long)le64_to_cpu(agpt->alternate_lba));
+ (unsigned long long)le64_to_cpu(pgpt->my_lba),
+ (unsigned long long)le64_to_cpu(agpt->alternate_lba));
error_found++;
}
if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
pr_warn("GPT:Primary header alternate_lba != Alt. header my_lba\n");
pr_warn("GPT:%lld != %lld\n",
- (unsigned long long)le64_to_cpu(pgpt->alternate_lba),
- (unsigned long long)le64_to_cpu(agpt->my_lba));
+ (unsigned long long)le64_to_cpu(pgpt->alternate_lba),
+ (unsigned long long)le64_to_cpu(agpt->my_lba));
error_found++;
}
if (le64_to_cpu(pgpt->first_usable_lba) !=
- le64_to_cpu(agpt->first_usable_lba)) {
+ le64_to_cpu(agpt->first_usable_lba)) {
pr_warn("GPT:first_usable_lbas don't match.\n");
pr_warn("GPT:%lld != %lld\n",
- (unsigned long long)le64_to_cpu(pgpt->first_usable_lba),
- (unsigned long long)le64_to_cpu(agpt->first_usable_lba));
+ (unsigned long long)le64_to_cpu(pgpt->first_usable_lba),
+ (unsigned long long)le64_to_cpu(
+ agpt->first_usable_lba));
error_found++;
}
if (le64_to_cpu(pgpt->last_usable_lba) !=
- le64_to_cpu(agpt->last_usable_lba)) {
+ le64_to_cpu(agpt->last_usable_lba)) {
pr_warn("GPT:last_usable_lbas don't match.\n");
pr_warn("GPT:%lld != %lld\n",
- (unsigned long long)le64_to_cpu(pgpt->last_usable_lba),
- (unsigned long long)le64_to_cpu(agpt->last_usable_lba));
+ (unsigned long long)le64_to_cpu(pgpt->last_usable_lba),
+ (unsigned long long)le64_to_cpu(agpt->last_usable_lba));
error_found++;
}
if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
@@ -518,27 +523,27 @@ compare_gpts(gpt_header *pgpt, gpt_heade
error_found++;
}
if (le32_to_cpu(pgpt->num_partition_entries) !=
- le32_to_cpu(agpt->num_partition_entries)) {
+ le32_to_cpu(agpt->num_partition_entries)) {
pr_warn("GPT:num_partition_entries don't match: "
- "0x%x != 0x%x\n",
- le32_to_cpu(pgpt->num_partition_entries),
- le32_to_cpu(agpt->num_partition_entries));
+ "0x%x != 0x%x\n",
+ le32_to_cpu(pgpt->num_partition_entries),
+ le32_to_cpu(agpt->num_partition_entries));
error_found++;
}
if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
- le32_to_cpu(agpt->sizeof_partition_entry)) {
+ le32_to_cpu(agpt->sizeof_partition_entry)) {
pr_warn("GPT:sizeof_partition_entry values don't match: "
- "0x%x != 0x%x\n",
- le32_to_cpu(pgpt->sizeof_partition_entry),
- le32_to_cpu(agpt->sizeof_partition_entry));
+ "0x%x != 0x%x\n",
+ le32_to_cpu(pgpt->sizeof_partition_entry),
+ le32_to_cpu(agpt->sizeof_partition_entry));
error_found++;
}
if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
- le32_to_cpu(agpt->partition_entry_array_crc32)) {
+ le32_to_cpu(agpt->partition_entry_array_crc32)) {
pr_warn("GPT:partition_entry_array_crc32 values don't match: "
- "0x%x != 0x%x\n",
- le32_to_cpu(pgpt->partition_entry_array_crc32),
- le32_to_cpu(agpt->partition_entry_array_crc32));
+ "0x%x != 0x%x\n",
+ le32_to_cpu(pgpt->partition_entry_array_crc32),
+ le32_to_cpu(agpt->partition_entry_array_crc32));
error_found++;
}
if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
@@ -594,7 +599,7 @@ static int find_valid_gpt(struct parsed_
return 0;
lastlba = last_lba(state->disk);
- if (!force_gpt) {
+ if (!force_gpt) {
/* This will be added to the EFI Spec. per Intel after v1.02. */
legacymbr = kzalloc(sizeof(*legacymbr), GFP_KERNEL);
if (!legacymbr)
@@ -608,18 +613,17 @@ static int find_valid_gpt(struct parsed_
goto fail;
pr_debug("Device has a %s MBR\n",
- good_pmbr == GPT_MBR_PROTECTIVE ?
- "protective" : "hybrid");
+ good_pmbr == GPT_MBR_PROTECTIVE ? "protective" :
+ "hybrid");
}
- good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA,
- &pgpt, &pptes);
- if (good_pgpt)
- good_agpt = is_gpt_valid(state,
- le64_to_cpu(pgpt->alternate_lba),
- &agpt, &aptes);
- if (!good_agpt && force_gpt)
- good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes);
+ good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt,
+ &pptes);
+ if (good_pgpt)
+ good_agpt = is_gpt_valid(
+ state, le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes);
+ if (!good_agpt && force_gpt)
+ good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes);
if (!good_agpt && force_gpt && fops->alternative_gpt_sector) {
sector_t agpt_sector;
@@ -627,43 +631,42 @@ static int find_valid_gpt(struct parsed_
err = fops->alternative_gpt_sector(disk, &agpt_sector);
if (!err)
- good_agpt = is_gpt_valid(state, agpt_sector,
- &agpt, &aptes);
+ good_agpt =
+ is_gpt_valid(state, agpt_sector, &agpt, &aptes);
}
- /* The obviously unsuccessful case */
- if (!good_pgpt && !good_agpt)
- goto fail;
-
- compare_gpts(pgpt, agpt, lastlba);
-
- /* The good cases */
- if (good_pgpt) {
- *gpt = pgpt;
- *ptes = pptes;
- kfree(agpt);
- kfree(aptes);
+ /* The obviously unsuccessful case */
+ if (!good_pgpt && !good_agpt)
+ goto fail;
+
+ compare_gpts(pgpt, agpt, lastlba);
+
+ /* The good cases */
+ if (good_pgpt) {
+ *gpt = pgpt;
+ *ptes = pptes;
+ kfree(agpt);
+ kfree(aptes);
if (!good_agpt)
- pr_warn("Alternate GPT is invalid, using primary GPT.\n");
- return 1;
- }
- else if (good_agpt) {
- *gpt = agpt;
- *ptes = aptes;
- kfree(pgpt);
- kfree(pptes);
+ pr_warn("Alternate GPT is invalid, using primary GPT.\n");
+ return 1;
+ } else if (good_agpt) {
+ *gpt = agpt;
+ *ptes = aptes;
+ kfree(pgpt);
+ kfree(pptes);
pr_warn("Primary GPT is invalid, using alternate GPT.\n");
- return 1;
- }
+ return 1;
+ }
- fail:
- kfree(pgpt);
- kfree(agpt);
- kfree(pptes);
- kfree(aptes);
- *gpt = NULL;
- *ptes = NULL;
- return 0;
+fail:
+ kfree(pgpt);
+ kfree(agpt);
+ kfree(pptes);
+ kfree(aptes);
+ *gpt = NULL;
+ *ptes = NULL;
+ return 0;
}
/**
@@ -725,7 +728,9 @@ int efi_partition(struct parsed_partitio
pr_debug("GUID Partition Table is valid! Yea!\n");
- for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
+ for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) &&
+ i < state->limit - 1;
+ i++) {
struct partition_meta_info *info;
unsigned label_max;
u64 start = le64_to_cpu(ptes[i].starting_lba);
@@ -735,10 +740,11 @@ int efi_partition(struct parsed_partitio
if (!is_pte_valid(&ptes[i], last_lba(state->disk)))
continue;
- put_partition(state, i+1, start * ssz, size * ssz);
+ put_partition(state, i + 1, start * ssz, size * ssz);
/* If this is a RAID volume, tell md */
- if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_RAID_GUID))
+ if (!efi_guidcmp(ptes[i].partition_type_guid,
+ PARTITION_LINUX_RAID_GUID))
state->parts[i + 1].flags = ADDPART_FLAG_RAID;
info = &state->parts[i + 1].info;
@@ -747,7 +753,8 @@ int efi_partition(struct parsed_partitio
/* Naively convert UTF16-LE to 7 bits. */
label_max = min(ARRAY_SIZE(info->volname) - 1,
ARRAY_SIZE(ptes[i].partition_name));
- utf16_le_to_7bit(ptes[i].partition_name, label_max, info->volname);
+ utf16_le_to_7bit(ptes[i].partition_name, label_max,
+ info->volname);
state->parts[i + 1].has_info = true;
}
kfree(ptes);

View file

@ -1,56 +0,0 @@
From patchwork Tue Jul 30 19:27:07 2024
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
X-Patchwork-Id: 13747818
Date: Tue, 30 Jul 2024 20:27:07 +0100
From: Daniel Golle <daniel@makrotopia.org>
To: Rob Herring <robh@kernel.org>, Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>, Jens Axboe <axboe@kernel.dk>,
Daniel Golle <daniel@makrotopia.org>, Christian Brauner <brauner@kernel.org>,
Al Viro <viro@zeniv.linux.org.uk>, Li Lingfeng <lilingfeng3@huawei.com>,
Ming Lei <ming.lei@redhat.com>, Christian Heusel <christian@heusel.eu>,
=?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= <rafal@milecki.pl>,
Felix Fietkau <nbd@nbd.name>, John Crispin <john@phrozen.org>,
Chad Monroe <chad.monroe@adtran.com>, Yangyu Chen <cyy@cyyself.name>,
Tianling Shen <cnsztl@immortalwrt.org>, Chuanhong Guo <gch981213@gmail.com>,
Chen Minqiang <ptpt52@gmail.com>, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-block@vger.kernel.org
Subject: [PATCH v5 4/4] block: add new genhd flag GENHD_FL_NVMEM
Message-ID:
<311ea569c23ce14e2896cd3b069dc494c58c49c2.1722365899.git.daniel@makrotopia.org>
References: <cover.1722365899.git.daniel@makrotopia.org>
Precedence: bulk
X-Mailing-List: linux-block@vger.kernel.org
List-Id: <linux-block.vger.kernel.org>
List-Subscribe: <mailto:linux-block+subscribe@vger.kernel.org>
List-Unsubscribe: <mailto:linux-block+unsubscribe@vger.kernel.org>
MIME-Version: 1.0
Content-Disposition: inline
In-Reply-To: <cover.1722365899.git.daniel@makrotopia.org>
Add new flag to destinguish block devices which may act as an NVMEM
provider.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
include/linux/blkdev.h | 2 ++
1 file changed, 2 insertions(+)
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -82,11 +82,13 @@ struct partition_meta_info {
* ``GENHD_FL_NO_PART``: partition support is disabled. The kernel will not
* scan for partitions from add_disk, and users can't add partitions manually.
*
+ * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider.
*/
enum {
GENHD_FL_REMOVABLE = 1 << 0,
GENHD_FL_HIDDEN = 1 << 1,
GENHD_FL_NO_PART = 1 << 2,
+ GENHD_FL_NVMEM = 1 << 3,
};
enum {

View file

@ -0,0 +1,75 @@
From f28e36c19b927671d93ccd2b5de3d518fccf721e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Tue, 8 Oct 2024 00:25:12 +0100
Subject: [PATCH 4/8] partitions/efi: allow assigning partition Device Tree
node
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
block/partitions/efi.c | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -86,6 +86,7 @@
#include <linux/crc32.h>
#include <linux/ctype.h>
#include <linux/math64.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include "check.h"
#include "efi.h"
@@ -694,6 +695,34 @@ static void utf16_le_to_7bit(const __le1
}
}
+static struct device_node *find_partition_of_node(struct device_node *partitions_np,
+ gpt_entry *ptes)
+{
+ char volname[64], partuuid[UUID_STRING_LEN + 1];
+ const char *uuid, *name;
+
+ if (!partitions_np ||
+ !of_device_is_compatible(partitions_np, "gpt-partitions"))
+ return NULL;
+
+ efi_guid_to_str(&ptes->unique_partition_guid, partuuid);
+ utf16_le_to_7bit(ptes->partition_name, ARRAY_SIZE(volname) - 1, volname);
+
+ for_each_available_child_of_node_scoped(partitions_np, np) {
+ if (!of_property_read_string(np, "uuid", &uuid) &&
+ strncmp(uuid, partuuid, ARRAY_SIZE(partuuid)))
+ continue;
+
+ if (!of_property_read_string(np, "partname", &name) &&
+ strncmp(name, volname, ARRAY_SIZE(volname)))
+ continue;
+
+ return np;
+ }
+
+ return NULL;
+}
+
/**
* efi_partition - scan for GPT partitions
* @state: disk parsed partitions
@@ -719,6 +748,8 @@ int efi_partition(struct parsed_partitio
gpt_entry *ptes = NULL;
u32 i;
unsigned ssz = queue_logical_block_size(state->disk->queue) / 512;
+ struct device *ddev = disk_to_dev(state->disk);
+ struct device_node *partitions_np = of_node_get(ddev->of_node);
if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) {
kfree(gpt);
@@ -740,7 +771,8 @@ int efi_partition(struct parsed_partitio
if (!is_pte_valid(&ptes[i], last_lba(state->disk)))
continue;
- put_partition(state, i + 1, start * ssz, size * ssz);
+ of_put_partition(state, i + 1, start * ssz, size * ssz,
+ find_partition_of_node(partitions_np, &ptes[i]));
/* If this is a RAID volume, tell md */
if (!efi_guidcmp(ptes[i].partition_type_guid,

View file

@ -1,34 +1,7 @@
From patchwork Tue Jul 30 19:26:42 2024 From 858df9db80c1568db255659baca7602504f823af Mon Sep 17 00:00:00 2001
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
X-Patchwork-Id: 13747817
Date: Tue, 30 Jul 2024 20:26:42 +0100
From: Daniel Golle <daniel@makrotopia.org> From: Daniel Golle <daniel@makrotopia.org>
To: Rob Herring <robh@kernel.org>, Krzysztof Kozlowski <krzk+dt@kernel.org>, Date: Wed, 15 May 2024 08:19:51 +0100
Conor Dooley <conor+dt@kernel.org>, Jens Axboe <axboe@kernel.dk>, Subject: [PATCH 5/8] block: add support for notifications
Daniel Golle <daniel@makrotopia.org>, Christian Brauner <brauner@kernel.org>,
Al Viro <viro@zeniv.linux.org.uk>, Li Lingfeng <lilingfeng3@huawei.com>,
Ming Lei <ming.lei@redhat.com>, Christian Heusel <christian@heusel.eu>,
=?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= <rafal@milecki.pl>,
Felix Fietkau <nbd@nbd.name>, John Crispin <john@phrozen.org>,
Chad Monroe <chad.monroe@adtran.com>, Yangyu Chen <cyy@cyyself.name>,
Tianling Shen <cnsztl@immortalwrt.org>, Chuanhong Guo <gch981213@gmail.com>,
Chen Minqiang <ptpt52@gmail.com>, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-block@vger.kernel.org
Subject: [PATCH v5 3/4] block: add support for notifications
Message-ID:
<ca0022886e8f211a323a716653a1396a3bc91653.1722365899.git.daniel@makrotopia.org>
References: <cover.1722365899.git.daniel@makrotopia.org>
Precedence: bulk
X-Mailing-List: linux-block@vger.kernel.org
List-Id: <linux-block.vger.kernel.org>
List-Subscribe: <mailto:linux-block+subscribe@vger.kernel.org>
List-Unsubscribe: <mailto:linux-block+unsubscribe@vger.kernel.org>
MIME-Version: 1.0
Content-Disposition: inline
In-Reply-To: <cover.1722365899.git.daniel@makrotopia.org>
Add notifier block to notify other subsystems about the addition or Add notifier block to notify other subsystems about the addition or
removal of block devices. removal of block devices.
@ -37,9 +10,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- ---
block/Kconfig | 6 +++ block/Kconfig | 6 +++
block/Makefile | 1 + block/Makefile | 1 +
block/blk-notify.c | 87 ++++++++++++++++++++++++++++++++++++++++++ block/blk-notify.c | 107 +++++++++++++++++++++++++++++++++++++++++
include/linux/blkdev.h | 11 ++++++ include/linux/blkdev.h | 8 +++
4 files changed, 105 insertions(+) 4 files changed, 122 insertions(+)
create mode 100644 block/blk-notify.c create mode 100644 block/blk-notify.c
--- a/block/Kconfig --- a/block/Kconfig
@ -66,7 +39,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+obj-$(CONFIG_BLOCK_NOTIFIERS) += blk-notify.o +obj-$(CONFIG_BLOCK_NOTIFIERS) += blk-notify.o
--- /dev/null --- /dev/null
+++ b/block/blk-notify.c +++ b/block/blk-notify.c
@@ -0,0 +1,87 @@ @@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: GPL-2.0-or-later
+/* +/*
+ * Notifiers for addition and removal of block devices + * Notifiers for addition and removal of block devices
@ -77,6 +50,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+#include <linux/list.h> +#include <linux/list.h>
+#include <linux/mutex.h> +#include <linux/mutex.h>
+#include <linux/notifier.h> +#include <linux/notifier.h>
+#include <linux/workqueue.h>
+ +
+#include "blk.h" +#include "blk.h"
+ +
@ -89,6 +63,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+static DEFINE_MUTEX(blk_notifier_lock); +static DEFINE_MUTEX(blk_notifier_lock);
+static LIST_HEAD(blk_devices); +static LIST_HEAD(blk_devices);
+ +
+struct blk_notify_event {
+ struct delayed_work work;
+ struct device *dev;
+};
+
+void blk_register_notify(struct notifier_block *nb) +void blk_register_notify(struct notifier_block *nb)
+{ +{
+ struct blk_device_list *existing_blkdev; + struct blk_device_list *existing_blkdev;
@ -111,19 +90,33 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+} +}
+EXPORT_SYMBOL_GPL(blk_unregister_notify); +EXPORT_SYMBOL_GPL(blk_unregister_notify);
+ +
+static void blk_notify_work(struct work_struct *work)
+{
+ struct blk_notify_event *ev =
+ container_of(work, struct blk_notify_event, work.work);
+
+ raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_ADD, ev->dev);
+ kfree(ev);
+}
+
+static int blk_call_notifier_add(struct device *dev) +static int blk_call_notifier_add(struct device *dev)
+{ +{
+ struct blk_device_list *new_blkdev; + struct blk_device_list *new_blkdev;
+ struct blk_notify_event *ev;
+ +
+ new_blkdev = kmalloc(sizeof (*new_blkdev), GFP_KERNEL); + new_blkdev = kmalloc(sizeof (*new_blkdev), GFP_KERNEL);
+ if (!new_blkdev) + if (!new_blkdev)
+ return -ENOMEM; + return -ENOMEM;
+ +
+ ev = kmalloc(sizeof(*ev), GFP_KERNEL);
+ INIT_DEFERRABLE_WORK(&ev->work, blk_notify_work);
+ ev->dev = dev;
+ new_blkdev->dev = dev; + new_blkdev->dev = dev;
+ mutex_lock(&blk_notifier_lock); + mutex_lock(&blk_notifier_lock);
+ list_add_tail(&new_blkdev->list, &blk_devices); + list_add_tail(&new_blkdev->list, &blk_devices);
+ raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_ADD, dev); + schedule_delayed_work(&ev->work, msecs_to_jiffies(500));
+ mutex_unlock(&blk_notifier_lock); + mutex_unlock(&blk_notifier_lock);
+
+ return 0; + return 0;
+} +}
+ +
@ -156,19 +149,16 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+device_initcall(blk_notifications_init); +device_initcall(blk_notifications_init);
--- a/include/linux/blkdev.h --- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h +++ b/include/linux/blkdev.h
@@ -1696,4 +1696,15 @@ static inline bool bdev_can_atomic_write @@ -1696,4 +1696,12 @@ static inline bool bdev_can_atomic_write
#define DEFINE_IO_COMP_BATCH(name) struct io_comp_batch name = { } #define DEFINE_IO_COMP_BATCH(name) struct io_comp_batch name = { }
+ +
+#ifdef CONFIG_BLOCK_NOTIFIERS
+#define BLK_DEVICE_ADD 1 +#define BLK_DEVICE_ADD 1
+#define BLK_DEVICE_REMOVE 2 +#define BLK_DEVICE_REMOVE 2
+#if defined(CONFIG_BLOCK_NOTIFIERS) +extern void blk_register_notify(struct notifier_block *nb);
+void blk_register_notify(struct notifier_block *nb); +extern void blk_unregister_notify(struct notifier_block *nb);
+void blk_unregister_notify(struct notifier_block *nb);
+#else
+static inline void blk_register_notify(struct notifier_block *nb) { };
+static inline void blk_unregister_notify(struct notifier_block *nb) { };
+#endif +#endif
+ +
#endif /* _LINUX_BLKDEV_H */ #endif /* _LINUX_BLKDEV_H */

View file

@ -0,0 +1,29 @@
From 2b28bf485b283991eea9f00c5831c1c39c73991f Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 21 Mar 2024 19:33:49 +0000
Subject: [PATCH 6/8] block: add new genhd flag GENHD_FL_NVMEM
Add new flag to destinguish block devices which may act as an NVMEM
provider.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
include/linux/blkdev.h | 2 ++
1 file changed, 2 insertions(+)
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -82,11 +82,13 @@ struct partition_meta_info {
* ``GENHD_FL_NO_PART``: partition support is disabled. The kernel will not
* scan for partitions from add_disk, and users can't add partitions manually.
*
+ * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider.
*/
enum {
GENHD_FL_REMOVABLE = 1 << 0,
GENHD_FL_HIDDEN = 1 << 1,
GENHD_FL_NO_PART = 1 << 2,
+ GENHD_FL_NVMEM = 1 << 3,
};
enum {

View file

@ -1,74 +0,0 @@
From f7ec19b34d1b7e934a58ceb102369bbd30b2631d Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:15:11 +0100
Subject: [PATCH 6/9] dt-bindings: mmc: mmc-card: add block device nodes
Add nodes representing the block devices exposed by an MMC device
including an example involving nvmem-cells.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
.../devicetree/bindings/mmc/mmc-card.yaml | 45 +++++++++++++++++++
1 file changed, 45 insertions(+)
--- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
+++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
@@ -26,6 +26,18 @@ properties:
Use this to indicate that the mmc-card has a broken hpi
implementation, and that hpi should not be used.
+ block:
+ $ref: /schemas/block/block-device.yaml#
+ description:
+ Represents the block storage provided by an SD card or the
+ main hardware partition of an eMMC.
+
+patternProperties:
+ '^boot[0-9]+':
+ $ref: /schemas/block/block-device.yaml#
+ description:
+ Represents a boot hardware partition on an eMMC.
+
required:
- compatible
- reg
@@ -42,6 +54,39 @@ examples:
compatible = "mmc-card";
reg = <0>;
broken-hpi;
+
+ block {
+ partitions {
+ cal_data: block-partition-rf {
+ partnum = <3>;
+ partname = "rf";
+
+ nvmem-layout {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ eeprom@0 {
+ reg = <0x0 0x1000>;
+ };
+ };
+ };
+ };
+ };
+
+ boot1 {
+ nvmem-layout {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ macaddr: macaddr@a {
+ compatible = "mac-base";
+ reg = <0xa 0x6>;
+ #nvmem-cell-cells = <1>;
+ };
+ };
+ };
};
};

View file

@ -1,23 +0,0 @@
From 043c4f88476cc0f29c9bf82a8a516f58d848e1cd Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:15:25 +0100
Subject: [PATCH 7/9] mmc: core: set card fwnode_handle
Set fwnode in case it isn't set yet and of_node is present.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mmc/core/bus.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -368,6 +368,8 @@ int mmc_add_card(struct mmc_card *card)
mmc_add_card_debugfs(card);
card->dev.of_node = mmc_of_find_child_device(card->host, 0);
+ if (card->dev.of_node && !card->dev.fwnode)
+ card->dev.fwnode = &card->dev.of_node->fwnode;
device_enable_async_suspend(&card->dev);

View file

@ -1,7 +1,7 @@
From 9703951cdfe868b130e64d6122420396c2807be8 Mon Sep 17 00:00:00 2001 From 26ae98bf77fdbd60536fe5c2175e528469b9ac9a Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org> From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:15:02 +0100 Date: Wed, 15 May 2024 18:18:37 +0300
Subject: [PATCH 5/9] nvmem: implement block NVMEM provider Subject: [PATCH 7/8] nvmem: implement block NVMEM provider
On embedded devices using an eMMC it is common that one or more partitions On embedded devices using an eMMC it is common that one or more partitions
on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
@ -12,8 +12,8 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
--- ---
drivers/nvmem/Kconfig | 11 +++ drivers/nvmem/Kconfig | 11 +++
drivers/nvmem/Makefile | 2 + drivers/nvmem/Makefile | 2 +
drivers/nvmem/block.c | 197 +++++++++++++++++++++++++++++++++++++++++ drivers/nvmem/block.c | 198 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 210 insertions(+) 3 files changed, 211 insertions(+)
create mode 100644 drivers/nvmem/block.c create mode 100644 drivers/nvmem/block.c
--- a/drivers/nvmem/Kconfig --- a/drivers/nvmem/Kconfig
@ -49,7 +49,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o
--- /dev/null --- /dev/null
+++ b/drivers/nvmem/block.c +++ b/drivers/nvmem/block.c
@@ -0,0 +1,208 @@ @@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: GPL-2.0-or-later
+/* +/*
+ * block device NVMEM provider + * block device NVMEM provider
@ -72,42 +72,32 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ +
+struct blk_nvmem { +struct blk_nvmem {
+ struct nvmem_device *nvmem; + struct nvmem_device *nvmem;
+ struct block_device *bdev; + struct device *dev;
+ struct list_head list; + struct list_head list;
+}; +};
+ +
+static int blk_nvmem_reg_read(void *priv, unsigned int from, +static int blk_nvmem_reg_read(void *priv, unsigned int from,
+ void *val, size_t bytes) + void *val, size_t bytes)
+{ +{
+ blk_mode_t mode = BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES;
+ unsigned long offs = from & ~PAGE_MASK, to_read; + unsigned long offs = from & ~PAGE_MASK, to_read;
+ pgoff_t f_index = from >> PAGE_SHIFT; + pgoff_t f_index = from >> PAGE_SHIFT;
+ struct address_space *mapping;
+ struct blk_nvmem *bnv = priv; + struct blk_nvmem *bnv = priv;
+ size_t bytes_left = bytes; + size_t bytes_left = bytes;
+ struct file *bdev_file;
+ struct folio *folio; + struct folio *folio;
+ void *p; + void *p;
+ int ret; + int ret = 0;
+ +
+ if (!bnv->bdev) + bdev_file = bdev_file_open_by_dev(bnv->dev->devt, mode, priv, NULL);
+ if (!bdev_file)
+ return -ENODEV; + return -ENODEV;
+ +
+ if (!bnv->bdev->bd_disk) + if (IS_ERR(bdev_file))
+ return -EINVAL; + return PTR_ERR(bdev_file);
+
+ if (!bnv->bdev->bd_disk->fops)
+ return -EIO;
+
+ if (!bnv->bdev->bd_disk->fops->open)
+ return -EIO;
+
+ ret = bnv->bdev->bd_disk->fops->open(bnv->bdev->bd_disk, BLK_OPEN_READ);
+ if (ret)
+ return ret;
+
+ mapping = bnv->bdev->bd_inode->i_mapping;
+ +
+ while (bytes_left) { + while (bytes_left) {
+ folio = read_mapping_folio(mapping, f_index++, NULL); + folio = read_mapping_folio(bdev_file->f_mapping, f_index++, NULL);
+ if (IS_ERR(folio)) { + if (IS_ERR(folio)) {
+ ret = PTR_ERR(folio); + ret = PTR_ERR(folio);
+ goto err_release_bdev; + goto err_release_bdev;
@ -122,15 +112,15 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ } + }
+ +
+err_release_bdev: +err_release_bdev:
+ bnv->bdev->bd_disk->fops->release(bnv->bdev->bd_disk); + fput(bdev_file);
+ +
+ return ret; + return ret;
+} +}
+ +
+static int blk_nvmem_register(struct device *dev) +static int blk_nvmem_register(struct device *dev)
+{ +{
+ struct device_node *np = dev_of_node(dev);
+ struct block_device *bdev = dev_to_bdev(dev); + struct block_device *bdev = dev_to_bdev(dev);
+ struct device_node *np = dev_of_node(dev);
+ struct nvmem_config config = {}; + struct nvmem_config config = {};
+ struct blk_nvmem *bnv; + struct blk_nvmem *bnv;
+ +
@ -178,7 +168,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ config.ignore_wp = true; + config.ignore_wp = true;
+ config.of_node = to_of_node(dev->fwnode); + config.of_node = to_of_node(dev->fwnode);
+ +
+ bnv->bdev = bdev; + bnv->dev = &bdev->bd_device;
+ bnv->nvmem = nvmem_register(&config); + bnv->nvmem = nvmem_register(&config);
+ if (IS_ERR(bnv->nvmem)) { + if (IS_ERR(bnv->nvmem)) {
+ dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem), + dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem),
@ -197,12 +187,11 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ +
+static void blk_nvmem_unregister(struct device *dev) +static void blk_nvmem_unregister(struct device *dev)
+{ +{
+ struct block_device *bdev = dev_to_bdev(dev);
+ struct blk_nvmem *bnv_c, *bnv = NULL; + struct blk_nvmem *bnv_c, *bnv = NULL;
+ +
+ mutex_lock(&devices_mutex); + mutex_lock(&devices_mutex);
+ list_for_each_entry(bnv_c, &nvmem_devices, list) { + list_for_each_entry(bnv_c, &nvmem_devices, list) {
+ if (bnv_c->bdev == bdev) { + if (bnv_c->dev == dev) {
+ bnv = bnv_c; + bnv = bnv_c;
+ break; + break;
+ } + }
@ -226,6 +215,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+ switch (code) { + switch (code) {
+ case BLK_DEVICE_ADD: + case BLK_DEVICE_ADD:
+ return blk_nvmem_register(dev); + return blk_nvmem_register(dev);
+ break;
+ case BLK_DEVICE_REMOVE: + case BLK_DEVICE_REMOVE:
+ blk_nvmem_unregister(dev); + blk_nvmem_unregister(dev);
+ break; + break;

View file

@ -1,7 +1,7 @@
From 7903b50441000365a6fe5badb39735889f562252 Mon Sep 17 00:00:00 2001 From caac69565748349a3e532130a891e18dd5c36c5e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org> From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:15:46 +0100 Date: Thu, 20 Jul 2023 17:36:44 +0100
Subject: [PATCH 9/9] mmc: block: set GENHD_FL_NVMEM Subject: [PATCH 8/8] mmc: block: set GENHD_FL_NVMEM
Set flag to consider MMC block devices as NVMEM providers. Set flag to consider MMC block devices as NVMEM providers.

View file

@ -1,27 +0,0 @@
From ef3e38fec26901b71975d7e810a2df6b8bd54a8e Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Thu, 30 May 2024 03:15:36 +0100
Subject: [PATCH 8/9] mmc: block: set fwnode of disk devices
Set fwnode of disk devices to 'block', 'boot0' and 'boot1' subnodes of
the mmc-card. This is done in preparation for having the eMMC act as
NVMEM provider.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/mmc/core/block.c | 7 +++++++
1 file changed, 7 insertions(+)
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -2678,6 +2678,10 @@ static struct mmc_blk_data *mmc_blk_allo
if (area_type == MMC_BLK_DATA_AREA_MAIN)
dev_set_drvdata(&card->dev, md);
disk_fwnode = mmc_blk_get_partitions_node(parent, subname);
+ if (!disk_fwnode)
+ disk_fwnode = device_get_named_child_node(subname ? md->parent->parent :
+ md->parent,
+ subname ? subname : "block");
ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups,
disk_fwnode);
if (ret)