FROMLIST: firmware: arm_scmi: introduce new devres notification ops

Expose to the SCMI drivers a new alternative devres managed notifications
API based on protocol handles.

All drivers still keep using the old API, no functional change.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>

Bug: 171409184
Link: https://lore.kernel.org/linux-arm-kernel/20210202221555.41167-1-cristian.marussi@arm.com/
Change-Id: I3867be1ada472e5d09335cb8be25cbcac84763b1
Signed-off-by: Rishabh Bhatnagar <quic_rishabhb@quicinc.com>
This commit is contained in:
Cristian Marussi 2021-02-02 22:15:24 +00:00 committed by Todd Kjos
parent d25dc33d27
commit 0c203b198e
2 changed files with 137 additions and 1 deletions

View File

@ -1408,6 +1408,127 @@ static int scmi_unregister_notifier(const struct scmi_handle *handle,
return 0;
}
struct scmi_notifier_devres {
const struct scmi_handle *handle;
u8 proto_id;
u8 evt_id;
u32 __src_id;
u32 *src_id;
struct notifier_block *nb;
};
static void scmi_devm_release_notifier(struct device *dev, void *res)
{
struct scmi_notifier_devres *dres = res;
scmi_unregister_notifier(dres->handle, dres->proto_id, dres->evt_id,
dres->src_id, dres->nb);
}
/**
* scmi_devm_register_notifier() - Managed registration of a notifier_block
* for an event
* @sdev: A reference to an scmi_device whose embedded struct device is to
* be used for devres accounting.
* @proto_id: Protocol ID
* @evt_id: Event ID
* @src_id: Source ID, when NULL register for events coming form ALL possible
* sources
* @nb: A standard notifier block to register for the specified event
*
* Generic devres managed helper to register a notifier_block against a
* protocol event.
*/
static int scmi_devm_register_notifier(struct scmi_device *sdev,
u8 proto_id, u8 evt_id, u32 *src_id,
struct notifier_block *nb)
{
int ret;
struct scmi_notifier_devres *dres;
dres = devres_alloc(scmi_devm_release_notifier,
sizeof(*dres), GFP_KERNEL);
if (!dres)
return -ENOMEM;
ret = scmi_register_notifier(sdev->handle, proto_id,
evt_id, src_id, nb);
if (ret) {
devres_free(dres);
return ret;
}
dres->handle = sdev->handle;
dres->proto_id = proto_id;
dres->evt_id = evt_id;
dres->nb = nb;
if (src_id) {
dres->__src_id = *src_id;
dres->src_id = &dres->__src_id;
} else {
dres->src_id = NULL;
}
devres_add(&sdev->dev, dres);
return ret;
}
static int scmi_devm_notifier_match(struct device *dev, void *res, void *data)
{
struct scmi_notifier_devres *dres = res;
struct scmi_notifier_devres *xres = data;
if (WARN_ON(!dres || !xres))
return 0;
return dres->proto_id == xres->proto_id &&
dres->evt_id == xres->evt_id &&
dres->nb == xres->nb &&
((!dres->src_id && !xres->src_id) ||
(dres->src_id && xres->src_id &&
dres->__src_id == xres->__src_id));
}
/**
* scmi_devm_unregister_notifier() - Managed un-registration of a
* notifier_block for an event
* @sdev: A reference to an scmi_device whose embedded struct device is to
* be used for devres accounting.
* @proto_id: Protocol ID
* @evt_id: Event ID
* @src_id: Source ID, when NULL register for events coming form ALL possible
* sources
* @nb: A standard notifier block to register for the specified event
*
* Generic devres managed helper to explicitly un-register a notifier_block
* against a protocol event, which was previously registered using the above
* @scmi_devm_register_notifier.
*/
static int scmi_devm_unregister_notifier(struct scmi_device *sdev,
u8 proto_id, u8 evt_id, u32 *src_id,
struct notifier_block *nb)
{
int ret;
struct scmi_notifier_devres dres;
dres.handle = sdev->handle;
dres.proto_id = proto_id;
dres.evt_id = evt_id;
if (src_id) {
dres.__src_id = *src_id;
dres.src_id = &dres.__src_id;
} else {
dres.src_id = NULL;
}
ret = devres_release(&sdev->dev, scmi_devm_release_notifier,
scmi_devm_notifier_match, &dres);
WARN_ON(ret);
return ret;
}
/**
* scmi_protocols_late_init() - Worker for late initialization
* @work: The work item to use associated to the proper SCMI instance
@ -1465,6 +1586,8 @@ static void scmi_protocols_late_init(struct work_struct *work)
* directly from an scmi_driver to register its own notifiers.
*/
static const struct scmi_notify_ops notify_ops = {
.devm_register_event_notifier = scmi_devm_register_notifier,
.devm_unregister_event_notifier = scmi_devm_unregister_notifier,
.register_event_notifier = scmi_register_notifier,
.unregister_event_notifier = scmi_unregister_notifier,
};

View File

@ -544,6 +544,10 @@ struct scmi_voltage_ops {
/**
* struct scmi_notify_ops - represents notifications' operations provided by
* SCMI core
* @devm_register_event_notifier: Managed registration of a notifier_block for
* the requested event
* @devm_unregister_event_notifier: Managed unregistration of a notifier_block
* for the requested event
* @register_event_notifier: Register a notifier_block for the requested event
* @unregister_event_notifier: Unregister a notifier_block for the requested
* event
@ -553,7 +557,9 @@ struct scmi_voltage_ops {
* tuple: (proto_id, evt_id, src_id) using the provided register/unregister
* interface where:
*
* @handle: The handle identifying the platform instance to use
* @sdev: The scmi_device to use when calling the devres managed ops devm_
* @handle: The handle identifying the platform instance to use, when not
* calling the managed ops devm_
* @proto_id: The protocol ID as in SCMI Specification
* @evt_id: The message ID of the desired event as in SCMI Specification
* @src_id: A pointer to the desired source ID if different sources are
@ -576,6 +582,13 @@ struct scmi_voltage_ops {
* @report: A custom struct describing the specific event delivered
*/
struct scmi_notify_ops {
int (*devm_register_event_notifier)(struct scmi_device *sdev,
u8 proto_id, u8 evt_id, u32 *src_id,
struct notifier_block *nb);
int (*devm_unregister_event_notifier)(struct scmi_device *sdev,
u8 proto_id, u8 evt_id,
u32 *src_id,
struct notifier_block *nb);
int (*register_event_notifier)(const struct scmi_handle *handle,
u8 proto_id, u8 evt_id, u32 *src_id,
struct notifier_block *nb);