blob: e2f21da5e069861204bed95d165eb0599615c395 [file] [log] [blame]
Julian Hall2dcd69c2020-11-23 18:05:04 +01001/*
julhal01c3f4e9a2020-12-15 13:39:01 +00002 * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
Julian Hall2dcd69c2020-11-23 18:05:04 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "service_provider.h"
8#include <protocols/rpc/common/packed-c/status.h>
9#include <stddef.h>
10
11static const struct service_handler *find_handler(const struct service_provider *sp,
julhal01c3f4e9a2020-12-15 13:39:01 +000012 uint32_t opcode)
Julian Hall2dcd69c2020-11-23 18:05:04 +010013{
14 const struct service_handler *handler = NULL;
Julian Hall2dcd69c2020-11-23 18:05:04 +010015
Julian Hall65ff9052021-07-27 09:08:32 +010016 if ((opcode >= sp->opcode_range_lo) && (opcode <= sp->opcode_range_hi)) {
17
18 size_t index = 0;
19
Julian Hall2dcd69c2020-11-23 18:05:04 +010020 while (index < sp->num_handlers) {
21 if (service_handler_get_opcode(&sp->handlers[index]) == opcode) {
22 handler = &sp->handlers[index];
23 break;
24 }
25 ++index;
26 }
27 }
28
29 return handler;
30}
31
Julian Hall65ff9052021-07-27 09:08:32 +010032static void set_opcode_range(struct service_provider *sp)
33{
34 uint32_t lo = UINT32_MAX;
35 uint32_t hi = 0;
36
37 /* Determine opcode range so that this service may be skipped
38 * without having to iterate over all handlers. This reduces
39 * the time to find a qualifying handler when multiple service
40 * providers are chained.
41 */
42 for (size_t index = 0; index < sp->num_handlers; index++) {
43
44 uint32_t opcode = service_handler_get_opcode(&sp->handlers[index]);
45
46 if (opcode < lo) lo = opcode;
47 if (opcode > hi) hi = opcode;
48 }
49
50 sp->opcode_range_lo = lo;
51 sp->opcode_range_hi = hi;
52}
53
julhal01c3f4e9a2020-12-15 13:39:01 +000054static rpc_status_t receive(struct rpc_interface *rpc_iface, struct call_req *req)
Julian Hall2dcd69c2020-11-23 18:05:04 +010055{
56 rpc_status_t rpc_status;
57 struct service_provider *sp = NULL;
58 const struct service_handler *handler = NULL;
59
julhal01c3f4e9a2020-12-15 13:39:01 +000060 sp = (struct service_provider*)((char*)rpc_iface - offsetof(struct service_provider, iface));
Julian Hall2dcd69c2020-11-23 18:05:04 +010061 handler = find_handler(sp, call_req_get_opcode(req));
62
julhal01c3f4e9a2020-12-15 13:39:01 +000063 if (handler) {
Julian Hall2dcd69c2020-11-23 18:05:04 +010064
julhal01c3f4e9a2020-12-15 13:39:01 +000065 rpc_status = service_handler_invoke(handler, rpc_iface->context, req);
66 }
67 else if (sp->successor) {
Julian Hall2dcd69c2020-11-23 18:05:04 +010068
julhal01c3f4e9a2020-12-15 13:39:01 +000069 rpc_status = rpc_interface_receive(sp->successor, req);
70 }
71 else {
72
73 rpc_status = TS_RPC_ERROR_INVALID_OPCODE;
74 }
Julian Hall2dcd69c2020-11-23 18:05:04 +010075
76 return rpc_status;
77}
78
79void service_provider_init(struct service_provider *sp, void *context,
julhal01c3f4e9a2020-12-15 13:39:01 +000080 const struct service_handler *handlers,
81 size_t num_handlers)
Julian Hall2dcd69c2020-11-23 18:05:04 +010082{
julhal01c3f4e9a2020-12-15 13:39:01 +000083 sp->iface.receive = receive;
84 sp->iface.context = context;
Julian Hall2dcd69c2020-11-23 18:05:04 +010085
86 sp->handlers = handlers;
87 sp->num_handlers = num_handlers;
88
julhal01c3f4e9a2020-12-15 13:39:01 +000089 sp->successor = NULL;
Julian Hall65ff9052021-07-27 09:08:32 +010090
91 set_opcode_range(sp);
Julian Hall2dcd69c2020-11-23 18:05:04 +010092}
Julian Hall13e76952021-07-13 12:17:09 +010093
94void service_provider_extend(struct service_provider *context,
95 struct service_provider *sub_provider)
96{
97 sub_provider->successor = context->successor;
98 context->successor = &sub_provider->iface;
99}