* [PATCH 1/2] mtd: spi-nor: drop fw_devlink suppliers below a flash that failed to probe
2026-11-11 12:01 [PATCH 0/2] mtd/nvmem: don't defer forever on absent NVMEM suppliers Manikandan Muralidharan
@ 2026-11-11 12:01 ` Manikandan Muralidharan
2026-11-11 12:01 ` [PATCH 2/2] nvmem: core: don't defer for a missing cell once the layout is bound Manikandan Muralidharan
1 sibling, 0 replies; 3+ messages in thread
From: Manikandan Muralidharan @ 2026-11-11 12:01 UTC (permalink / raw)
To: pratyush, mwalle, takahiro.kuwano, miquel.raynal, richard,
vigneshr, srini, linux-mtd, linux-kernel
Cc: manikandan.m
When a SPI NOR flash is not populated or not reachable, spi_nor_scan()
fails and nothing described below the flash node (the SFDP NVMEM device,
its nvmem-layout, partitions) is ever registered. fw_devlink still holds
links from consumers of those nodes, so a consumer such as an Ethernet
MAC whose "nvmem-cells" points at the SFDP EUI-48 cell waits for its
supplier forever and is never probed:
platform f8008000.ethernet: deferred probe pending: platform: wait for
supplier /ahb/apb/spi@f0024000/flash@0/sfdp/nvmem-layout/mac-address
On a permanent spi_nor_scan() failure, call
fw_devlink_purge_absent_suppliers() on each child of the flash node. It
marks the nodes that never became devices with FWNODE_FLAG_NOT_DEVICE
and drops their consumer links, so the consumer is probed.
The consumer then probes, but of_nvmem_cell_get() still returns
-EPROBE_DEFER because nvmem_device_match() does not find a device for
the SFDP node. When fw_devlink has marked that node FWNODE_FLAG_NOT_DEVICE,
it will never become a device, so return -ENOENT instead. The consumer
can then fall back, e.g. macb uses a random MAC address.
Signed-off-by: Manikandan Muralidharan <manikandan.m@microchip.com>
---
drivers/mtd/spi-nor/core.c | 26 +++++++++++++++++++++++++-
drivers/nvmem/core.c | 13 ++++++++++++-
2 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index a034dce7c839..57faab89f5af 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -12,6 +12,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/fwnode.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
@@ -3624,6 +3625,25 @@ static int spi_nor_create_write_dirmap(struct spi_nor *nor)
return PTR_ERR_OR_ZERO(nor->dirmap.wdesc);
}
+/**
+ * spi_nor_purge_absent_suppliers() - drop fw_devlink links below a missing
+ * flash
+ * @dev: pointer to the flash 'struct device'
+ *
+ * When the flash cannot be probed (e.g. it is not populated or not
+ * reachable), nothing described below its node, such as the SFDP NVMEM
+ * device or the partitions, is ever registered. Mark those nodes as never
+ * becoming devices and drop their consumer links, so that consumers such as
+ * an Ethernet MAC using an NVMEM cell are not deferred forever.
+ */
+static void spi_nor_purge_absent_suppliers(struct device *dev)
+{
+ struct fwnode_handle *child;
+
+ device_for_each_child_node(dev, child)
+ fw_devlink_purge_absent_suppliers(child);
+}
+
static int spi_nor_probe(struct spi_mem *spimem)
{
struct spi_device *spi = spimem->spi;
@@ -3672,8 +3692,12 @@ static int spi_nor_probe(struct spi_mem *spimem)
flash_name = spi->modalias;
ret = spi_nor_scan(nor, flash_name, &hwcaps);
- if (ret)
+ if (ret) {
+ /* A deferred probe (e.g. on the reset GPIO) may still succeed. */
+ if (ret != -EPROBE_DEFER)
+ spi_nor_purge_absent_suppliers(dev);
return ret;
+ }
spi_nor_debugfs_register(nor);
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 2e07f95de7ff..be3a05150085 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -10,6 +10,7 @@
#include <linux/device.h>
#include <linux/export.h>
#include <linux/fs.h>
+#include <linux/fwnode.h>
#include <linux/idr.h>
#include <linux/init.h>
#include <linux/kref.h>
@@ -1458,11 +1459,21 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
}
nvmem = nvmem_device_match(nvmem_np, device_match_of_node);
- of_node_put(nvmem_np);
if (IS_ERR(nvmem)) {
+ /*
+ * fw_devlink marks a node that will never become a device,
+ * either because its parent failed to probe or because the
+ * parent bound without registering it. Don't defer for it.
+ */
+ if (PTR_ERR(nvmem) == -EPROBE_DEFER &&
+ fwnode_test_flag(of_fwnode_handle(nvmem_np),
+ FWNODE_FLAG_NOT_DEVICE))
+ nvmem = ERR_PTR(-ENOENT);
+ of_node_put(nvmem_np);
of_node_put(cell_np);
return ERR_CAST(nvmem);
}
+ of_node_put(nvmem_np);
ret = nvmem_layout_module_get_optional(nvmem);
if (ret) {
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH 2/2] nvmem: core: don't defer for a missing cell once the layout is bound
2026-11-11 12:01 [PATCH 0/2] mtd/nvmem: don't defer forever on absent NVMEM suppliers Manikandan Muralidharan
2026-11-11 12:01 ` [PATCH 1/2] mtd: spi-nor: drop fw_devlink suppliers below a flash that failed to probe Manikandan Muralidharan
@ 2026-11-11 12:01 ` Manikandan Muralidharan
1 sibling, 0 replies; 3+ messages in thread
From: Manikandan Muralidharan @ 2026-11-11 12:01 UTC (permalink / raw)
To: pratyush, mwalle, takahiro.kuwano, miquel.raynal, richard,
vigneshr, srini, linux-mtd, linux-kernel
Cc: manikandan.m
of_nvmem_cell_get() returns -EPROBE_DEFER whenever a requested cell is
not found and the nvmem device has a layout, assuming the layout has not
added its cells yet. A layout may add none, e.g. when the data the cell
describes is not programmed on the device. The layout is then bound but
the cell is never going to show up, and the consumer is deferred forever
instead of falling back.
Only defer while the layout device is not bound yet, and return -ENOENT
once it is, so that a consumer such as an Ethernet MAC can fall back to a
random address.
Signed-off-by: Manikandan Muralidharan <manikandan.m@microchip.com>
---
drivers/nvmem/core.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index be3a05150085..f34a35a04e55 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -1403,6 +1403,31 @@ static int nvmem_layout_module_get_optional(struct nvmem_device *nvmem)
return 0;
}
+/**
+ * nvmem_layout_pending() - Check whether a layout may still add cells
+ * @nvmem: nvmem device the layout belongs to
+ *
+ * A layout adds its cells from its probe. Once the layout device is bound,
+ * a cell that is still missing is never going to show up.
+ *
+ * Return: true if @nvmem has a layout that is not bound yet, false otherwise.
+ */
+static bool nvmem_layout_pending(struct nvmem_device *nvmem)
+{
+ struct device *dev;
+ bool bound;
+
+ if (!nvmem->layout)
+ return false;
+
+ dev = &nvmem->layout->dev;
+ device_lock(dev);
+ bound = device_is_bound(dev);
+ device_unlock(dev);
+
+ return !bound;
+}
+
/**
* of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
*
@@ -1486,7 +1511,7 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
of_node_put(cell_np);
if (!cell_entry) {
nvmem_layout_module_put(nvmem);
- ret = nvmem->layout ? -EPROBE_DEFER : -ENOENT;
+ ret = nvmem_layout_pending(nvmem) ? -EPROBE_DEFER : -ENOENT;
nvmem_device_put(nvmem);
return ERR_PTR(ret);
}
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread