Skip to content

Commit

Permalink
firmware: arm_scmi: Refactor events registration
Browse files Browse the repository at this point in the history
Add a new refactored protocol events registration helper and invoke it
from the centralized initialization process triggered by get_ops() and
friends.

Also add a `get_num_sources` as a new optional callback amongst protocol
events operations. Finally remove events registration call-sites from
within the legacy protocol init routines.

Link: https://lore.kernel.org/r/[email protected]
Tested-by: Florian Fainelli <[email protected]>
Signed-off-by: Cristian Marussi <[email protected]>
Signed-off-by: Sudeep Holla <[email protected]>
  • Loading branch information
freefall75 authored and sudeep-holla committed Mar 29, 2021
1 parent 5ad3d1c commit 533c709
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 75 deletions.
15 changes: 9 additions & 6 deletions drivers/firmware/arm_scmi/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,14 @@ static const struct scmi_event_ops base_event_ops = {
.fill_custom_report = scmi_base_fill_custom_report,
};

static const struct scmi_protocol_events base_protocol_events = {
.queue_sz = 4 * SCMI_PROTO_QUEUE_SZ,
.ops = &base_event_ops,
.evts = base_events,
.num_events = ARRAY_SIZE(base_events),
.num_sources = SCMI_BASE_NUM_SOURCES,
};

int scmi_base_protocol_init(struct scmi_handle *h)
{
int id, ret;
Expand Down Expand Up @@ -352,12 +360,6 @@ int scmi_base_protocol_init(struct scmi_handle *h)
dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols,
rev->num_agents);

scmi_register_protocol_events(handle, SCMI_PROTOCOL_BASE,
(4 * SCMI_PROTO_QUEUE_SZ),
&base_event_ops, base_events,
ARRAY_SIZE(base_events),
SCMI_BASE_NUM_SOURCES);

for (id = 0; id < rev->num_agents; id++) {
scmi_base_discover_agent_get(handle, id, name);
dev_dbg(dev, "Agent %d: %s\n", id, name);
Expand All @@ -370,6 +372,7 @@ static const struct scmi_protocol scmi_base = {
.id = SCMI_PROTOCOL_BASE,
.init = &scmi_base_protocol_init,
.ops = NULL,
.events = &base_protocol_events,
};

DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base)
2 changes: 2 additions & 0 deletions drivers/firmware/arm_scmi/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,15 @@ typedef int (*scmi_prot_init_fn_t)(struct scmi_handle *);
* @instance_deinit: Optional protocol de-initialization function.
* @ops: Optional reference to the operations provided by the protocol and
* exposed in scmi_protocol.h.
* @events: An optional reference to the events supported by this protocol.
*/
struct scmi_protocol {
const u8 id;
const scmi_prot_init_fn_t init;
const scmi_prot_init_fn_t instance_init;
const scmi_prot_init_fn_t instance_deinit;
const void *ops;
const struct scmi_protocol_events *events;
};

int __init scmi_bus_init(void);
Expand Down
16 changes: 16 additions & 0 deletions drivers/firmware/arm_scmi/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,19 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
if (ret != proto->id)
goto clean;

/*
* Warn but ignore events registration errors since we do not want
* to skip whole protocols if their notifications are messed up.
*/
if (pi->proto->events) {
ret = scmi_register_protocol_events(handle, pi->proto->id,
pi->proto->events);
if (ret)
dev_warn(handle->dev,
"Protocol:%X - Events Registration Failed - err:%d\n",
pi->proto->id, ret);
}

devres_close_group(handle->dev, pi->gid);
dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id);

