AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/01 23:32 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": [
    "BLK_NVMEM",
    "BT_QCA",
    "NVMEM"
  ],
  "FocusSymbols": [
    "blk_nvmem_reg_read",
    "blk_nvmem_add",
    "blk_nvmem_del",
    "hci_dev_get_bd_addr_from_nvmem",
    "of_get_nvmem_eui48",
    "of_nvmem_layout_get_container",
    "qca_check_bdaddr"
  ],
  "Reasoning": "The patch introduces a new block device NVMEM provider (`BLK_NVMEM`), allowing block devices or partitions to act as NVMEM providers. It also adds functionality to retrieve Bluetooth Device Addresses (BD_ADDR) and MAC addresses from NVMEM cells (`of_get_nvmem_eui48`, `hci_dev_get_bd_addr_from_nvmem`), and modifies the NVMEM layout container logic. These are functional changes to the block, NVMEM, and Bluetooth subsystems that should be fuzzed.",
  "WorthFuzzing": true
}

1/1 2026/07/01 23:32 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit b64dd50039c4e34e44b4865562de7fa027ef2049\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Wed Jul 1 23:32:44 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/Documentation/devicetree/bindings/mmc/mmc-card.yaml b/Documentation/devicetree/bindings/mmc/mmc-card.yaml\nindex a61d6c96df7591..0422894508478c 100644\n--- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml\n+++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml\n@@ -38,7 +38,9 @@ patternProperties:\n     properties:\n       compatible:\n         contains:\n-          const: fixed-partitions\n+          enum:\n+            - fixed-partitions\n+            - fixed-layout\n \n required:\n   - compatible\n@@ -86,6 +88,25 @@ examples:\n                     read-only;\n                 };\n             };\n+\n+            partitions-boot2 {\n+                compatible = \"fixed-layout\";\n+\n+                #address-cells = \u003c1\u003e;\n+                #size-cells = \u003c1\u003e;\n+\n+                mac-addr@4400 {\n+                    compatible = \"mac-base\";\n+                    reg = \u003c0x4400 0x6\u003e;\n+                    #nvmem-cell-cells = \u003c1\u003e;\n+                };\n+\n+                bd-addr@5400 {\n+                    compatible = \"mac-base\";\n+                    reg = \u003c0x5400 0x6\u003e;\n+                    #nvmem-cell-cells = \u003c1\u003e;\n+                };\n+            };\n         };\n     };\n \ndiff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml\nindex c8e9c55c1afb4c..7cb28f30c9af03 100644\n--- a/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml\n+++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml\n@@ -22,4 +22,13 @@ properties:\n     description:\n       boot firmware is incorrectly passing the address in big-endian order\n \n+  nvmem-cells:\n+    maxItems: 1\n+    description:\n+      Nvmem data cell that contains a 6 byte BD address with the most\n+      significant byte first (big-endian).\n+\n+  nvmem-cell-names:\n+    const: local-bd-address\n+\n additionalProperties: true\ndiff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml\nindex d4f4d72ee0d388..7f9d16cb7c1433 100644\n--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml\n+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml\n@@ -92,6 +92,22 @@ properties:\n \n   ieee80211-freq-limit: true\n \n+  nvmem-cells:\n+    minItems: 1\n+    maxItems: 3\n+    description:\n+      References to nvmem cells for MAC address and/or calibration data.\n+      Supported cell names are mac-address, calibration, and pre-calibration.\n+\n+  nvmem-cell-names:\n+    minItems: 1\n+    maxItems: 3\n+    items:\n+      enum:\n+        - mac-address\n+        - calibration\n+        - pre-calibration\n+\n   qcom,calibration-data:\n     $ref: /schemas/types.yaml#/definitions/uint8-array\n     description:\ndiff --git a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts\nindex bf088fa9807f04..38839b8a361e76 100644\n--- a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts\n+++ b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts\n@@ -409,7 +409,33 @@ \u0026sdhc_1 {\n \tno-sdio;\n \tno-sd;\n \n+\t#address-cells = \u003c1\u003e;\n+\t#size-cells = \u003c0\u003e;\n+\n \tstatus = \"okay\";\n+\n+\tcard@0 {\n+\t\tcompatible = \"mmc-card\";\n+\t\treg = \u003c0\u003e;\n+\n+\t\tpartitions-boot1 {\n+\t\t\tcompatible = \"fixed-layout\";\n+\t\t\t#address-cells = \u003c1\u003e;\n+\t\t\t#size-cells = \u003c1\u003e;\n+\n+\t\t\twifi_mac_addr: mac-addr@4400 {\n+\t\t\t\tcompatible = \"mac-base\";\n+\t\t\t\treg = \u003c0x4400 0x6\u003e;\n+\t\t\t\t#nvmem-cell-cells = \u003c1\u003e;\n+\t\t\t};\n+\n+\t\t\tbd_addr: bd-addr@5400 {\n+\t\t\t\tcompatible = \"mac-base\";\n+\t\t\t\treg = \u003c0x5400 0x6\u003e;\n+\t\t\t\t#nvmem-cell-cells = \u003c1\u003e;\n+\t\t\t};\n+\t\t};\n+\t};\n };\n \n \u0026spi5 {\n@@ -512,6 +538,9 @@ bluetooth {\n \t\tvddch0-supply = \u003c\u0026pm4125_l22\u003e;\n \t\tenable-gpios = \u003c\u0026tlmm 87 GPIO_ACTIVE_HIGH\u003e;\n \t\tmax-speed = \u003c3000000\u003e;\n+\n+\t\tnvmem-cells = \u003c\u0026bd_addr 0\u003e;\n+\t\tnvmem-cell-names = \"local-bd-address\";\n \t};\n };\n \n@@ -557,6 +586,9 @@ \u0026wifi {\n \tqcom,ath10k-calibration-variant = \"ArduinoImola\";\n \tfirmware-name = \"qcm2290\";\n \n+\tnvmem-cells = \u003c\u0026wifi_mac_addr 0\u003e;\n+\tnvmem-cell-names = \"mac-address\";\n+\n \tstatus = \"okay\";\n };\n \ndiff --git a/block/Kconfig b/block/Kconfig\nindex 70e4a66d941ff6..aec5d9fc13a3d3 100644\n--- a/block/Kconfig\n+++ b/block/Kconfig\n@@ -209,6 +209,15 @@ config BLK_INLINE_ENCRYPTION_FALLBACK\n \t  by falling back to the kernel crypto API when inline\n \t  encryption hardware is not present.\n \n+config BLK_NVMEM\n+\tbool \"Block device NVMEM provider\"\n+\tdepends on OF\n+\tdepends on NVMEM\n+\thelp\n+\t  Allow block devices (or partitions) to act as NVMEM providers,\n+\t  typically used with eMMC to store MAC addresses or Wi-Fi\n+\t  calibration data on embedded devices.\n+\n source \"block/partitions/Kconfig\"\n \n config BLK_PM\ndiff --git a/block/Makefile b/block/Makefile\nindex e7bd320e3d6971..8200297fbcbab3 100644\n--- a/block/Makefile\n+++ b/block/Makefile\n@@ -39,3 +39,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION)\t+= blk-crypto.o blk-crypto-profile.o \\\n \t\t\t\t\t   blk-crypto-sysfs.o\n obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK)\t+= blk-crypto-fallback.o\n obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED)\t+= holder.o\n+obj-$(CONFIG_BLK_NVMEM)                += blk-nvmem.o\ndiff --git a/block/blk-nvmem.c b/block/blk-nvmem.c\nnew file mode 100644\nindex 00000000000000..49e9b5d4410d5e\n--- /dev/null\n+++ b/block/blk-nvmem.c\n@@ -0,0 +1,109 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * block device NVMEM provider\n+ *\n+ * Copyright (c) 2024 Daniel Golle \u003cdaniel@makrotopia.org\u003e\n+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.\n+ *\n+ * Useful on devices using a partition on an eMMC for MAC addresses or\n+ * Wi-Fi calibration EEPROM data.\n+ */\n+\n+#include \u003clinux/cleanup.h\u003e\n+#include \u003clinux/device.h\u003e\n+#include \u003clinux/file.h\u003e\n+#include \u003clinux/nvmem-provider.h\u003e\n+#include \u003clinux/nvmem-consumer.h\u003e\n+#include \u003clinux/of.h\u003e\n+#include \u003clinux/pagemap.h\u003e\n+#include \u003clinux/property.h\u003e\n+\n+#include \"blk.h\"\n+\n+static int blk_nvmem_reg_read(void *priv, unsigned int from, void *val, size_t bytes)\n+{\n+\tdev_t devt = (dev_t)(uintptr_t)priv;\n+\tsize_t bytes_left = bytes;\n+\tloff_t pos = from;\n+\tint ret = 0;\n+\n+\tstruct file *bdev_file __free(fput) =\n+\t\tbdev_file_open_by_dev(devt, BLK_OPEN_READ, NULL, NULL);\n+\tif (IS_ERR(bdev_file))\n+\t\treturn PTR_ERR(bdev_file);\n+\n+\twhile (bytes_left) {\n+\t\tpgoff_t f_index = pos \u003e\u003e PAGE_SHIFT;\n+\t\tstruct folio *folio;\n+\t\tsize_t folio_off;\n+\t\tsize_t to_read;\n+\n+\t\tfolio = read_mapping_folio(bdev_file-\u003ef_mapping, f_index, NULL);\n+\t\tif (IS_ERR(folio)) {\n+\t\t\tret = PTR_ERR(folio);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tfolio_off = offset_in_folio(folio, pos);\n+\t\tto_read = min(bytes_left, folio_size(folio) - folio_off);\n+\t\tmemcpy_from_folio(val, folio, folio_off, to_read);\n+\t\tpos += to_read;\n+\t\tbytes_left -= to_read;\n+\t\tval += to_read;\n+\t\tfolio_put(folio);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int blk_nvmem_add(struct block_device *bdev)\n+{\n+\tstruct device *dev = \u0026bdev-\u003ebd_device;\n+\tstruct nvmem_config config = {};\n+\n+\t/* skip devices which do not have a device tree node */\n+\tif (!dev_of_node(dev))\n+\t\treturn 0;\n+\n+\t/* skip devices without an nvmem layout defined */\n+\tstruct device_node *child __free(device_node) =\n+\t\tof_get_child_by_name(dev_of_node(dev), \"nvmem-layout\");\n+\tif (!child \u0026\u0026 !of_device_is_compatible(dev_of_node(dev), \"fixed-layout\"))\n+\t\treturn 0;\n+\n+\t/*\n+\t * skip block device too large to be represented as NVMEM devices,\n+\t * nvmem_config.size is a signed int\n+\t */\n+\tif (bdev_nr_bytes(bdev) \u003e INT_MAX) {\n+\t\tdev_warn(dev, \"block device too large to be an NVMEM provider\\n\");\n+\t\treturn 0;\n+\t}\n+\n+\tconfig.id = NVMEM_DEVID_NONE;\n+\tconfig.dev = dev;\n+\tconfig.name = dev_name(dev);\n+\tconfig.owner = THIS_MODULE;\n+\tconfig.priv = (void *)(uintptr_t)dev-\u003edevt;\n+\tconfig.reg_read = blk_nvmem_reg_read;\n+\tconfig.size = bdev_nr_bytes(bdev);\n+\tconfig.word_size = 1;\n+\tconfig.stride = 1;\n+\tconfig.read_only = true;\n+\tconfig.root_only = true;\n+\tconfig.ignore_wp = true;\n+\tconfig.of_node = to_of_node(dev-\u003efwnode);\n+\n+\tbdev-\u003ebd_nvmem = nvmem_register(\u0026config);\n+\tif (IS_ERR(bdev-\u003ebd_nvmem))\n+\t\treturn dev_err_probe(dev, PTR_ERR(bdev-\u003ebd_nvmem),\n+\t\t\t\t     \"Failed to register NVMEM device\\n\");\n+\n+\treturn 0;\n+}\n+\n+void blk_nvmem_del(struct block_device *bdev)\n+{\n+\tnvmem_unregister(bdev-\u003ebd_nvmem);\n+\tbdev-\u003ebd_nvmem = NULL;\n+}\ndiff --git a/block/blk.h b/block/blk.h\nindex 25af8ac5ef0f77..dad8f0d7a218ed 100644\n--- a/block/blk.h\n+++ b/block/blk.h\n@@ -810,4 +810,12 @@ static inline void blk_debugfs_unlock(struct request_queue *q,\n \tmemalloc_noio_restore(memflags);\n }\n \n+#ifdef CONFIG_BLK_NVMEM\n+int blk_nvmem_add(struct block_device *bdev);\n+void blk_nvmem_del(struct block_device *bdev);\n+#else\n+static inline int blk_nvmem_add(struct block_device *bdev) { return 0; }\n+static inline void blk_nvmem_del(struct block_device *bdev) {}\n+#endif\n+\n #endif /* BLK_INTERNAL_H */\ndiff --git a/block/genhd.c b/block/genhd.c\nindex f84b6a355b574a..0c9c5e5ea7baff 100644\n--- a/block/genhd.c\n+++ b/block/genhd.c\n@@ -421,6 +421,8 @@ static void add_disk_final(struct gendisk *disk)\n \t\t */\n \t\tdev_set_uevent_suppress(ddev, 0);\n \t\tdisk_uevent(disk, KOBJ_ADD);\n+\n+\t\tblk_nvmem_add(disk-\u003epart0);\n \t}\n \n \tblk_apply_bdi_limits(disk-\u003ebdi, \u0026disk-\u003equeue-\u003elimits);\n@@ -704,6 +706,8 @@ static void __del_gendisk(struct gendisk *disk)\n \n \tdisk_del_events(disk);\n \n+\tblk_nvmem_del(disk-\u003epart0);\n+\n \t/*\n \t * Prevent new openers by unlinked the bdev inode.\n \t */\ndiff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c\nindex 04ebe290bc784e..06cb787b0559f3 100644\n--- a/drivers/bluetooth/btqca.c\n+++ b/drivers/bluetooth/btqca.c\n@@ -723,8 +723,11 @@ static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *co\n \t}\n \n \tbda = (struct hci_rp_read_bd_addr *)skb-\u003edata;\n-\tif (!bacmp(\u0026bda-\u003ebdaddr, \u0026config-\u003ebdaddr))\n+\tif (!bacmp(\u0026bda-\u003ebdaddr, \u0026config-\u003ebdaddr)) {\n \t\thci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);\n+\t\thci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM);\n+\t\thci_set_quirk(hdev, HCI_QUIRK_BDADDR_NVMEM_BE);\n+\t}\n \n \tkfree_skb(skb);\n \ndiff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c\nindex b90584e1b99eab..efa631ce7283bd 100644\n--- a/drivers/nvmem/layouts.c\n+++ b/drivers/nvmem/layouts.c\n@@ -167,7 +167,18 @@ static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,\n \n struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)\n {\n-\treturn of_get_child_by_name(nvmem-\u003edev.of_node, \"nvmem-layout\");\n+\tstruct device_node *np;\n+\n+\t/* Search for nvmem-layout child */\n+\tnp = of_get_child_by_name(nvmem-\u003edev.of_node, \"nvmem-layout\");\n+\tif (np)\n+\t\treturn np;\n+\n+\t/* The nvmem of_node is itself a fixed-layout node */\n+\tif (of_device_is_compatible(nvmem-\u003edev.of_node, \"fixed-layout\"))\n+\t\treturn of_node_get(nvmem-\u003edev.of_node);\n+\n+\treturn NULL;\n }\n EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);\n \ndiff --git a/include/linux/blk_types.h b/include/linux/blk_types.h\nindex 8808ee76e73c09..6ed173c649025b 100644\n--- a/include/linux/blk_types.h\n+++ b/include/linux/blk_types.h\n@@ -15,6 +15,7 @@\n struct bio_set;\n struct bio;\n struct bio_integrity_payload;\n+struct nvmem_device;\n struct page;\n struct io_context;\n struct cgroup_subsys_state;\n@@ -73,6 +74,9 @@ struct block_device {\n \tint\t\t\tbd_writers;\n #ifdef CONFIG_SECURITY\n \tvoid\t\t\t*bd_security;\n+#endif\n+#ifdef CONFIG_BLK_NVMEM\n+\tstruct nvmem_device\t*bd_nvmem;\n #endif\n \t/*\n \t * keep this out-of-line as it's both big and not needed in the fast\ndiff --git a/include/linux/of_net.h b/include/linux/of_net.h\nindex d88715a0b3a52f..7854ba555d9a55 100644\n--- a/include/linux/of_net.h\n+++ b/include/linux/of_net.h\n@@ -15,6 +15,7 @@ struct net_device;\n extern int of_get_phy_mode(struct device_node *np, phy_interface_t *interface);\n extern int of_get_mac_address(struct device_node *np, u8 *mac);\n extern int of_get_mac_address_nvmem(struct device_node *np, u8 *mac);\n+int of_get_nvmem_eui48(struct device_node *np, const char *cell_name, u8 *addr);\n int of_get_ethdev_address(struct device_node *np, struct net_device *dev);\n extern struct net_device *of_find_net_device_by_node(struct device_node *np);\n #else\n@@ -34,6 +35,12 @@ static inline int of_get_mac_address_nvmem(struct device_node *np, u8 *mac)\n \treturn -ENODEV;\n }\n \n+static inline int of_get_nvmem_eui48(struct device_node *np,\n+\t\t\t\t      const char *cell_name, u8 *addr)\n+{\n+\treturn -ENODEV;\n+}\n+\n static inline int of_get_ethdev_address(struct device_node *np, struct net_device *dev)\n {\n \treturn -ENODEV;\ndiff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h\nindex 38186a245f14db..145ab94e51482f 100644\n--- a/include/net/bluetooth/hci.h\n+++ b/include/net/bluetooth/hci.h\n@@ -161,6 +161,24 @@ enum {\n \t */\n \tHCI_QUIRK_BDADDR_PROPERTY_BROKEN,\n \n+\t/* When this quirk is set, the public Bluetooth address\n+\t * initially reported by HCI Read BD Address command\n+\t * is considered invalid. The public BD Address can be\n+\t * retrieved via a 'local-bd-address' NVMEM cell.\n+\t *\n+\t * This quirk can be set before hci_register_dev is called or\n+\t * during the hdev-\u003esetup vendor callback.\n+\t */\n+\tHCI_QUIRK_USE_BDADDR_NVMEM,\n+\n+\t/* When this quirk is set, the Bluetooth Device Address provided by\n+\t * the 'local-bd-address' NVMEM is stored in big-endian order.\n+\t *\n+\t * This quirk can be set before hci_register_dev is called or\n+\t * during the hdev-\u003esetup vendor callback.\n+\t */\n+\tHCI_QUIRK_BDADDR_NVMEM_BE,\n+\n \t/* When this quirk is set, the duplicate filtering during\n \t * scanning is based on Bluetooth devices addresses. To allow\n \t * RSSI based updates, restart scanning if needed.\ndiff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c\nindex 3be8c3581c6caa..c0ed7fb14d19bd 100644\n--- a/net/bluetooth/hci_sync.c\n+++ b/net/bluetooth/hci_sync.c\n@@ -7,6 +7,7 @@\n  */\n \n #include \u003clinux/property.h\u003e\n+#include \u003clinux/of_net.h\u003e\n \n #include \u003cnet/bluetooth/bluetooth.h\u003e\n #include \u003cnet/bluetooth/hci_core.h\u003e\n@@ -3593,6 +3594,39 @@ int hci_powered_update_sync(struct hci_dev *hdev)\n \treturn 0;\n }\n \n+/**\n+ * hci_dev_get_bd_addr_from_nvmem - Get the Bluetooth Device Address\n+ *\t\t\t\t    (BD_ADDR) for a HCI device from\n+ *\t\t\t\t    an NVMEM cell.\n+ * @hdev:\tThe HCI device\n+ *\n+ * Search for 'local-bd-address' NVMEM cell in the device firmware node.\n+ *\n+ * All-zero BD addresses are rejected (unprovisioned).\n+ *\n+ * Return: 0 on success, or a negative error code on failure.\n+ */\n+static int hci_dev_get_bd_addr_from_nvmem(struct hci_dev *hdev)\n+{\n+\tstruct device_node *np = dev_of_node(hdev-\u003edev.parent);\n+\tu8 ba[sizeof(bdaddr_t)];\n+\tint err;\n+\n+\tif (!np)\n+\t\treturn -ENODEV;\n+\n+\terr = of_get_nvmem_eui48(np, \"local-bd-address\", ba);\n+\tif (err)\n+\t\treturn err;\n+\n+\tif (hci_test_quirk(hdev, HCI_QUIRK_BDADDR_NVMEM_BE))\n+\t\tbaswap(\u0026hdev-\u003epublic_addr, (bdaddr_t *)ba);\n+\telse\n+\t\tbacpy(\u0026hdev-\u003epublic_addr, (bdaddr_t *)ba);\n+\n+\treturn 0;\n+}\n+\n /**\n  * hci_dev_get_bd_addr_from_property - Get the Bluetooth Device Address\n  *\t\t\t\t       (BD_ADDR) for a HCI device from\n@@ -5072,12 +5106,17 @@ static int hci_dev_setup_sync(struct hci_dev *hdev)\n \t * its setup callback.\n \t */\n \tinvalid_bdaddr = hci_test_quirk(hdev, HCI_QUIRK_INVALID_BDADDR) ||\n-\t\t\t hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);\n+\t\t\t hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY) ||\n+\t\t\t hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM);\n \tif (!ret) {\n \t\tif (hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY) \u0026\u0026\n \t\t    !bacmp(\u0026hdev-\u003epublic_addr, BDADDR_ANY))\n \t\t\thci_dev_get_bd_addr_from_property(hdev);\n \n+\t\tif (hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM) \u0026\u0026\n+\t\t    !bacmp(\u0026hdev-\u003epublic_addr, BDADDR_ANY))\n+\t\t\thci_dev_get_bd_addr_from_nvmem(hdev);\n+\n \t\tif (invalid_bdaddr \u0026\u0026 bacmp(\u0026hdev-\u003epublic_addr, BDADDR_ANY) \u0026\u0026\n \t\t    hdev-\u003eset_bdaddr) {\n \t\t\tret = hdev-\u003eset_bdaddr(hdev, \u0026hdev-\u003epublic_addr);\ndiff --git a/net/core/of_net.c b/net/core/of_net.c\nindex 93ea425b9248a2..11c1acca151266 100644\n--- a/net/core/of_net.c\n+++ b/net/core/of_net.c\n@@ -61,9 +61,7 @@ static int of_get_mac_addr(struct device_node *np, const char *name, u8 *addr)\n int of_get_mac_address_nvmem(struct device_node *np, u8 *addr)\n {\n \tstruct platform_device *pdev = of_find_device_by_node(np);\n-\tstruct nvmem_cell *cell;\n-\tconst void *mac;\n-\tsize_t len;\n+\tu8 mac[ETH_ALEN] __aligned(sizeof(u16));\n \tint ret;\n \n \t/* Try lookup by device first, there might be a nvmem_cell_lookup\n@@ -75,27 +73,54 @@ int of_get_mac_address_nvmem(struct device_node *np, u8 *addr)\n \t\treturn ret;\n \t}\n \n-\tcell = of_nvmem_cell_get(np, \"mac-address\");\n+\tret = of_get_nvmem_eui48(np, \"mac-address\", mac);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (!is_valid_ether_addr(mac))\n+\t\treturn -EINVAL;\n+\n+\tether_addr_copy(addr, mac);\n+\treturn 0;\n+}\n+EXPORT_SYMBOL(of_get_mac_address_nvmem);\n+\n+/**\n+ * of_get_nvmem_eui48 - Read a 6-byte EUI-48 address from a named NVMEM cell.\n+ * @np:\t\tDevice node to look up the NVMEM cell from.\n+ * @cell_name:\tName of the NVMEM cell (e.g. \"mac-address\", \"local-bd-address\").\n+ * @addr:\tOutput buffer for the 6-byte address.\n+ *\n+ * Reads the named NVMEM cell and validates that it contains a non-zero 6-byte\n+ * address. Returns 0 on success, negative errno on failure.\n+ */\n+int of_get_nvmem_eui48(struct device_node *np, const char *cell_name, u8 *addr)\n+{\n+\tstruct nvmem_cell *cell;\n+\tconst void *eui48;\n+\tsize_t len;\n+\n+\tcell = of_nvmem_cell_get(np, cell_name);\n \tif (IS_ERR(cell))\n \t\treturn PTR_ERR(cell);\n \n-\tmac = nvmem_cell_read(cell, \u0026len);\n+\teui48 = nvmem_cell_read(cell, \u0026len);\n \tnvmem_cell_put(cell);\n \n-\tif (IS_ERR(mac))\n-\t\treturn PTR_ERR(mac);\n+\tif (IS_ERR(eui48))\n+\t\treturn PTR_ERR(eui48);\n \n-\tif (len != ETH_ALEN || !is_valid_ether_addr(mac)) {\n-\t\tkfree(mac);\n+\tif (len != ETH_ALEN || !memchr_inv(eui48, 0, ETH_ALEN)) {\n+\t\tkfree(eui48);\n \t\treturn -EINVAL;\n \t}\n \n-\tmemcpy(addr, mac, ETH_ALEN);\n-\tkfree(mac);\n+\tmemcpy(addr, eui48, ETH_ALEN);\n+\tkfree(eui48);\n \n \treturn 0;\n }\n-EXPORT_SYMBOL(of_get_mac_address_nvmem);\n+EXPORT_SYMBOL_GPL(of_get_nvmem_eui48);\n \n /**\n  * of_get_mac_address()\n"
}

