From: Cristian Marussi Date: Sun, 10 May 2026 16:05:25 +0000 (+0100) Subject: firmware: arm_scmi: Add a generic transport supplier X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=ab6eb28a47d48c0c9edd885eca60fa5a39cc80b7;p=thirdparty%2Fkernel%2Flinux.git firmware: arm_scmi: Add a generic transport supplier 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 Link: https://patch.msgid.link/20260510160527.3537474-3-cristian.marussi@arm.com Signed-off-by: Sudeep Holla --- diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 9de8e4eb719a..b9723c105fc1 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 - : 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) \ { \