[PATCH v2 2/4] firmware: arm_scmi: Add a generic transport supplier
Cristian Marussi
cristian.marussi at arm.com
Sun May 10 09:05:25 PDT 2026
Add the capability to define a common generic transport supplier which
embeds the logic needed to support one single unique instance of transport
supplier.
Signed-off-by: Cristian Marussi <cristian.marussi at arm.com>
---
drivers/firmware/arm_scmi/common.h | 111 +++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index af6f9f498e14..e2885173594a 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -502,6 +502,117 @@ struct scmi_transport {
const struct scmi_transport_handle *th;
};
+/**
+ * struct scmi_transport_supplier - Transport descriptor
+ * @mtx: A mutex to protect @available
+ * @available: A reference to an initialized transport device, when available.
+ * This reference is implicitly used to track the status of the
+ * supplier and it can cycle through the following 3 states:
+ * 1. NOT_READY - PTR_ERR(-EPROBE_DEFER): no supplier available;
+ * this is the transport initial state.
+ * 2. AVAILABLE - <supplier_dev>: a transport supplier has been
+ * initialized and it is available, ready to use.
+ * 3. BUSY _ PTR_ERR(-EBUSY): transport supplier is currently in use.
+ * @th: An embedded transport handle object that embeds the helpers
+ * implementing the above mentioned logic
+ *
+ * Note that this transport driver enforces single instance probing.
+ */
+struct scmi_transport_supplier {
+ /* Protect @available */
+ struct mutex mtx;
+ struct device *available;
+ const struct scmi_transport_handle th;
+};
+
+#define to_sup(t) container_of(t, struct scmi_transport_supplier, th)
+
+/**
+ * scmi_transport_supplier_put - A helper to dispose of a supplier
+ * @th: A reference to the transport handle to use
+ * @supplier: A reference to the device supplier to manage, cannot be NULL
+ * or ERR_PTR.
+ *
+ * Note that putting a supplier will have different effect based on the
+ * current state of scmi_transport_supplier.available:
+ * - NOT_READY/BUSY: @supplier will be set as the new available device: this
+ * can be used to made available a supplier OR stop using one.
+ * - AVAILABLE: if the @supplier we are disposing of matches the currently
+ * available one, roll back to NOT_READY state.
+ * Any other attempt to override an available supplier with a
+ * new one is rejected, effectively enforcing one single supplier.
+ *
+ * Return: 0 on Success, errno otherwise.
+ */
+static inline int
+scmi_transport_supplier_put(const struct scmi_transport_handle *th,
+ struct device *supplier)
+{
+ struct scmi_transport_supplier *sup = to_sup(th);
+
+ /* Nothing to do when the provided supplier was never real */
+ if (IS_ERR_OR_NULL(supplier))
+ return 0;
+
+ guard(mutex)(&sup->mtx);
+ switch (PTR_ERR_OR_ZERO(sup->available)) {
+ case -EPROBE_DEFER:
+ case -EBUSY:
+ sup->available = supplier;
+ break;
+ case 0:
+ /* Putting a supplier when in the AVAILABLE state causes a
+ * transition back to the NOT_READY state, BUT only if the
+ * supplier we are disposing of was exactly the device that was
+ * previously made readily available.
+ */
+ if (supplier != sup->available)
+ return -EINVAL;
+ sup->available = ERR_PTR(-EPROBE_DEFER);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * scmi_transport_supplier_get - A helper to get hold of a supplier
+ * @th: A reference to the transport handle to use
+ *
+ * Note that, trying to get a supplier device can return:
+ * - a ready to use supplier device, (subsequently made unavailable)
+ * - PTR_ERR(-EPROBE_DEFER): no supplier is available
+ * - PTR_ERR(-BUSY): supplier was already taken by a previous get
+ *
+ * This allows the probe to defer and wait when a possible device can
+ * be reasonably expected to appear.
+ *
+ * Return: a usable supplier device on Success or PTR_ERR on Failure.
+ */
+static inline struct device *
+scmi_transport_supplier_get(const struct scmi_transport_handle *th)
+{
+ struct scmi_transport_supplier *sup = to_sup(th);
+ struct device *supplier;
+
+ guard(mutex)(&sup->mtx);
+ supplier = sup->available;
+ if (!IS_ERR(sup->available))
+ sup->available = ERR_PTR(-EBUSY);
+
+ return supplier;
+}
+
+#define DEFINE_SCMI_TRANSPORT_SUPPLIER(__supplier) \
+struct scmi_transport_supplier __supplier = { \
+ .mtx = __MUTEX_INITIALIZER(__supplier.mtx), \
+ .available = INIT_ERR_PTR(-EPROBE_DEFER), \
+ .th.supplier_get = scmi_transport_supplier_get, \
+ .th.supplier_put = scmi_transport_supplier_put, \
+}
+
#define DEFINE_SCMI_TRANSPORT_DRIVER(__tag, __drv, __desc, __match, __core_ops)\
static void __tag##_dev_free(void *data) \
{ \
--
2.53.0
More information about the linux-arm-kernel
mailing list