2/1 2026/07/01 23:32 agent patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "BLK_NVMEM",
    "BT_QCA",
    "NVMEM"
  ],
  "FocusSymbols": [
    "blk_nvmem_reg_read",
    "blk_nvmem_add",
    "blk_nvmem_del",
    "hci_dev_get_bd_addr_from_nvmem",
    "of_get_nvmem_eui48",
    "of_nvmem_layout_get_container",
    "qca_check_bdaddr"
  ],
  "Reasoning": "The patch introduces a new block device NVMEM provider (`BLK_NVMEM`), allowing block devices or partitions to act as NVMEM providers. It also adds functionality to retrieve Bluetooth Device Addresses (BD_ADDR) and MAC addresses from NVMEM cells (`of_get_nvmem_eui48`, `hci_dev_get_bd_addr_from_nvmem`), and modifies the NVMEM layout container logic. These are functional changes to the block, NVMEM, and Bluetooth subsystems that should be fuzzed.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit b64dd50039c4e34e44b4865562de7fa027ef2049
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Jul 1 23:32:44 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/devicetree/bindings/mmc/mmc-card.yaml b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
index a61d6c96df7591..0422894508478c 100644
--- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml
+++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml
@@ -38,7 +38,9 @@ patternProperties:
     properties:
       compatible:
         contains:
-          const: fixed-partitions
+          enum:
+            - fixed-partitions
+            - fixed-layout
 
 required:
   - compatible
@@ -86,6 +88,25 @@ examples:
                     read-only;
                 };
             };
+
+            partitions-boot2 {
+                compatible = "fixed-layout";
+
+                #address-cells = <1>;
+                #size-cells = <1>;
+
+                mac-addr@4400 {
+                    compatible = "mac-base";
+                    reg = <0x4400 0x6>;
+                    #nvmem-cell-cells = <1>;
+                };
+
+                bd-addr@5400 {
+                    compatible = "mac-base";
+                    reg = <0x5400 0x6>;
+                    #nvmem-cell-cells = <1>;
+                };
+            };
         };
     };
 
diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml
index c8e9c55c1afb4c..7cb28f30c9af03 100644
--- a/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml
+++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,bluetooth-common.yaml
@@ -22,4 +22,13 @@ properties:
     description:
       boot firmware is incorrectly passing the address in big-endian order
 
+  nvmem-cells:
+    maxItems: 1
+    description:
+      Nvmem data cell that contains a 6 byte BD address with the most
+      significant byte first (big-endian).
+
+  nvmem-cell-names:
+    const: local-bd-address
+
 additionalProperties: true
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
index d4f4d72ee0d388..7f9d16cb7c1433 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
@@ -92,6 +92,22 @@ properties:
 
   ieee80211-freq-limit: true
 
+  nvmem-cells:
+    minItems: 1
+    maxItems: 3
+    description:
+      References to nvmem cells for MAC address and/or calibration data.
+      Supported cell names are mac-address, calibration, and pre-calibration.
+
+  nvmem-cell-names:
+    minItems: 1
+    maxItems: 3
+    items:
+      enum:
+        - mac-address
+        - calibration
+        - pre-calibration
+
   qcom,calibration-data:
     $ref: /schemas/types.yaml#/definitions/uint8-array
     description:
diff --git a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
index bf088fa9807f04..38839b8a361e76 100644
--- a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
+++ b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts
@@ -409,7 +409,33 @@ &sdhc_1 {
 	no-sdio;
 	no-sd;
 
+	#address-cells = <1>;
+	#size-cells = <0>;
+
 	status = "okay";
+
+	card@0 {
+		compatible = "mmc-card";
+		reg = <0>;
+
+		partitions-boot1 {
+			compatible = "fixed-layout";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			wifi_mac_addr: mac-addr@4400 {
+				compatible = "mac-base";
+				reg = <0x4400 0x6>;
+				#nvmem-cell-cells = <1>;
+			};
+
+			bd_addr: bd-addr@5400 {
+				compatible = "mac-base";
+				reg = <0x5400 0x6>;
+				#nvmem-cell-cells = <1>;
+			};
+		};
+	};
 };
 
 &spi5 {
@@ -512,6 +538,9 @@ bluetooth {
 		vddch0-supply = <&pm4125_l22>;
 		enable-gpios = <&tlmm 87 GPIO_ACTIVE_HIGH>;
 		max-speed = <3000000>;
+
+		nvmem-cells = <&bd_addr 0>;
+		nvmem-cell-names = "local-bd-address";
 	};
 };
 
@@ -557,6 +586,9 @@ &wifi {
 	qcom,ath10k-calibration-variant = "ArduinoImola";
 	firmware-name = "qcm2290";
 
+	nvmem-cells = <&wifi_mac_addr 0>;
+	nvmem-cell-names = "mac-address";
+
 	status = "okay";
 };
 
diff --git a/block/Kconfig b/block/Kconfig
index 70e4a66d941ff6..aec5d9fc13a3d3 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -209,6 +209,15 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
 	  by falling back to the kernel crypto API when inline
 	  encryption hardware is not present.
 
+config BLK_NVMEM
+	bool "Block device NVMEM provider"
+	depends on OF
+	depends on NVMEM
+	help
+	  Allow block devices (or partitions) to act as NVMEM providers,
+	  typically used with eMMC to store MAC addresses or Wi-Fi
+	  calibration data on embedded devices.
+
 source "block/partitions/Kconfig"
 
 config BLK_PM
diff --git a/block/Makefile b/block/Makefile
index e7bd320e3d6971..8200297fbcbab3 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -39,3 +39,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION)	+= blk-crypto.o blk-crypto-profile.o \
 					   blk-crypto-sysfs.o
 obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK)	+= blk-crypto-fallback.o
 obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED)	+= holder.o
