1 /*
2  * Copyright (c) 2014, Mentor Graphics Corporation
3  * All rights reserved.
4  * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
5  * Copyright (c) 2018 Linaro, Inc. All rights reserved.
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  */
9 
10 #include <internal/utilities.h>
11 #include <openamp/rpmsg.h>
12 #include <metal/alloc.h>
13 
14 #include "rpmsg_internal.h"
15 
16 /**
17  * @internal
18  *
19  * @brief rpmsg_get_address
20  *
21  * This function provides unique 32 bit address.
22  *
23  * @param bitmap	Bit map for addresses
24  * @param size		Size of bitmap
25  *
26  * @return A unique address
27  */
rpmsg_get_address(unsigned long * bitmap,unsigned int start,int size)28 static uint32_t rpmsg_get_address(unsigned long *bitmap, unsigned int start, int size)
29 {
30 	unsigned int addr = RPMSG_ADDR_ANY;
31 	unsigned int nextbit;
32 
33 	nextbit = metal_bitmap_next_clear_bit(bitmap, start, size);
34 	if (nextbit < (uint32_t)size) {
35 		addr = RPMSG_RESERVED_ADDRESSES + nextbit;
36 		metal_bitmap_set_bit(bitmap, nextbit);
37 	}
38 
39 	return addr;
40 }
41 
42 /**
43  * @internal
44  *
45  * @brief Frees the given address.
46  *
47  * @param bitmap	Bit map for addresses
48  * @param size		Size of bitmap
49  * @param addr		Address to free
50  */
rpmsg_release_address(unsigned long * bitmap,int size,int addr)51 static void rpmsg_release_address(unsigned long *bitmap, int size,
52 				  int addr)
53 {
54 	addr -= RPMSG_RESERVED_ADDRESSES;
55 	if (addr >= 0 && addr < size)
56 		metal_bitmap_clear_bit(bitmap, addr);
57 }
58 
59 /**
60  * @internal
61  *
62  * @brief Checks whether address is used or free.
63  *
64  * @param bitmap	Bit map for addresses
65  * @param size		Size of bitmap
66  * @param addr		Address to free
67  *
68  * @return TRUE/FALSE
69  */
rpmsg_is_address_set(unsigned long * bitmap,int size,int addr)70 static int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr)
71 {
72 	addr -= RPMSG_RESERVED_ADDRESSES;
73 	if (addr >= 0 && addr < size)
74 		return metal_bitmap_is_bit_set(bitmap, addr);
75 	else
76 		return RPMSG_ERR_PARAM;
77 }
78 
79 /**
80  * @internal
81  *
82  * @brief Marks the address as consumed.
83  *
84  * @param bitmap	Bit map for addresses
85  * @param size		Size of bitmap
86  * @param addr		Address to free
87  *
88  * @return 0 on success, otherwise error code
89  */
rpmsg_set_address(unsigned long * bitmap,int size,int addr)90 static int rpmsg_set_address(unsigned long *bitmap, int size, int addr)
91 {
92 	addr -= RPMSG_RESERVED_ADDRESSES;
93 	if (addr >= 0 && addr < size) {
94 		metal_bitmap_set_bit(bitmap, addr);
95 		return RPMSG_SUCCESS;
96 	} else {
97 		return RPMSG_ERR_PARAM;
98 	}
99 }
100 
rpmsg_ept_incref(struct rpmsg_endpoint * ept)101 void rpmsg_ept_incref(struct rpmsg_endpoint *ept)
102 {
103 	if (ept)
104 		ept->refcnt++;
105 }
106 
rpmsg_ept_decref(struct rpmsg_endpoint * ept)107 void rpmsg_ept_decref(struct rpmsg_endpoint *ept)
108 {
109 	if (ept) {
110 		ept->refcnt--;
111 		if (!ept->refcnt) {
112 			if (ept->release_cb)
113 				ept->release_cb(ept);
114 			else
115 				ept->rdev = NULL;
116 		}
117 	}
118 }
119 
rpmsg_send_offchannel_raw(struct rpmsg_endpoint * ept,uint32_t src,uint32_t dst,const void * data,int len,int wait)120 int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src,
121 			      uint32_t dst, const void *data, int len,
122 			      int wait)
123 {
124 	struct rpmsg_device *rdev;
125 
126 	if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY || len < 0)
127 		return RPMSG_ERR_PARAM;
128 
129 	rdev = ept->rdev;
130 
131 	if (rdev->ops.send_offchannel_raw)
132 		return rdev->ops.send_offchannel_raw(rdev, src, dst, data,
133 						     len, wait);
134 
135 	return RPMSG_ERR_PARAM;
136 }
137 
rpmsg_send_ns_message(struct rpmsg_endpoint * ept,unsigned long flags)138 int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags)
139 {
140 	struct rpmsg_ns_msg ns_msg;
141 	int ret;
142 
143 	ns_msg.flags = flags;
144 	ns_msg.addr = ept->addr;
145 	(void)safe_strcpy(ns_msg.name, sizeof(ns_msg.name), ept->name, sizeof(ept->name));
146 	ret = rpmsg_send_offchannel_raw(ept, ept->addr,
147 					RPMSG_NS_EPT_ADDR,
148 					&ns_msg, sizeof(ns_msg), true);
149 	if (ret < 0)
150 		return ret;
151 	else
152 		return RPMSG_SUCCESS;
153 }
154 
rpmsg_hold_rx_buffer(struct rpmsg_endpoint * ept,void * rxbuf)155 void rpmsg_hold_rx_buffer(struct rpmsg_endpoint *ept, void *rxbuf)
156 {
157 	struct rpmsg_device *rdev;
158 
159 	if (!ept || !ept->rdev || !rxbuf)
160 		return;
161 
162 	rdev = ept->rdev;
163 
164 	if (rdev->ops.hold_rx_buffer)
165 		rdev->ops.hold_rx_buffer(rdev, rxbuf);
166 }
167 
rpmsg_release_rx_buffer(struct rpmsg_endpoint * ept,void * rxbuf)168 void rpmsg_release_rx_buffer(struct rpmsg_endpoint *ept, void *rxbuf)
169 {
170 	struct rpmsg_device *rdev;
171 
172 	if (!ept || !ept->rdev || !rxbuf)
173 		return;
174 
175 	rdev = ept->rdev;
176 
177 	if (rdev->ops.release_rx_buffer)
178 		rdev->ops.release_rx_buffer(rdev, rxbuf);
179 }
180 
rpmsg_release_tx_buffer(struct rpmsg_endpoint * ept,void * buf)181 int rpmsg_release_tx_buffer(struct rpmsg_endpoint *ept, void *buf)
182 {
183 	struct rpmsg_device *rdev;
184 
185 	if (!ept || !ept->rdev || !buf)
186 		return RPMSG_ERR_PARAM;
187 
188 	rdev = ept->rdev;
189 
190 	if (rdev->ops.release_tx_buffer)
191 		return rdev->ops.release_tx_buffer(rdev, buf);
192 
193 	return RPMSG_ERR_PERM;
194 }
195 
rpmsg_get_tx_payload_buffer(struct rpmsg_endpoint * ept,uint32_t * len,int wait)196 void *rpmsg_get_tx_payload_buffer(struct rpmsg_endpoint *ept,
197 				  uint32_t *len, int wait)
198 {
199 	struct rpmsg_device *rdev;
200 
201 	if (!ept || !ept->rdev || !len)
202 		return NULL;
203 
204 	rdev = ept->rdev;
205 
206 	if (rdev->ops.get_tx_payload_buffer)
207 		return rdev->ops.get_tx_payload_buffer(rdev, len, wait);
208 
209 	return NULL;
210 }
211 
rpmsg_get_tx_buffer_size(struct rpmsg_endpoint * ept)212 int rpmsg_get_tx_buffer_size(struct rpmsg_endpoint *ept)
213 {
214 	struct rpmsg_device *rdev;
215 
216 	if (!ept || !ept->rdev)
217 		return RPMSG_ERR_PARAM;
218 
219 	rdev = ept->rdev;
220 
221 	if (rdev->ops.get_tx_buffer_size)
222 		return rdev->ops.get_tx_buffer_size(rdev);
223 
224 	return RPMSG_EOPNOTSUPP;
225 }
226 
rpmsg_get_rx_buffer_size(struct rpmsg_endpoint * ept)227 int rpmsg_get_rx_buffer_size(struct rpmsg_endpoint *ept)
228 {
229 	struct rpmsg_device *rdev;
230 
231 	if (!ept || !ept->rdev)
232 		return RPMSG_ERR_PARAM;
233 
234 	rdev = ept->rdev;
235 
236 	if (rdev->ops.get_rx_buffer_size)
237 		return rdev->ops.get_rx_buffer_size(rdev);
238 
239 	return RPMSG_EOPNOTSUPP;
240 }
241 
rpmsg_send_offchannel_nocopy(struct rpmsg_endpoint * ept,uint32_t src,uint32_t dst,const void * data,int len)242 int rpmsg_send_offchannel_nocopy(struct rpmsg_endpoint *ept, uint32_t src,
243 				 uint32_t dst, const void *data, int len)
244 {
245 	struct rpmsg_device *rdev;
246 
247 	if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY || len < 0)
248 		return RPMSG_ERR_PARAM;
249 
250 	rdev = ept->rdev;
251 
252 	if (rdev->ops.send_offchannel_nocopy)
253 		return rdev->ops.send_offchannel_nocopy(rdev, src, dst,
254 							data, len);
255 
256 	return RPMSG_ERR_PARAM;
257 }
258 
rpmsg_get_endpoint(struct rpmsg_device * rdev,const char * name,uint32_t addr,uint32_t dest_addr)259 struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rdev,
260 					  const char *name, uint32_t addr,
261 					  uint32_t dest_addr)
262 {
263 	struct metal_list *node;
264 	struct rpmsg_endpoint *ept;
265 
266 	metal_list_for_each(&rdev->endpoints, node) {
267 		int name_match = 0;
268 
269 		ept = metal_container_of(node, struct rpmsg_endpoint, node);
270 		/* try to get by local address only */
271 		if (addr != RPMSG_ADDR_ANY && ept->addr == addr)
272 			return ept;
273 		/* else use name service and destination address */
274 		if (name)
275 			name_match = !strncmp(ept->name, name,
276 					      sizeof(ept->name));
277 		if (!name || !name_match)
278 			continue;
279 		/* destination address is known, equal to ept remote address */
280 		if (dest_addr != RPMSG_ADDR_ANY && ept->dest_addr == dest_addr)
281 			return ept;
282 		/* ept is registered but not associated to remote ept */
283 		if (addr == RPMSG_ADDR_ANY && ept->dest_addr == RPMSG_ADDR_ANY)
284 			return ept;
285 	}
286 	return NULL;
287 }
288 
rpmsg_unregister_endpoint(struct rpmsg_endpoint * ept)289 static void rpmsg_unregister_endpoint(struct rpmsg_endpoint *ept)
290 {
291 	struct rpmsg_device *rdev = ept->rdev;
292 
293 	metal_mutex_acquire(&rdev->lock);
294 	if (ept->addr != RPMSG_ADDR_ANY)
295 		rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
296 				      ept->addr);
297 	metal_list_del(&ept->node);
298 	rpmsg_ept_decref(ept);
299 	metal_mutex_release(&rdev->lock);
300 }
301 
rpmsg_register_endpoint(struct rpmsg_device * rdev,struct rpmsg_endpoint * ept,const char * name,uint32_t src,uint32_t dest,rpmsg_ept_cb cb,rpmsg_ns_unbind_cb ns_unbind_cb,void * priv)302 void rpmsg_register_endpoint(struct rpmsg_device *rdev,
303 			     struct rpmsg_endpoint *ept,
304 			     const char *name,
305 			     uint32_t src, uint32_t dest,
306 			     rpmsg_ept_cb cb,
307 			     rpmsg_ns_unbind_cb ns_unbind_cb, void *priv)
308 {
309 	if (name)
310 		(void)safe_strcpy(ept->name, sizeof(ept->name), name, RPMSG_NAME_SIZE);
311 	else
312 		ept->name[0] = 0;
313 
314 	ept->refcnt = 1;
315 	ept->addr = src;
316 	ept->dest_addr = dest;
317 	ept->cb = cb;
318 	ept->ns_unbind_cb = ns_unbind_cb;
319 	ept->priv = priv;
320 	ept->rdev = rdev;
321 	metal_list_add_tail(&rdev->endpoints, &ept->node);
322 }
323 
rpmsg_create_ept(struct rpmsg_endpoint * ept,struct rpmsg_device * rdev,const char * name,uint32_t src,uint32_t dest,rpmsg_ept_cb cb,rpmsg_ns_unbind_cb unbind_cb)324 int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev,
325 		     const char *name, uint32_t src, uint32_t dest,
326 		     rpmsg_ept_cb cb, rpmsg_ns_unbind_cb unbind_cb)
327 {
328 	int status = RPMSG_SUCCESS;
329 	uint32_t addr = src;
330 
331 	if (!ept || !rdev || !cb)
332 		return RPMSG_ERR_PARAM;
333 
334 	metal_mutex_acquire(&rdev->lock);
335 	if (src == RPMSG_ADDR_ANY) {
336 		addr = rpmsg_get_address(rdev->bitmap, rdev->bitnext, RPMSG_ADDR_BMP_SIZE);
337 		if (addr == RPMSG_ADDR_ANY) {
338 			status = RPMSG_ERR_ADDR;
339 			goto ret_status;
340 		}
341 		rdev->bitnext = (addr + 1) % RPMSG_ADDR_BMP_SIZE;
342 	} else if (src >= RPMSG_RESERVED_ADDRESSES) {
343 		status = rpmsg_is_address_set(rdev->bitmap,
344 					      RPMSG_ADDR_BMP_SIZE, src);
345 		if (!status) {
346 			/* Mark the address as used in the address bitmap. */
347 			rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
348 					  src);
349 		} else if (status > 0) {
350 			status = RPMSG_ERR_ADDR;
351 			goto ret_status;
352 		} else {
353 			goto ret_status;
354 		}
355 	} else {
356 		/* Skip check the address duplication in 0-1023:
357 		 * 1.Trust the author of predefined service
358 		 * 2.Simplify the tracking implementation
359 		 */
360 	}
361 
362 	rpmsg_register_endpoint(rdev, ept, name, addr, dest, cb, unbind_cb, ept->priv);
363 	metal_mutex_release(&rdev->lock);
364 
365 	/* Send NS announcement to remote processor */
366 	if (ept->name[0] && rdev->support_ns &&
367 	    ept->dest_addr == RPMSG_ADDR_ANY)
368 		status = rpmsg_send_ns_message(ept, RPMSG_NS_CREATE);
369 
370 	if (status)
371 		rpmsg_unregister_endpoint(ept);
372 	return status;
373 
374 ret_status:
375 	metal_mutex_release(&rdev->lock);
376 	return status;
377 }
378 
rpmsg_destroy_ept(struct rpmsg_endpoint * ept)379 void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
380 {
381 	struct rpmsg_device *rdev;
382 
383 	if (!ept || !ept->rdev)
384 		return;
385 
386 	rdev = ept->rdev;
387 
388 	if (ept->name[0] && rdev->support_ns &&
389 	    ept->addr >= RPMSG_RESERVED_ADDRESSES)
390 		(void)rpmsg_send_ns_message(ept, RPMSG_NS_DESTROY);
391 	rpmsg_unregister_endpoint(ept);
392 }
393