1 /*
2  * Copyright (c) 2021, L&T Technology Services Ltd.
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <errno.h>
9 #include <openamp/rpmsg_rpc_client_server.h>
10 
11 #define LPERROR(format, ...) metal_log(METAL_LOG_ERROR, format, ##__VA_ARGS__)
12 
13 static int rpmsg_endpoint_server_cb(struct rpmsg_endpoint *, void *,
14 				    size_t, uint32_t, void *);
15 
rpmsg_rpc_server_init(struct rpmsg_rpc_svr * rpcs,struct rpmsg_device * rdev,const struct rpmsg_rpc_services * services,int len,rpmsg_ns_unbind_cb rpmsg_service_server_unbind)16 int rpmsg_rpc_server_init(struct rpmsg_rpc_svr *rpcs, struct rpmsg_device *rdev,
17 			  const struct rpmsg_rpc_services *services, int len,
18 			  rpmsg_ns_unbind_cb rpmsg_service_server_unbind)
19 {
20 	int ret;
21 
22 	rpcs->services = services;
23 	rpcs->n_services = len;
24 
25 	ret = rpmsg_create_ept(&rpcs->ept, rdev, RPMSG_RPC_SERVICE_NAME,
26 			       RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
27 			       rpmsg_endpoint_server_cb,
28 			       rpmsg_service_server_unbind);
29 	if (ret)
30 		return ret;
31 
32 	return ret;
33 }
34 
find_service(struct rpmsg_rpc_svr * rpcs,unsigned int id)35 static const struct rpmsg_rpc_services *find_service(struct rpmsg_rpc_svr *rpcs,
36 						     unsigned int id)
37 {
38 	const struct rpmsg_rpc_services *service;
39 
40 	for (unsigned int i = 0; i < rpcs->n_services; i++) {
41 		service = &rpcs->services[i];
42 
43 		if (service->id == id) {
44 			return service;
45 		}
46 	}
47 	return NULL;
48 }
49 
rpmsg_endpoint_server_cb(struct rpmsg_endpoint * ept,void * data,size_t len,uint32_t src,void * priv)50 static int rpmsg_endpoint_server_cb(struct rpmsg_endpoint *ept, void *data,
51 				    size_t len,
52 				    uint32_t src, void *priv)
53 {
54 	unsigned char buf[MAX_BUF_LEN];
55 	unsigned int id;
56 	const struct rpmsg_rpc_services *service;
57 	struct rpmsg_rpc_svr *rpcs;
58 	(void)priv;
59 	(void)src;
60 
61 	if (len > MAX_BUF_LEN)
62 		return -EINVAL;
63 
64 	rpcs = metal_container_of(ept, struct rpmsg_rpc_svr, ept);
65 
66 	memcpy(buf, data, len);
67 	id = *buf;
68 	service = find_service(rpcs, id);
69 
70 	if (service) {
71 		if (service->cb_function(buf, rpcs)) {
72 			LPERROR("Service failed at rpc id: %ld\r\n", id);
73 		}
74 	} else {
75 		LPERROR("Handling remote procedure call errors: rpc id %ld\r\n",
76 			id);
77 		rpmsg_rpc_server_send(rpcs, id, RPMSG_RPC_INVALID_ID, NULL, 0);
78 	}
79 	return RPMSG_SUCCESS;
80 }
81 
rpmsg_rpc_server_send(struct rpmsg_rpc_svr * rpcs,uint32_t rpc_id,int status,void * request_param,size_t param_size)82 int rpmsg_rpc_server_send(struct rpmsg_rpc_svr *rpcs, uint32_t rpc_id,
83 			  int status, void *request_param, size_t param_size)
84 {
85 	struct rpmsg_endpoint *ept = &rpcs->ept;
86 	struct rpmsg_rpc_answer msg;
87 
88 	if (!ept)
89 		return -EINVAL;
90 	if (param_size > (MAX_BUF_LEN - sizeof(msg.status)))
91 		return -EINVAL;
92 
93 	msg.id = rpc_id;
94 	msg.status = status;
95 	memcpy(msg.params, request_param, param_size);
96 
97 	return rpmsg_send(ept, &msg, MAX_FUNC_ID_LEN + param_size);
98 }
99