Expand Down Expand Up @@ -719,6 +732,9 @@ void scmi_protocol_release(struct scmi_handle *handle, u8 protocol_id)
if (refcount_dec_and_test(&pi->users)) {
void *gid = pi->gid;

if (pi->proto->events)
scmi_deregister_protocol_events(handle, protocol_id);

if (pi->proto->instance_deinit)
pi->proto->instance_deinit(handle);

Expand Down
88 changes: 56 additions & 32 deletions drivers/firmware/arm_scmi/notify.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/*
* System Control and Management Interface (SCMI) Notification support
*
* Copyright (C) 2020 ARM Ltd.
* Copyright (C) 2020-2021 ARM Ltd.
*/
/**
* DOC: Theory of operation
Expand Down Expand Up @@ -733,14 +733,9 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni,
/**
* scmi_register_protocol_events() - Register Protocol Events with the core
* @handle: The handle identifying the platform instance against which the
* the protocol's events are registered
* protocol's events are registered
* @proto_id: Protocol ID
* @queue_sz: Size in bytes of the associated queue to be allocated
* @ops: Protocol specific event-related operations
* @evt: Event descriptor array
* @num_events: Number of events in @evt array
* @num_sources: Number of possible sources for this protocol on this
* platform.
* @ee: A structure describing the events supported by this protocol.
*
* Used by SCMI Protocols initialization code to register with the notification
* core the list of supported events and their descriptors: takes care to
Expand All @@ -749,18 +744,18 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni,
*
* Return: 0 on Success
*/
int scmi_register_protocol_events(const struct scmi_handle *handle,
u8 proto_id, size_t queue_sz,
const struct scmi_event_ops *ops,
const struct scmi_event *evt, int num_events,
int num_sources)
int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
const struct scmi_protocol_events *ee)
{
int i;
unsigned int num_sources;
size_t payld_sz = 0;
struct scmi_registered_events_desc *pd;
struct scmi_notify_instance *ni;
const struct scmi_event *evt;

if (!ops || !evt)
if (!ee || !ee->ops || !ee->evts ||
(!ee->num_sources && !ee->ops->get_num_sources))
return -EINVAL;

/* Ensure notify_priv is updated */
Expand All @@ -769,40 +764,49 @@ int scmi_register_protocol_events(const struct scmi_handle *handle,
return -ENOMEM;
ni = handle->notify_priv;

/* Attach to the notification main devres group */
if (!devres_open_group(ni->handle->dev, ni->gid, GFP_KERNEL))
return -ENOMEM;
/* num_sources cannot be <= 0 */
if (ee->num_sources) {
num_sources = ee->num_sources;
} else {
int nsrc = ee->ops->get_num_sources(handle);

if (nsrc <= 0)
return -EINVAL;
num_sources = nsrc;
}

for (i = 0; i < num_events; i++)
evt = ee->evts;
for (i = 0; i < ee->num_events; i++)
payld_sz = max_t(size_t, payld_sz, evt[i].max_payld_sz);
payld_sz += sizeof(struct scmi_event_header);

pd = scmi_allocate_registered_events_desc(ni, proto_id, queue_sz,
payld_sz, num_events, ops);
pd = scmi_allocate_registered_events_desc(ni, proto_id, ee->queue_sz,
payld_sz, ee->num_events,
ee->ops);
if (IS_ERR(pd))
goto err;
return PTR_ERR(pd);

for (i = 0; i < num_events; i++, evt++) {
for (i = 0; i < ee->num_events; i++, evt++) {
struct scmi_registered_event *r_evt;

r_evt = devm_kzalloc(ni->handle->dev, sizeof(*r_evt),
GFP_KERNEL);
if (!r_evt)
goto err;
return -ENOMEM;
r_evt->proto = pd;
r_evt->evt = evt;

r_evt->sources = devm_kcalloc(ni->handle->dev, num_sources,
sizeof(refcount_t), GFP_KERNEL);
if (!r_evt->sources)
goto err;
return -ENOMEM;
r_evt->num_sources = num_sources;
mutex_init(&r_evt->sources_mtx);

r_evt->report = devm_kzalloc(ni->handle->dev,
evt->max_report_sz, GFP_KERNEL);
if (!r_evt->report)
goto err;
return -ENOMEM;

pd->registered_events[i] = r_evt;
/* Ensure events are updated */
Expand All @@ -816,22 +820,42 @@ int scmi_register_protocol_events(const struct scmi_handle *handle,
/* Ensure protocols are updated */
smp_wmb();

devres_close_group(ni->handle->dev, ni->gid);

/*
* Finalize any pending events' handler which could have been waiting
* for this protocol's events registration.
*/
schedule_work(&ni->init_work);

return 0;
}

err:
dev_warn(handle->dev, "Proto:%X - Registration Failed !\n", proto_id);
/* A failing protocol registration does not trigger full failure */
devres_close_group(ni->handle->dev, ni->gid);
/**
* scmi_deregister_protocol_events - Deregister protocol events with the core
* @handle: The handle identifying the platform instance against which the
* protocol's events are registered
* @proto_id: Protocol ID
*/
void scmi_deregister_protocol_events(const struct scmi_handle *handle,
u8 proto_id)
{
struct scmi_notify_instance *ni;
struct scmi_registered_events_desc *pd;

return -ENOMEM;
/* Ensure notify_priv is updated */
smp_rmb();
if (!handle->notify_priv)
return;

ni = handle->notify_priv;
pd = ni->registered_protocols[proto_id];
if (!pd)
return;

ni->registered_protocols[proto_id] = NULL;
/* Ensure protocols are updated */
smp_wmb();

cancel_work_sync(&pd->equeue.notify_work);
}

/**
Expand Down
35 changes: 29 additions & 6 deletions drivers/firmware/arm_scmi/notify.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* notification header file containing some definitions, structures
* and function prototypes related to SCMI Notification handling.
*
* Copyright (C) 2020 ARM Ltd.
* Copyright (C) 2020-2021 ARM Ltd.
*/
#ifndef _SCMI_NOTIFY_H
#define _SCMI_NOTIFY_H
Expand All @@ -31,8 +31,12 @@ struct scmi_event {
size_t max_report_sz;
};

struct scmi_protocol_handle;

/**
* struct scmi_event_ops - Protocol helpers called by the notification core.
* @get_num_sources: Returns the number of possible events' sources for this
* protocol
* @set_notify_enabled: Enable/disable the required evt_id/src_id notifications
* using the proper custom protocol commands.
* Return 0 on Success
Expand All @@ -46,6 +50,7 @@ struct scmi_event {
* process context.
*/
struct scmi_event_ops {
int (*get_num_sources)(const struct scmi_handle *handle);
int (*set_notify_enabled)(const struct scmi_handle *handle,
u8 evt_id, u32 src_id, bool enabled);
void *(*fill_custom_report)(const struct scmi_handle *handle,
Expand All @@ -54,14 +59,32 @@ struct scmi_event_ops {
void *report, u32 *src_id);
};

/**
* struct scmi_protocol_events - Per-protocol description of available events
* @queue_sz: Size in bytes of the per-protocol queue to use.
* @ops: Array of protocol-specific events operations.
* @evts: Array of supported protocol's events.
* @num_events: Number of supported protocol's events described in @evts.
* @num_sources: Number of protocol's sources, should be greater than 0; if not
* available at compile time, it will be provided at run-time via
* @get_num_sources.
*/
struct scmi_protocol_events {
size_t queue_sz;
const struct scmi_event_ops *ops;
const struct scmi_event *evts;
unsigned int num_events;
unsigned int num_sources;
};

int scmi_notification_init(struct scmi_handle *handle);
void scmi_notification_exit(struct scmi_handle *handle);

int scmi_register_protocol_events(const struct scmi_handle *handle,
u8 proto_id, size_t queue_sz,
const struct scmi_event_ops *ops,
const struct scmi_event *evt, int num_events,
int num_sources);
struct scmi_protocol_handle;
int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
const struct scmi_protocol_events *ee);
void scmi_deregister_protocol_events(const struct scmi_handle *handle,
u8 proto_id);
int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id,
const void *buf, size_t len, ktime_t ts);

Expand Down
25 changes: 19 additions & 6 deletions drivers/firmware/arm_scmi/perf.c
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,16 @@ static void *scmi_perf_fill_custom_report(const struct scmi_handle *handle,
return rep;
}

static int scmi_perf_get_num_sources(const struct scmi_handle *handle)
{
struct scmi_perf_info *pi = handle->perf_priv;

if (!pi)
return -EINVAL;

return pi->num_domains;
}

static const struct scmi_event perf_events[] = {
{
.id = SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED,
Expand All @@ -851,10 +861,18 @@ static const struct scmi_event perf_events[] = {
};

static const struct scmi_event_ops perf_event_ops = {
.get_num_sources = scmi_perf_get_num_sources,
.set_notify_enabled = scmi_perf_set_notify_enabled,
.fill_custom_report = scmi_perf_fill_custom_report,
};

static const struct scmi_protocol_events perf_protocol_events = {
.queue_sz = SCMI_PROTO_QUEUE_SZ,
.ops = &perf_event_ops,
.evts = perf_events,
.num_events = ARRAY_SIZE(perf_events),
};

static int scmi_perf_protocol_init(struct scmi_handle *handle)
{
int domain;
Expand Down Expand Up @@ -887,12 +905,6 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)
scmi_perf_domain_init_fc(handle, domain, &dom->fc_info);
}

scmi_register_protocol_events(handle,
SCMI_PROTOCOL_PERF, SCMI_PROTO_QUEUE_SZ,
&perf_event_ops, perf_events,
ARRAY_SIZE(perf_events),
pinfo->num_domains);

pinfo->version = version;
handle->perf_ops = &perf_ops;
handle->perf_priv = pinfo;
Expand All @@ -904,6 +916,7 @@ static const struct scmi_protocol scmi_perf = {
.id = SCMI_PROTOCOL_PERF,
.init = &scmi_perf_protocol_init,
.ops = &perf_ops,
.events = &perf_protocol_events,
};

DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(perf, scmi_perf)
Loading

0 comments on commit 533c709

Please sign in to comment.