Commit 533c7095 authored by Cristian Marussi's avatar Cristian Marussi Committed by Sudeep Holla
Browse files

firmware: arm_scmi: Refactor events registration

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/20210316124903.35011-7-cristian.marussi@arm.com


Tested-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarCristian Marussi <cristian.marussi@arm.com>
Signed-off-by: default avatarSudeep Holla <sudeep.holla@arm.com>
parent 5ad3d1cf
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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 −0
Original line number Diff line number Diff line
@@ -226,6 +226,7 @@ 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;
@@ -233,6 +234,7 @@ struct scmi_protocol {
	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);
+16 −0
Original line number Diff line number Diff line
@@ -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);

@@ -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);

+56 −32
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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 */
@@ -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);

	for (i = 0; i < num_events; i++)
		if (nsrc <= 0)
			return -EINVAL;
		num_sources = nsrc;
	}

	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 */
@@ -816,8 +820,6 @@ 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.
@@ -825,13 +827,35 @@ int scmi_register_protocol_events(const struct scmi_handle *handle,
	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);
}

/**
+29 −6
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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,
@@ -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);

Loading