mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
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 <cristian.marussi@arm.com> Link: https://patch.msgid.link/20260510160527.3537474-3-cristian.marussi@arm.com Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
This commit is contained in:
parent
9dfae7d2ed
commit
ab6eb28a47
|
|
@ -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) \
|
||||
{ \
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user