+obj-$(CONFIG_BLK_NVMEM)                += blk-nvmem.o
diff --git a/block/blk-nvmem.c b/block/blk-nvmem.c
new file mode 100644
index 00000000000000..49e9b5d4410d5e
--- /dev/null
+++ b/block/blk-nvmem.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * block device NVMEM provider
+ *
+ * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * Useful on devices using a partition on an eMMC for MAC addresses or
+ * Wi-Fi calibration EEPROM data.
+ */
+
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/nvmem-provider.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/pagemap.h>
+#include <linux/property.h>
+
+#include "blk.h"
+
+static int blk_nvmem_reg_read(void *priv, unsigned int from, void *val, size_t bytes)
+{
+	dev_t devt = (dev_t)(uintptr_t)priv;
+	size_t bytes_left = bytes;
+	loff_t pos = from;
+	int ret = 0;
+
+	struct file *bdev_file __free(fput) =
+		bdev_file_open_by_dev(devt, BLK_OPEN_READ, NULL, NULL);
+	if (IS_ERR(bdev_file))
+		return PTR_ERR(bdev_file);
+
+	while (bytes_left) {
+		pgoff_t f_index = pos >> PAGE_SHIFT;
+		struct folio *folio;
+		size_t folio_off;
+		size_t to_read;
+
+		folio = read_mapping_folio(bdev_file->f_mapping, f_index, NULL);
+		if (IS_ERR(folio)) {
+			ret = PTR_ERR(folio);
+			break;
+		}
+
+		folio_off = offset_in_folio(folio, pos);
+		to_read = min(bytes_left, folio_size(folio) - folio_off);
+		memcpy_from_folio(val, folio, folio_off, to_read);
+		pos += to_read;
+		bytes_left -= to_read;
+		val += to_read;
+		folio_put(folio);
+	}
+
+	return ret;
+}
+
+int blk_nvmem_add(struct block_device *bdev)
+{
+	struct device *dev = &bdev->bd_device;
+	struct nvmem_config config = {};
+
+	/* skip devices which do not have a device tree node */
+	if (!dev_of_node(dev))
+		return 0;
+
+	/* skip devices without an nvmem layout defined */
+	struct device_node *child __free(device_node) =
+		of_get_child_by_name(dev_of_node(dev), "nvmem-layout");
+	if (!child && !of_device_is_compatible(dev_of_node(dev), "fixed-layout"))
+		return 0;
+
+	/*
+	 * skip block device too large to be represented as NVMEM devices,
+	 * nvmem_config.size is a signed int
+	 */
+	if (bdev_nr_bytes(bdev) > INT_MAX) {
+		dev_warn(dev, "block device too large to be an NVMEM provider\n");
+		return 0;
+	}
+
+	config.id = NVMEM_DEVID_NONE;
+	config.dev = dev;
+	config.name = dev_name(dev);
+	config.owner = THIS_MODULE;
+	config.priv = (void *)(uintptr_t)dev->devt;
+	config.reg_read = blk_nvmem_reg_read;
+	config.size = bdev_nr_bytes(bdev);
+	config.word_size = 1;
+	config.stride = 1;
+	config.read_only = true;
+	config.root_only = true;
+	config.ignore_wp = true;
+	config.of_node = to_of_node(dev->fwnode);
+
+	bdev->bd_nvmem = nvmem_register(&config);
+	if (IS_ERR(bdev->bd_nvmem))
+		return dev_err_probe(dev, PTR_ERR(bdev->bd_nvmem),
+				     "Failed to register NVMEM device\n");
+
+	return 0;
+}
+
+void blk_nvmem_del(struct block_device *bdev)
+{
+	nvmem_unregister(bdev->bd_nvmem);
+	bdev->bd_nvmem = NULL;
+}
diff --git a/block/blk.h b/block/blk.h
index 25af8ac5ef0f77..dad8f0d7a218ed 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -810,4 +810,12 @@ static inline void blk_debugfs_unlock(struct request_queue *q,
 	memalloc_noio_restore(memflags);
 }
 
+#ifdef CONFIG_BLK_NVMEM
+int blk_nvmem_add(struct block_device *bdev);
+void blk_nvmem_del(struct block_device *bdev);
+#else
+static inline int blk_nvmem_add(struct block_device *bdev) { return 0; }
+static inline void blk_nvmem_del(struct block_device *bdev) {}
+#endif
+
 #endif /* BLK_INTERNAL_H */
diff --git a/block/genhd.c b/block/genhd.c
index f84b6a355b574a..0c9c5e5ea7baff 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -421,6 +421,8 @@ static void add_disk_final(struct gendisk *disk)
 		 */
 		dev_set_uevent_suppress(ddev, 0);
 		disk_uevent(disk, KOBJ_ADD);
+
+		blk_nvmem_add(disk->part0);
 	}
 
 	blk_apply_bdi_limits(disk->bdi, &disk->queue->limits);
@@ -704,6 +706,8 @@ static void __del_gendisk(struct gendisk *disk)
 
 	disk_del_events(disk);
 
+	blk_nvmem_del(disk->part0);
+
 	/*
 	 * Prevent new openers by unlinked the bdev inode.
 	 */
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 04ebe290bc784e..06cb787b0559f3 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -723,8 +723,11 @@ static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *co
 	}
 
 	bda = (struct hci_rp_read_bd_addr *)skb->data;
-	if (!bacmp(&bda->bdaddr, &config->bdaddr))
+	if (!bacmp(&bda->bdaddr, &config->bdaddr)) {
 		hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);
+		hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM);
+		hci_set_quirk(hdev, HCI_QUIRK_BDADDR_NVMEM_BE);
+	}
 
 	kfree_skb(skb);
 
diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c
index b90584e1b99eab..efa631ce7283bd 100644
--- a/drivers/nvmem/layouts.c
+++ b/drivers/nvmem/layouts.c
@@ -167,7 +167,18 @@ static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
 
 struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
 {
-	return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
+	struct device_node *np;
+
+	/* Search for nvmem-layout child */
+	np = of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
+	if (np)
+		return np;
+
+	/* The nvmem of_node is itself a fixed-layout node */
+	if (of_device_is_compatible(nvmem->dev.of_node, "fixed-layout"))
+		return of_node_get(nvmem->dev.of_node);
+
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
 
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 8808ee76e73c09..6ed173c649025b 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -15,6 +15,7 @@
 struct bio_set;
 struct bio;
 struct bio_integrity_payload;
+struct nvmem_device;
 struct page;
 struct io_context;
 struct cgroup_subsys_state;
@@ -73,6 +74,9 @@ struct block_device {
 	int			bd_writers;
 #ifdef CONFIG_SECURITY
 	void			*bd_security;
+#endif
+#ifdef CONFIG_BLK_NVMEM
+	struct nvmem_device	*bd_nvmem;
 #endif
 	/*
 	 * keep this out-of-line as it's both big and not needed in the fast
diff --git a/include/linux/of_net.h b/include/linux/of_net.h
index d88715a0b3a52f..7854ba555d9a55 100644
--- a/include/linux/of_net.h
+++ b/include/linux/of_net.h
@@ -15,6 +15,7 @@ struct net_device;
 extern int of_get_phy_mode(struct device_node *np, phy_interface_t *interface);
 extern int of_get_mac_address(struct device_node *np, u8 *mac);
 extern int of_get_mac_address_nvmem(struct device_node *np, u8 *mac);
+int of_get_nvmem_eui48(struct device_node *np, const char *cell_name, u8 *addr);
 int of_get_ethdev_address(struct device_node *np, struct net_device *dev);
 extern struct net_device *of_find_net_device_by_node(struct device_node *np);
 #else
@@ -34,6 +35,12 @@ static inline int of_get_mac_address_nvmem(struct device_node *np, u8 *mac)
 	return -ENODEV;
 }
 
+static inline int of_get_nvmem_eui48(struct device_node *np,
+				      const char *cell_name, u8 *addr)
+{
+	return -ENODEV;
+}
+
 static inline int of_get_ethdev_address(struct device_node *np, struct net_device *dev)
 {
 	return -ENODEV;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 38186a245f14db..145ab94e51482f 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -161,6 +161,24 @@ enum {
 	 */
 	HCI_QUIRK_BDADDR_PROPERTY_BROKEN,
 
+	/* When this quirk is set, the public Bluetooth address
+	 * initially reported by HCI Read BD Address command
+	 * is considered invalid. The public BD Address can be
+	 * retrieved via a 'local-bd-address' NVMEM cell.
+	 *
+	 * This quirk can be set before hci_register_dev is called or
+	 * during the hdev->setup vendor callback.
+	 */
+	HCI_QUIRK_USE_BDADDR_NVMEM,
+
+	/* When this quirk is set, the Bluetooth Device Address provided by
+	 * the 'local-bd-address' NVMEM is stored in big-endian order.
+	 *
+	 * This quirk can be set before hci_register_dev is called or
+	 * during the hdev->setup vendor callback.
+	 */
+	HCI_QUIRK_BDADDR_NVMEM_BE,
+
 	/* When this quirk is set, the duplicate filtering during
 	 * scanning is based on Bluetooth devices addresses. To allow
 	 * RSSI based updates, restart scanning if needed.
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 3be8c3581c6caa..c0ed7fb14d19bd 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/property.h>
+#include <linux/of_net.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -3593,6 +3594,39 @@ int hci_powered_update_sync(struct hci_dev *hdev)
 	return 0;
 }
 
+/**
+ * hci_dev_get_bd_addr_from_nvmem - Get the Bluetooth Device Address
+ *				    (BD_ADDR) for a HCI device from
+ *				    an NVMEM cell.
+ * @hdev:	The HCI device
+ *
+ * Search for 'local-bd-address' NVMEM cell in the device firmware node.
+ *
+ * All-zero BD addresses are rejected (unprovisioned).
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+static int hci_dev_get_bd_addr_from_nvmem(struct hci_dev *hdev)
+{
+	struct device_node *np = dev_of_node(hdev->dev.parent);
+	u8 ba[sizeof(bdaddr_t)];
+	int err;
+
+	if (!np)
+		return -ENODEV;
+
+	err = of_get_nvmem_eui48(np, "local-bd-address", ba);
+	if (err)
+		return err;
+
+	if (hci_test_quirk(hdev, HCI_QUIRK_BDADDR_NVMEM_BE))
+		baswap(&hdev->public_addr, (bdaddr_t *)ba);
+	else
+		bacpy(&hdev->public_addr, (bdaddr_t *)ba);
+
+	return 0;
+}
+
 /**
  * hci_dev_get_bd_addr_from_property - Get the Bluetooth Device Address
  *				       (BD_ADDR) for a HCI device from
@@ -5072,12 +5106,17 @@ static int hci_dev_setup_sync(struct hci_dev *hdev)
 	 * its setup callback.
 	 */
 	invalid_bdaddr = hci_test_quirk(hdev, HCI_QUIRK_INVALID_BDADDR) ||
-			 hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);
+			 hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY) ||
+			 hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM);
 	if (!ret) {
 		if (hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY) &&
 		    !bacmp(&hdev->public_addr, BDADDR_ANY))
 			hci_dev_get_bd_addr_from_property(hdev);
 
