mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-07 16:11:43 +00:00
Merge pull request #1132 from jeenu-arm/pubsub
Publish and Subscribe framework
This commit is contained in:
@@ -62,6 +62,10 @@ SECTIONS
|
||||
KEEP(*(cpu_ops))
|
||||
__CPU_OPS_END__ = .;
|
||||
|
||||
/* Place pubsub sections for events */
|
||||
. = ALIGN(8);
|
||||
#include <pubsub_events.h>
|
||||
|
||||
. = NEXT(4096);
|
||||
__RODATA_END__ = .;
|
||||
} >RAM
|
||||
@@ -95,6 +99,10 @@ SECTIONS
|
||||
KEEP(*(cpu_ops))
|
||||
__CPU_OPS_END__ = .;
|
||||
|
||||
/* Place pubsub sections for events */
|
||||
. = ALIGN(8);
|
||||
#include <pubsub_events.h>
|
||||
|
||||
*(.vectors)
|
||||
__RO_END_UNALIGNED__ = .;
|
||||
/*
|
||||
|
||||
@@ -50,6 +50,10 @@ SECTIONS
|
||||
KEEP(*(cpu_ops))
|
||||
__CPU_OPS_END__ = .;
|
||||
|
||||
/* Place pubsub sections for events */
|
||||
. = ALIGN(8);
|
||||
#include <pubsub_events.h>
|
||||
|
||||
. = NEXT(4096);
|
||||
__RODATA_END__ = .;
|
||||
} >RAM
|
||||
@@ -75,6 +79,10 @@ SECTIONS
|
||||
KEEP(*(cpu_ops))
|
||||
__CPU_OPS_END__ = .;
|
||||
|
||||
/* Place pubsub sections for events */
|
||||
. = ALIGN(8);
|
||||
#include <pubsub_events.h>
|
||||
|
||||
*(.vectors)
|
||||
__RO_END_UNALIGNED__ = .;
|
||||
|
||||
|
||||
@@ -2258,6 +2258,103 @@ should consider the trade-off between memory footprint and security.
|
||||
This build flag is disabled by default, minimising memory footprint. On ARM
|
||||
platforms, it is enabled.
|
||||
|
||||
Publish and Subscribe Framework
|
||||
-------------------------------
|
||||
|
||||
The Publish and Subscribe Framework allows EL3 components to define and publish
|
||||
events, to which other EL3 components can subscribe.
|
||||
|
||||
The following macros are provided by the framework:
|
||||
|
||||
- ``REGISTER_PUBSUB_EVENT(event)``: Defines an event, and takes one argument,
|
||||
the event name, which must be a valid C identifier. All calls to
|
||||
``REGISTER_PUBSUB_EVENT`` macro must be placed in the file
|
||||
``pubsub_events.h``.
|
||||
|
||||
- ``PUBLISH_EVENT_ARG(event, arg)``: Publishes a defined event, by iterating
|
||||
subscribed handlers and calling them in turn. The handlers will be passed the
|
||||
parameter ``arg``. The expected use-case is to broadcast an event.
|
||||
|
||||
- ``PUBLISH_EVENT(event)``: Like ``PUBLISH_EVENT_ARG``, except that the value
|
||||
``NULL`` is passed to subscribed handlers.
|
||||
|
||||
- ``SUBSCRIBE_TO_EVENT(event, handler)``: Registers the ``handler`` to
|
||||
subscribe to ``event``. The handler will be executed whenever the ``event``
|
||||
is published.
|
||||
|
||||
- ``for_each_subscriber(event, subscriber)``: Iterates through all handlers
|
||||
subscribed for ``event``. ``subscriber`` must be a local variable of type
|
||||
``pubsub_cb_t *``, and will point to each subscribed handler in turn during
|
||||
iteration. This macro can be used for those patterns that none of the
|
||||
``PUBLISH_EVENT_*()`` macros cover.
|
||||
|
||||
Publishing an event that wasn't defined using ``REGISTER_PUBSUB_EVENT`` will
|
||||
result in build error. Subscribing to an undefined event however won't.
|
||||
|
||||
Subscribed handlers must be of type ``pubsub_cb_t``, with following function
|
||||
signature:
|
||||
|
||||
::
|
||||
|
||||
typedef void* (*pubsub_cb_t)(const void *arg);
|
||||
|
||||
There may be arbitrary number of handlers registered to the same event. The
|
||||
order in which subscribed handlers are notified when that event is published is
|
||||
not defined. Subscribed handlers may be executed in any order; handlers should
|
||||
not assume any relative ordering amongst them.
|
||||
|
||||
Publishing an event on a PE will result in subscribed handlers executing on that
|
||||
PE only; it won't cause handlers to execute on a different PE.
|
||||
|
||||
Note that publishing an event on a PE blocks until all the subscribed handlers
|
||||
finish executing on the PE.
|
||||
|
||||
Publish and Subscribe Example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A publisher that wants to publish event ``foo`` would:
|
||||
|
||||
- Define the event ``foo`` in the ``pubsub_events.h``.
|
||||
|
||||
::
|
||||
|
||||
REGISTER_PUBSUB_EVENT(foo);
|
||||
|
||||
- Depending on the nature of event, use one of ``PUBLISH_EVENT_*()`` macros to
|
||||
publish the event at the appropriate path and time of execution.
|
||||
|
||||
A subscriber that wants to subscribe to event ``foo`` published above would
|
||||
implement:
|
||||
|
||||
::
|
||||
|
||||
void *foo_handler(const void *arg)
|
||||
{
|
||||
void *result;
|
||||
|
||||
/* Do handling ... */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SUBSCRIBE_TO_EVENT(foo, foo_handler);
|
||||
|
||||
Available Events
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
ARM Trusted Firmware core makes some events available by default. They're listed
|
||||
below, along with information as to when they're published, and the arguments
|
||||
passed to subscribed handlers.
|
||||
|
||||
Other EL3 components that are conditionally compiled in may make their own
|
||||
events available, but aren't documented here.
|
||||
|
||||
- ``psci_cpu_on_finish``
|
||||
|
||||
- When: Published on a PE after it's finished its power-up sequence.
|
||||
|
||||
- Argument: ``NULL``.
|
||||
|
||||
Performance Measurement Framework
|
||||
---------------------------------
|
||||
|
||||
|
||||
84
include/lib/el3_runtime/pubsub.h
Normal file
84
include/lib/el3_runtime/pubsub.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef __PUBSUB_H__
|
||||
#define __PUBSUB_H__
|
||||
|
||||
#define __pubsub_start_sym(event) __pubsub_##event##_start
|
||||
#define __pubsub_end_sym(event) __pubsub_##event##_end
|
||||
|
||||
#ifdef __LINKER__
|
||||
|
||||
/* For the linker ... */
|
||||
|
||||
#define __pubsub_section(event) __pubsub_##event
|
||||
|
||||
/*
|
||||
* REGISTER_PUBSUB_EVENT has a different definition between linker and compiler
|
||||
* contexts. In linker context, this collects pubsub sections for each event,
|
||||
* placing guard symbols around each.
|
||||
*/
|
||||
#define REGISTER_PUBSUB_EVENT(event) \
|
||||
__pubsub_start_sym(event) = .; \
|
||||
KEEP(*(__pubsub_section(event))); \
|
||||
__pubsub_end_sym(event) = .
|
||||
|
||||
#else /* __LINKER__ */
|
||||
|
||||
/* For the compiler ... */
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <cdefs.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define __pubsub_section(event) __section("__pubsub_" #event)
|
||||
|
||||
/*
|
||||
* In compiler context, REGISTER_PUBSUB_EVENT declares the per-event symbols
|
||||
* exported by the linker required for the other pubsub macros to work.
|
||||
*/
|
||||
#define REGISTER_PUBSUB_EVENT(event) \
|
||||
extern pubsub_cb_t __pubsub_start_sym(event)[]; \
|
||||
extern pubsub_cb_t __pubsub_end_sym(event)[]
|
||||
|
||||
/*
|
||||
* Have the function func called back when the specified event happens. This
|
||||
* macro places the function address into the pubsub section, which is picked up
|
||||
* and invoked by the invoke_pubsubs() function via. the PUBLISH_EVENT* macros.
|
||||
*/
|
||||
#define SUBSCRIBE_TO_EVENT(event, func) \
|
||||
pubsub_cb_t __cb_func_##func##event __pubsub_section(event) = func
|
||||
|
||||
/*
|
||||
* Iterate over subscribed handlers for a defined event. 'event' is the name of
|
||||
* the event, and 'subscriber' a local variable of type 'pubsub_cb_t *'.
|
||||
*/
|
||||
#define for_each_subscriber(event, subscriber) \
|
||||
for (subscriber = __pubsub_start_sym(event); \
|
||||
subscriber < __pubsub_end_sym(event); \
|
||||
subscriber++)
|
||||
|
||||
/*
|
||||
* Publish a defined event supplying an argument. All subscribed handlers are
|
||||
* invoked, but the return value of handlers are ignored for now.
|
||||
*/
|
||||
#define PUBLISH_EVENT_ARG(event, arg) \
|
||||
do { \
|
||||
pubsub_cb_t *subscriber; \
|
||||
for_each_subscriber(event, subscriber) { \
|
||||
(*subscriber)(arg); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Publish a defined event with NULL argument */
|
||||
#define PUBLISH_EVENT(event) PUBLISH_EVENT_ARG(event, NULL)
|
||||
|
||||
/* Subscriber callback type */
|
||||
typedef void* (*pubsub_cb_t)(const void *arg);
|
||||
|
||||
#endif /* __LINKER__ */
|
||||
#endif /* __PUBSUB_H__ */
|
||||
18
include/lib/el3_runtime/pubsub_events.h
Normal file
18
include/lib/el3_runtime/pubsub_events.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <pubsub.h>
|
||||
|
||||
/*
|
||||
* This file defines a list of pubsub events, declared using
|
||||
* REGISTER_PUBSUB_EVENT() macro.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Event published after a CPU has been powered up and finished its
|
||||
* initialization.
|
||||
*/
|
||||
REGISTER_PUBSUB_EVENT(psci_cpu_on_finish);
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <context_mgmt.h>
|
||||
#include <debug.h>
|
||||
#include <platform.h>
|
||||
#include <pubsub_events.h>
|
||||
#include <stddef.h>
|
||||
#include "psci_private.h"
|
||||
|
||||
@@ -188,6 +189,8 @@ void psci_cpu_on_finish(unsigned int cpu_idx,
|
||||
if (psci_spd_pm && psci_spd_pm->svc_on_finish)
|
||||
psci_spd_pm->svc_on_finish(0);
|
||||
|
||||
PUBLISH_EVENT(psci_cpu_on_finish);
|
||||
|
||||
/* Populate the mpidr field within the cpu node array */
|
||||
/* This needs to be done only once */
|
||||
psci_cpu_pd_nodes[cpu_idx].mpidr = read_mpidr() & MPIDR_AFFINITY_MASK;
|
||||
|
||||
Reference in New Issue
Block a user