+		if (hci_test_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM) &&
+		    !bacmp(&hdev->public_addr, BDADDR_ANY))
+			hci_dev_get_bd_addr_from_nvmem(hdev);
+
 		if (invalid_bdaddr && bacmp(&hdev->public_addr, BDADDR_ANY) &&
 		    hdev->set_bdaddr) {
 			ret = hdev->set_bdaddr(hdev, &hdev->public_addr);
diff --git a/net/core/of_net.c b/net/core/of_net.c
index 93ea425b9248a2..11c1acca151266 100644
--- a/net/core/of_net.c
+++ b/net/core/of_net.c
@@ -61,9 +61,7 @@ static int of_get_mac_addr(struct device_node *np, const char *name, u8 *addr)
 int of_get_mac_address_nvmem(struct device_node *np, u8 *addr)
 {
 	struct platform_device *pdev = of_find_device_by_node(np);
-	struct nvmem_cell *cell;
-	const void *mac;
-	size_t len;
+	u8 mac[ETH_ALEN] __aligned(sizeof(u16));
 	int ret;
 
 	/* Try lookup by device first, there might be a nvmem_cell_lookup
@@ -75,27 +73,54 @@ int of_get_mac_address_nvmem(struct device_node *np, u8 *addr)
 		return ret;
 	}
 
-	cell = of_nvmem_cell_get(np, "mac-address");
+	ret = of_get_nvmem_eui48(np, "mac-address", mac);
+	if (ret)
+		return ret;
+
+	if (!is_valid_ether_addr(mac))
+		return -EINVAL;
+
+	ether_addr_copy(addr, mac);
+	return 0;
+}
+EXPORT_SYMBOL(of_get_mac_address_nvmem);
+
+/**
+ * of_get_nvmem_eui48 - Read a 6-byte EUI-48 address from a named NVMEM cell.
+ * @np:		Device node to look up the NVMEM cell from.
+ * @cell_name:	Name of the NVMEM cell (e.g. "mac-address", "local-bd-address").
+ * @addr:	Output buffer for the 6-byte address.
+ *
+ * Reads the named NVMEM cell and validates that it contains a non-zero 6-byte
+ * address. Returns 0 on success, negative errno on failure.
+ */
+int of_get_nvmem_eui48(struct device_node *np, const char *cell_name, u8 *addr)
+{
+	struct nvmem_cell *cell;
+	const void *eui48;
+	size_t len;
+
+	cell = of_nvmem_cell_get(np, cell_name);
 	if (IS_ERR(cell))
 		return PTR_ERR(cell);
 
-	mac = nvmem_cell_read(cell, &len);
+	eui48 = nvmem_cell_read(cell, &len);
 	nvmem_cell_put(cell);
 
-	if (IS_ERR(mac))
-		return PTR_ERR(mac);
+	if (IS_ERR(eui48))
+		return PTR_ERR(eui48);
 
-	if (len != ETH_ALEN || !is_valid_ether_addr(mac)) {
-		kfree(mac);
+	if (len != ETH_ALEN || !memchr_inv(eui48, 0, ETH_ALEN)) {
+		kfree(eui48);
 		return -EINVAL;
 	}
 
-	memcpy(addr, mac, ETH_ALEN);
-	kfree(mac);
+	memcpy(addr, eui48, ETH_ALEN);
+	kfree(eui48);
 
 	return 0;
 }
-EXPORT_SYMBOL(of_get_mac_address_nvmem);
+EXPORT_SYMBOL_GPL(of_get_nvmem_eui48);
 
 /**
  * of_get_mac_address()

3/2 2026/07/01 23:32 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 9158
							output: 21
							thoughts: 2504
						

Thoughts:
**Fuzzing Feasibility of the BLK_NVMEM Patch**

Okay, so we have this patch introducing `BLK_NVMEM`, allowing block devices to act as NVMEM providers. My initial thought is to assess its fuzzing potential. It's touching `blk-nvmem.c`, adding `blk_nvmem_add`, `blk_nvmem_del` in `genhd.c`, and sprinkling changes throughout the Bluetooth and networking subsystems, with modifications to `hci_sync.c`, `of_net.c`, and `btqca.c`. So, it's quite a wide-reaching change.

First, let's look at reachability. `blk_nvmem_add` is called in `add_disk_final`, so when a block device is added. The crucial check is the need for a device tree node with either an `nvmem-layout` or the `fixed-layout` compatible. This could be problematic in standard x86 VMs. Syzkaller *can* inject device tree nodes, but this is less common on x86, particularly with direct DT overlays.

The core of the matter is whether this is reachable given the device tree requirements. `blk_nvmem_reg_read` is another interesting function that reads from the block device using `bdev_file_open_by_dev`. This seems like a new avenue for fuzzing, but it hinges on `blk_nvmem_add` succeeding, i.e., the existence of the right DT node. It's unlikely for standard block devices on x86, perhaps even loop devices.

However, `of_get_nvmem_eui48` is exported and used in `of_get_mac_address_nvmem`. This is used by many network drivers. This is interesting since the `hci_dev_get_bd_addr_from_nvmem` is called from `hci_dev_setup_sync` if `HCI_QUIRK_USE_BDADDR_NVMEM` is set. This is controlled by a Bluetooth quirk and triggered in `btqca.c`. Syzkaller *can* fuzz hci_uart, but this still depends on a device tree node for `of_get_nvmem_eui48`.

Config-wise, `CONFIG_BLK_NVMEM`, `CONFIG_NVMEM`, and possibly `CONFIG_BT_HCIUART_QCA` are key.

Looking at the code, specifically `blk_nvmem_reg_read`, it's a new NVMEM provider that uses a block device. Worth fuzzing because of this. Now, can Syzkaller *reach* this? Potentially on ARM64 with Device Trees, as this is used in MMC devices. For example, if there is a `nvmem-layout` or `fixed-layout`.

The MMC example shows a clear path for DT-based devices to leverage this new functionality. The generic code is reachable if any NVMEM cell is present.

Now, let's consider reachability. `of_get_mac_address_nvmem` is used by a lot of drivers, which call `eth_platform_get_mac_address`, and that calls `of_get_mac_address_nvmem`.

So, what are we trying to reach? We have `blk_nvmem_reg_read`, `blk_nvmem_add`, and `blk_nvmem_del`, as well as `hci_dev_get_bd_addr_from_nvmem` and `of_get_nvmem_eui48`. This is *functional* code.

The question is, are these code paths impossible to reach in virtualized environments? For x86 without DT, yes, the initial paths seem impossible to reach. But with ARM64 with DTs, they can be reached. Syzkaller's configfs/DT overlay support might also be relevant here. If there is a "mac-address" nvmem cell in the DT, it will be read, even if it fails, the first few lines are still executed.

We need to make sure the base DT has an `nvmem-layout` on a block device. If it's missing, the rest of the code won't be reachable. This requires an overlay. This isn't that far fetched considering Syzkaller has support for configfs and DT overlays, which could potentially give us a way to dynamically add DT nodes. So, in terms of virtualized environments and feasibility, the focus needs to be on platforms where DT is present, such as ARM64, and where Syzkaller can manipulate the device tree. Yes, this patch introduces functionality that is worth fuzzing.



4/2 2026/07/01 23:33 tool grepper
0m Args:
{
  "Expression": "config BLK_NVMEM"
}

Results:
{
  "Output": "block/Kconfig=202=config BLK_INLINE_ENCRYPTION_FALLBACK\n--\nblock/Kconfig-211-\nblock/Kconfig:212:config BLK_NVMEM\nblock/Kconfig-213-\tbool \"Block device NVMEM provider\"\n"
}

5/2 2026/07/01 23:33 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 12782
							output: 19
							thoughts: 27
						

Thoughts:
Here's my thought process, as if I were considering this issue:

**Examining the Bluetooth UART Configuration**

Okay, so I need to verify something crucial about the Bluetooth QCA driver (`btqca.c`). I'm wondering if `BT_HCIUART_QCA` is, in fact, the correct configuration option for this specific module. It's a critical point to ensure proper functionality and prevent any unexpected behavior during operation. A misconfiguration here could lead to communication failures, reduced throughput, or even more serious issues within the Bluetooth subsystem. I'm going to quickly cross-reference this with the documentation and any related code comments to confirm the intended association between the driver and this specific configuration. This is basic, but necessary to be sure I haven't missed anything. I'll need to double-check the associated definitions and dependencies to make certain all is in order.



6/2 2026/07/01 23:33 tool grepper
0m Args:
{
  "Expression": "btqca\\.o"
}

Results:
{
  "Output": "drivers/bluetooth/Makefile=25=obj-$(CONFIG_BT_RTL)\t\t+= btrtl.o\ndrivers/bluetooth/Makefile:26:obj-$(CONFIG_BT_QCA)\t\t+= btqca.o\ndrivers/bluetooth/Makefile-27-obj-$(CONFIG_BT_MTK)\t\t+= btmtk.o\n"
}

7/2 2026/07/01 23:33 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13107
							output: 29
							thoughts: 35
						

Thoughts:
Okay, here's my interpretation of those thoughts, tailored for an expert audience:

**Analyzing the Bluetooth Qualcomm Configuration**

Right, so we're looking at `CONFIG_BT_QCA`. That immediately tells me we're dealing with a Qualcomm Bluetooth implementation, likely on an embedded system. The focus here is likely the driver or related support. My next thought is, let's see if the `of_get_nvmem_eui48` function is available. I'm assuming that function might be relevant for getting the EUI-48 (Bluetooth MAC address) from non-volatile memory, potentially through a device tree node. We'll need to check if the symbol is exported and accessible. I suspect this is part of the initialization sequence for the Bluetooth controller. The goal is to avoid hardcoding the Bluetooth MAC in the driver.



8/2 2026/07/01 23:33 tool grepper
0m Args:
{
  "Expression": "EXPORT_SYMBOL.*of_get_nvmem_eui48"
}

Results:
{
  "Output": "net/core/of_net.c=97=int of_get_nvmem_eui48(struct device_node *np, const char *cell_name, u8 *addr)\n--\nnet/core/of_net.c-122-}\nnet/core/of_net.c:123:EXPORT_SYMBOL_GPL(of_get_nvmem_eui48);\nnet/core/of_net.c-124-\n"
}

9/2 2026/07/01 23:33 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13474
							output: 28
							thoughts: 26
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Analyzing the Bluetooth HCI Device Address Retrieval**

Yes, that's correct, absolutely. We're on the right track. Time to dive into the specifics of how this works.

Let's dissect the implementation of `hci_dev_get_bd_addr_from_nvmem`, specifically. I want to understand how we're pulling the Bluetooth device address from non-volatile memory. I need to refresh my memory on the interactions with the NVRAM and any potential race conditions that could come into play with this. Are we considering any potential NVRAM corruption scenarios? We must look into the error handling and potential recovery mechanisms of this function, as well as the initialization routines that precede it, to be confident of the Bluetooth device address retrieval.



10/2 2026/07/01 23:33 tool grepper
0m Args:
{
  "Expression": "hci_dev_get_bd_addr_from_nvmem"
}

Results:
{
  "Output": "net/bluetooth/hci_sync.c=3539=int hci_powered_update_sync(struct hci_dev *hdev)\n--\nnet/bluetooth/hci_sync.c-3597-/**\nnet/bluetooth/hci_sync.c:3598: * hci_dev_get_bd_addr_from_nvmem - Get the Bluetooth Device Address\nnet/bluetooth/hci_sync.c-3599- *\t\t\t\t    (BD_ADDR) for a HCI device from\n--\nnet/bluetooth/hci_sync.c-3608- */\nnet/bluetooth/hci_sync.c:3609:static int hci_dev_get_bd_addr_from_nvmem(struct hci_dev *hdev)\nnet/bluetooth/hci_sync.c-3610-{\n--\nnet/bluetooth/hci_sync.c=5082=static int hci_dev_setup_sync(struct hci_dev *hdev)\n--\nnet/bluetooth/hci_sync.c-5117-\t\t    !bacmp(\u0026hdev-\u003epublic_addr, BDADDR_ANY))\nnet/bluetooth/hci_sync.c:5118:\t\t\thci_dev_get_bd_addr_from_nvmem(hdev);\nnet/bluetooth/hci_sync.c-5119-\n"
}

11/2 2026/07/01 23:33 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 14030
							output: 24
							thoughts: 170
						

Thoughts:
**My Configuration Logic**

Okay, let's break this down. First, I need to figure out if `CONFIG_NVMEM` is actually necessary in this context. It seems like `BLK_NVMEM` is dependent on `NVMEM`, which is a good starting point. So, the direct consequence of enabling `NVMEM` is that I should also enable `BLK_NVMEM`. And since this is related to a platform with `BT_QCA`, I think that `BT_QCA` should be enabled as well.

Now, are there any other dependencies I need to consider? It looks like `CONFIG_OF` – the "devicetree" support – is required by `BLK_NVMEM`. I already know `CONFIG_OF` is commonly enabled on ARM and ARM64 architectures, and sometimes on x86 architectures. I don't *have* to explicitly specify `OF` unless I want to customize its settings, because the system usually handles this. If I explicitly specify `BLK_NVMEM`, the testing system will try to enable it and its dependancies.

To confirm this, I should go and examine `of_nvmem_layout_get_container` in the source code. Let me check the specifics for `drivers/nvmem/layouts.c` to see if that reinforces this conclusion.



12/2 2026/07/01 23:33 tool grepper
0m Args:
{
  "Expression": "of_nvmem_layout_get_container"
}

Results:
{
  "Output": "drivers/nvmem/core.c=843=static int nvmem_add_cells_from_fixed_layout(struct nvmem_device *nvmem)\n--\ndrivers/nvmem/core.c-847-\ndrivers/nvmem/core.c:848:\tlayout_np = of_nvmem_layout_get_container(nvmem);\ndrivers/nvmem/core.c-849-\tif (!layout_np)\n--\ndrivers/nvmem/layouts.c=133=static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,\n--\ndrivers/nvmem/layouts.c-167-\ndrivers/nvmem/layouts.c:168:struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)\ndrivers/nvmem/layouts.c-169-{\n--\ndrivers/nvmem/layouts.c-182-}\ndrivers/nvmem/layouts.c:183:EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);\ndrivers/nvmem/layouts.c-184-\n--\ndrivers/nvmem/layouts.c=189=int nvmem_populate_layout(struct nvmem_device *nvmem)\n--\ndrivers/nvmem/layouts.c-193-\ndrivers/nvmem/layouts.c:194:\tlayout_dn = of_nvmem_layout_get_container(nvmem);\ndrivers/nvmem/layouts.c-195-\tif (!layout_dn)\n--\ndrivers/nvmem/layouts/onie-tlv.c=98=static int onie_tlv_add_cells(struct device *dev, struct nvmem_device *nvmem,\n--\ndrivers/nvmem/layouts/onie-tlv.c-107-\ndrivers/nvmem/layouts/onie-tlv.c:108:\tlayout = of_nvmem_layout_get_container(nvmem);\ndrivers/nvmem/layouts/onie-tlv.c-109-\tif (!layout)\n--\ndrivers/nvmem/layouts/sl28vpd.c=83=static int sl28vpd_add_cells(struct nvmem_layout *layout)\n--\ndrivers/nvmem/layouts/sl28vpd.c-113-\ndrivers/nvmem/layouts/sl28vpd.c:114:\tlayout_np = of_nvmem_layout_get_container(nvmem);\ndrivers/nvmem/layouts/sl28vpd.c-115-\tif (!layout_np)\n--\ninclude/linux/nvmem-provider.h=215=static inline void nvmem_layout_unregister(struct nvmem_layout *layout) {}\n--\ninclude/linux/nvmem-provider.h-221-/**\ninclude/linux/nvmem-provider.h:222: * of_nvmem_layout_get_container() - Get OF node of layout container\ninclude/linux/nvmem-provider.h-223- *\n--\ninclude/linux/nvmem-provider.h-228- */\ninclude/linux/nvmem-provider.h:229:struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem);\ninclude/linux/nvmem-provider.h-230-\n--\ninclude/linux/nvmem-provider.h-232-\ninclude/linux/nvmem-provider.h:233:static inline struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)\ninclude/linux/nvmem-provider.h-234-{\n"
}

13/2 2026/07/01 23:33 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 15415
							output: 247
							thoughts: 599
						

Thoughts:
**Analyzing the Functional Impact of this NVMEM Patch**

Okay, let's break down this patch. My immediate thought is that it's introducing some interesting functional changes, so fuzzing is definitely warranted. Specifically, the patch is modifying `of_nvmem_layout_get_container` to directly support `fixed-layout` on the NVMEM of_node. This is a crucial area of modification, right off the bat.

To be thorough, I need to list the key functions or "focus symbols" that are affected. Here's what jumps out at me: `blk_nvmem_reg_read`, `blk_nvmem_add`, `blk_nvmem_del`, `hci_dev_get_bd_addr_from_nvmem`, `of_get_nvmem_eui48`, and of course `of_nvmem_layout_get_container` - this one is at the heart of the changes. I'll also add `qca_check_bdaddr`, since it's being modified to set the new quirks.

From a configuration perspective, it looks like `BLK_NVMEM` and `BT_QCA` are going to be critical. Given that this is working with NVMEM, I'll need to enable `NVMEM` as well. Might as well include `OF`, since the patch is touching the device tree.

The reasoning here is that the patch introduces a new block device NVMEM provider (`BLK_NVMEM`). This will allow block devices or partitions to act as NVMEM providers. It also adds the ability to retrieve Bluetooth Device Addresses (BD_ADDR) and MAC addresses from NVMEM cells (`of_get_nvmem_eui48`, `hci_dev_get_bd_addr_from_nvmem`), and the core NVMEM layout container logic is being modified. So it's a ripple effect through the block, NVMEM, and Bluetooth subsystems. This all screams "fuzz me!"

Let's double-check some of these functions to be certain. `hci_dev_get_bd_addr_from_nvmem` is static, but Syzkaller can still fuzz it if it's reachable. I see that `of_get_nvmem_eui48` is exported. `blk_nvmem_reg_read` is static, `blk_nvmem_add` is exported, `blk_nvmem_del` is exported, and `of_nvmem_layout_get_container` is exported too. Good. Seems like the surface area is pretty well defined. I've got a clear plan now: enable those configs, make sure the focus symbols are included in the fuzzing configuration, and get ready to throw some test cases at this.



14/2 2026/07/01 23:33 tool set-results
0m Args:
{
  "EnableConfigs": [
    "BLK_NVMEM",
    "BT_QCA",
    "NVMEM"
  ],
  "FocusSymbols": [
    "blk_nvmem_reg_read",
    "blk_nvmem_add",
    "blk_nvmem_del",
    "hci_dev_get_bd_addr_from_nvmem",
    "of_get_nvmem_eui48",
    "of_nvmem_layout_get_container",
    "qca_check_bdaddr"
  ],
  "Reasoning": "The patch introduces a new block device NVMEM provider (`BLK_NVMEM`), allowing block devices or partitions to act as NVMEM providers. It also adds functionality to retrieve Bluetooth Device Addresses (BD_ADDR) and MAC addresses from NVMEM cells (`of_get_nvmem_eui48`, `hci_dev_get_bd_addr_from_nvmem`), and modifies the NVMEM layout container logic. These are functional changes to the block, NVMEM, and Bluetooth subsystems that should be fuzzed.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "BLK_NVMEM",
    "BT_QCA",
    "NVMEM"
  ],
  "FocusSymbols": [
    "blk_nvmem_reg_read",
    "blk_nvmem_add",
    "blk_nvmem_del",
    "hci_dev_get_bd_addr_from_nvmem",
    "of_get_nvmem_eui48",
    "of_nvmem_layout_get_container",
    "qca_check_bdaddr"
  ],
  "Reasoning": "The patch introduces a new block device NVMEM provider (`BLK_NVMEM`), allowing block devices or partitions to act as NVMEM providers. It also adds functionality to retrieve Bluetooth Device Addresses (BD_ADDR) and MAC addresses from NVMEM cells (`of_get_nvmem_eui48`, `hci_dev_get_bd_addr_from_nvmem`), and modifies the NVMEM layout container logic. These are functional changes to the block, NVMEM, and Bluetooth subsystems that should be fuzzed.",
  "WorthFuzzing": true
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)