1 /*
2 * Copyright (c) 2014, Mentor Graphics Corporation
3 * All rights reserved.
4 * Copyright (c) 2015 Xilinx, Inc. All rights reserved.
5 * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * 3. Neither the name of Mentor Graphics Corporation nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
32 /**************************************************************************
33 * FILE NAME
34 *
35 * rpmsg_core.c
36 *
37 * COMPONENT
38 *
39 * OpenAMP
40 *
41 * DESCRIPTION
42 *
43 * This file provides the core functionality of RPMSG messaging part like
44 * message parsing ,Rx/Tx callbacks handling , channel creation/deletion
45 * and address management.
46 *
47 *
48 **************************************************************************/
49 #include <string.h>
50 #include "openamp/rpmsg.h"
51 #include "metal/utilities.h"
53 /* Internal functions */
54 static void rpmsg_rx_callback(struct virtqueue *vq);
55 static void rpmsg_tx_callback(struct virtqueue *vq);
57 /**
58 * rpmsg_start_ipc
59 *
60 * This function creates communication links(virtqueues) for remote device
61 * and notifies it to start IPC.
62 *
63 * @param rdev - remote device handle
64 *
65 * @return - status of function execution
66 *
67 */
68 int rpmsg_start_ipc(struct remote_device *rdev)
69 {
70 struct virtio_device *virt_dev;
71 struct rpmsg_endpoint *ns_ept;
72 void (*callback[2]) (struct virtqueue * vq);
73 const char *vq_names[2];
74 unsigned long dev_features;
75 int status;
76 struct virtqueue *vqs[2];
77 int i;
79 virt_dev = &rdev->virt_dev;
81 /* Initialize names and callbacks based on the device role */
82 if (rdev->role == RPMSG_MASTER) {
83 vq_names[0] = "tx_vq";
84 vq_names[1] = "rx_vq";
85 callback[0] = rpmsg_tx_callback;
86 callback[1] = rpmsg_rx_callback;
87 } else {
88 vq_names[0] = "rx_vq";
89 vq_names[1] = "tx_vq";
90 callback[0] = rpmsg_rx_callback;
91 callback[1] = rpmsg_tx_callback;
92 }
94 /* Create virtqueues for remote device */
95 status = virt_dev->func->create_virtqueues(virt_dev, 0,
96 RPMSG_MAX_VQ_PER_RDEV,
97 vq_names, callback,
98 RPMSG_NULL);
99 if (status != RPMSG_SUCCESS) {
100 return status;
101 }
103 dev_features = virt_dev->func->get_features(virt_dev);
105 /*
106 * Create name service announcement endpoint if device supports name
107 * service announcement feature.
108 */
109 if ((dev_features & (1 << VIRTIO_RPMSG_F_NS))) {
110 rdev->support_ns = RPMSG_TRUE;
111 ns_ept = _create_endpoint(rdev, rpmsg_ns_callback, rdev,
112 RPMSG_NS_EPT_ADDR);
113 if (!ns_ept) {
114 return RPMSG_ERR_NO_MEM;
115 }
116 }
118 /* Initialize notifications for vring. */
119 if (rdev->role == RPMSG_MASTER) {
120 vqs[0] = rdev->tvq;
121 vqs[1] = rdev->rvq;
122 } else {
123 vqs[0] = rdev->rvq;
124 vqs[1] = rdev->tvq;
125 }
126 for (i = 0; i <= 1; i++) {
127 status = hil_enable_vring_notifications(i, vqs[i]);
128 if (status != RPMSG_SUCCESS) {
129 return status;
130 }
131 }
133 status = rpmsg_rdev_notify(rdev);
135 return status;
136 }
138 /**
139 * _rpmsg_create_channel
140 *
141 * Creates new rpmsg channel with the given parameters.
142 *
143 * @param rdev - pointer to remote device which contains the channel
144 * @param name - name of the device
145 * @param src - source address for the rpmsg channel
146 * @param dst - destination address for the rpmsg channel
147 *
148 * @return - pointer to new rpmsg channel
149 *
150 */
151 struct rpmsg_channel *_rpmsg_create_channel(struct remote_device *rdev,
152 char *name, unsigned long src,
153 unsigned long dst)
154 {
155 struct rpmsg_channel *rp_chnl;
157 rp_chnl = env_allocate_memory(sizeof(struct rpmsg_channel));
158 if (rp_chnl) {
159 memset(rp_chnl, 0x00, sizeof(struct rpmsg_channel));
160 strncpy(rp_chnl->name, name, sizeof(rp_chnl->name));
161 rp_chnl->src = src;
162 rp_chnl->dst = dst;
163 rp_chnl->rdev = rdev;
164 /* Place channel on channels list */
165 metal_mutex_acquire(&rdev->lock);
166 metal_list_add_tail(&rdev->rp_channels, &rp_chnl->node);
167 metal_mutex_release(&rdev->lock);
168 }
170 return rp_chnl;
171 }
173 /**
174 * _rpmsg_delete_channel
175 *
176 * Deletes given rpmsg channel.
177 *
178 * @param rp_chnl - pointer to rpmsg channel to delete
179 *
180 * return - none
181 */
182 void _rpmsg_delete_channel(struct rpmsg_channel *rp_chnl)
183 {
184 if (rp_chnl) {
185 metal_mutex_acquire(&rp_chnl->rdev->lock);
186 metal_list_del(&rp_chnl->node);
187 metal_mutex_release(&rp_chnl->rdev->lock);
188 env_free_memory(rp_chnl);
189 }
190 }
192 /**
193 * _create_endpoint
194 *
195 * This function creates rpmsg endpoint.
196 *
197 * @param rdev - pointer to remote device
198 * @param cb - Rx completion call back
199 * @param priv - private data
200 * @param addr - endpoint src address
201 *
202 * @return - pointer to endpoint control block
203 *
204 */
205 struct rpmsg_endpoint *_create_endpoint(struct remote_device *rdev,
206 rpmsg_rx_cb_t cb, void *priv,
207 unsigned long addr)
208 {
210 struct rpmsg_endpoint *rp_ept;
211 int status = RPMSG_SUCCESS;
213 rp_ept = env_allocate_memory(sizeof(struct rpmsg_endpoint));
214 if (!rp_ept) {
215 return RPMSG_NULL;
216 }
217 memset(rp_ept, 0x00, sizeof(struct rpmsg_endpoint));
219 metal_mutex_acquire(&rdev->lock);
221 if (addr != RPMSG_ADDR_ANY) {
222 /*
223 * Application has requested a particular src address for endpoint,
224 * first check if address is available.
225 */
226 if (!rpmsg_is_address_set
227 (rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr)) {
228 /* Mark the address as used in the address bitmap. */
229 rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
230 addr);
232 } else {
233 status = RPMSG_ERR_DEV_ADDR;
234 }
235 } else {
236 addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE);
237 if ((int)addr < 0) {
238 status = RPMSG_ERR_DEV_ADDR;
239 }
240 }
242 /* Do cleanup in case of error and return */
243 if (RPMSG_SUCCESS != status) {
244 env_free_memory(rp_ept);
245 metal_mutex_release(&rdev->lock);
246 return RPMSG_NULL;
247 }
249 rp_ept->addr = addr;
250 rp_ept->cb = cb;
251 rp_ept->priv = priv;
253 metal_list_add_tail(&rdev->rp_endpoints, &rp_ept->node);
255 metal_mutex_release(&rdev->lock);
257 return rp_ept;
258 }
260 /**
261 * rpmsg_destroy_ept
262 *
263 * This function deletes rpmsg endpoint and performs cleanup.
264 *
265 * @param rdev - pointer to remote device
266 * @param rp_ept - pointer to endpoint to destroy
267 *
268 */
269 void _destroy_endpoint(struct remote_device *rdev,
270 struct rpmsg_endpoint *rp_ept)
271 {
272 metal_mutex_acquire(&rdev->lock);
273 rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
274 rp_ept->addr);
275 metal_list_del(&rp_ept->node);
276 metal_mutex_release(&rdev->lock);
277 /* free node and rp_ept */
278 env_free_memory(rp_ept);
279 }
281 /**
282 * rpmsg_send_ns_message
283 *
284 * Sends name service announcement to remote device
285 *
286 * @param rdev - pointer to remote device
287 * @param rp_chnl - pointer to rpmsg channel
288 * @param flags - Channel creation/deletion flags
289 *
290 */
291 void rpmsg_send_ns_message(struct remote_device *rdev,
292 struct rpmsg_channel *rp_chnl, unsigned long flags)
293 {
295 struct rpmsg_hdr *rp_hdr;
296 struct rpmsg_ns_msg *ns_msg;
297 unsigned short idx;
298 unsigned long len;
300 metal_mutex_acquire(&rdev->lock);
302 /* Get Tx buffer. */
303 rp_hdr = (struct rpmsg_hdr *)rpmsg_get_tx_buffer(rdev, &len, &idx);
304 if (!rp_hdr) {
305 metal_mutex_release(&rdev->lock);
306 return;
307 }
309 /* Fill out name service data. */
310 rp_hdr->dst = RPMSG_NS_EPT_ADDR;
311 rp_hdr->len = sizeof(struct rpmsg_ns_msg);
312 ns_msg = (struct rpmsg_ns_msg *) RPMSG_LOCATE_DATA(rp_hdr);
313 strncpy(ns_msg->name, rp_chnl->name, sizeof(rp_chnl->name));
314 ns_msg->flags = flags;
315 ns_msg->addr = rp_chnl->src;
317 /* Place the buffer on virtqueue. */
318 rpmsg_enqueue_buffer(rdev, rp_hdr, len, idx);
320 /* Notify the other side that it has data to process. */
321 virtqueue_kick(rdev->tvq);
323 metal_mutex_release(&rdev->lock);
324 }
326 /**
327 * rpmsg_enqueue_buffers
328 *
329 * Places buffer on the virtqueue for consumption by the other side.
330 *
331 * @param rdev - pointer to remote core
332 * @param buffer - buffer pointer
333 * @param len - buffer length
334 * @idx - buffer index
335 *
336 * @return - status of function execution
337 *
338 */
339 int rpmsg_enqueue_buffer(struct remote_device *rdev, void *buffer,
340 unsigned long len, unsigned short idx)
341 {
342 struct llist node;
343 int status;
345 /* Initialize buffer node */
346 node.data = buffer;
347 node.attr = len;
348 node.next = RPMSG_NULL;
349 node.prev = RPMSG_NULL;
351 if (rdev->role == RPMSG_REMOTE) {
352 status = virtqueue_add_buffer(rdev->tvq, &node, 0, 1, buffer);
353 } else {
354 status = virtqueue_add_consumed_buffer(rdev->tvq, idx, len);
355 }
357 return status;
358 }
360 /**
361 * rpmsg_return_buffer
362 *
363 * Places the used buffer back on the virtqueue.
364 *
365 * @param rdev - pointer to remote core
366 * @param buffer - buffer pointer
367 * @param len - buffer length
368 * @param idx - buffer index
369 *
370 */
371 void rpmsg_return_buffer(struct remote_device *rdev, void *buffer,
372 unsigned long len, unsigned short idx)
373 {
374 struct llist node;
376 /* Initialize buffer node */
377 node.data = buffer;
378 node.attr = len;
379 node.next = RPMSG_NULL;
380 node.prev = RPMSG_NULL;
382 if (rdev->role == RPMSG_REMOTE) {
383 virtqueue_add_buffer(rdev->rvq, &node, 0, 1, buffer);
384 } else {
385 virtqueue_add_consumed_buffer(rdev->rvq, idx, len);
386 }
387 }
389 /**
390 * rpmsg_get_tx_buffer
391 *
392 * Provides buffer to transmit messages.
393 *
394 * @param rdev - pointer to remote device
395 * @param len - length of returned buffer
396 * @param idx - buffer index
397 *
398 * return - pointer to buffer.
399 */
400 void *rpmsg_get_tx_buffer(struct remote_device *rdev, unsigned long *len,
401 unsigned short *idx)
402 {
403 void *data;
405 if (rdev->role == RPMSG_REMOTE) {
406 data = virtqueue_get_buffer(rdev->tvq, (uint32_t *) len);
407 if (data == RPMSG_NULL) {
408 data = sh_mem_get_buffer(rdev->mem_pool);
409 *len = RPMSG_BUFFER_SIZE;
410 }
411 } else {
412 data =
413 virtqueue_get_available_buffer(rdev->tvq, idx,
414 (uint32_t *) len);
415 }
416 return ((void *)env_map_vatopa(data));
417 }
419 /**
420 * rpmsg_get_rx_buffer
421 *
422 * Retrieves the received buffer from the virtqueue.
423 *
424 * @param rdev - pointer to remote device
425 * @param len - size of received buffer
426 * @param idx - index of buffer
427 *
428 * @return - pointer to received buffer
429 *
430 */
431 void *rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len,
432 unsigned short *idx)
433 {
435 void *data;
436 if (rdev->role == RPMSG_REMOTE) {
437 data = virtqueue_get_buffer(rdev->rvq, (uint32_t *) len);
438 } else {
439 data =
440 virtqueue_get_available_buffer(rdev->rvq, idx,
441 (uint32_t *) len);
442 }
443 return ((void *)env_map_vatopa(data));
444 }
446 /**
447 * rpmsg_free_buffer
448 *
449 * Frees the allocated buffers.
450 *
451 * @param rdev - pointer to remote device
452 * @param buffer - pointer to buffer to free
453 *
454 */
455 void rpmsg_free_buffer(struct remote_device *rdev, void *buffer)
456 {
457 if (rdev->role == RPMSG_REMOTE) {
458 sh_mem_free_buffer(buffer, rdev->mem_pool);
459 }
460 }
462 /**
463 * rpmsg_tx_callback
464 *
465 * Tx callback function.
466 *
467 * @param vq - pointer to virtqueue on which Tx is has been
468 * completed.
469 *
470 */
471 static void rpmsg_tx_callback(struct virtqueue *vq)
472 {
473 struct remote_device *rdev;
474 struct virtio_device *vdev;
475 struct rpmsg_channel *rp_chnl;
476 struct metal_list *node;
478 vdev = (struct virtio_device *)vq->vq_dev;
479 rdev = (struct remote_device *)vdev;
481 /* Check if the remote device is master. */
482 if (rdev->role == RPMSG_MASTER) {
484 /* Notification is received from the master. Now the remote(us) can
485 * performs one of two operations;
486 *
487 * a. If name service announcement is supported then it will send NS message.
488 * else
489 * b. It will update the channel state to active so that further communication
490 * can take place.
491 */
492 metal_list_for_each(&rdev->rp_channels, node) {
493 rp_chnl = metal_container_of(node,
494 struct rpmsg_channel, node);
496 if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
498 if (rdev->support_ns) {
499 rp_chnl->state = RPMSG_CHNL_STATE_NS;
500 } else {
501 rp_chnl->state =
502 RPMSG_CHNL_STATE_ACTIVE;
503 }
505 if (rp_chnl->state == RPMSG_CHNL_STATE_NS) {
506 rpmsg_send_ns_message(rdev, rp_chnl,
507 RPMSG_NS_CREATE);
508 }
509 }
511 }
512 }
513 }
515 /**
516 * rpmsg_rx_callback
517 *
518 * Rx callback function.
519 *
520 * @param vq - pointer to virtqueue on which messages is received
521 *
522 */
523 void rpmsg_rx_callback(struct virtqueue *vq)
524 {
525 struct remote_device *rdev;
526 struct virtio_device *vdev;
527 struct rpmsg_channel *rp_chnl;
528 struct rpmsg_endpoint *rp_ept;
529 struct rpmsg_hdr *rp_hdr;
530 struct metal_list *node;
531 unsigned long len;
532 unsigned short idx;
534 vdev = (struct virtio_device *)vq->vq_dev;
535 rdev = (struct remote_device *)vdev;
537 if (rdev->role == RPMSG_MASTER) {
538 metal_list_for_each(&rdev->rp_channels, node) {
539 rp_chnl = metal_container_of(node,
540 struct rpmsg_channel, node);
541 if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
542 if (rdev->support_ns) {
543 rp_chnl->state = RPMSG_CHNL_STATE_NS;
544 rpmsg_send_ns_message(rdev, rp_chnl,
545 RPMSG_NS_CREATE);
546 } else {
547 rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
548 }
549 return;
550 }
551 }
552 }
554 metal_mutex_acquire(&rdev->lock);
556 /* Process the received data from remote node */
557 rp_hdr = (struct rpmsg_hdr *)rpmsg_get_rx_buffer(rdev, &len, &idx);
559 metal_mutex_release(&rdev->lock);
561 while (rp_hdr) {
563 /* Get the channel node from the remote device channels list. */
564 metal_mutex_acquire(&rdev->lock);
565 rp_ept = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst);
566 metal_mutex_release(&rdev->lock);
568 if (!rp_ept)
569 /* Fatal error no endpoint for the given dst addr. */
570 return;
572 rp_chnl = rp_ept->rp_chnl;
574 if ((rp_chnl) && (rp_chnl->state == RPMSG_CHNL_STATE_NS)) {
575 /* First message from RPMSG Master, update channel
576 * destination address and state */
577 rp_chnl->dst = rp_hdr->src;
578 rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
580 /* Notify channel creation to application */
581 if (rdev->channel_created) {
582 rdev->channel_created(rp_chnl);
583 }
584 } else {
585 rp_ept->cb(rp_chnl, (void *)RPMSG_LOCATE_DATA(rp_hdr), rp_hdr->len,
586 rp_ept->priv, rp_hdr->src);
587 }
589 metal_mutex_acquire(&rdev->lock);
591 /* Return used buffers. */
592 rpmsg_return_buffer(rdev, rp_hdr, len, idx);
594 rp_hdr =
595 (struct rpmsg_hdr *)rpmsg_get_rx_buffer(rdev, &len, &idx);
596 metal_mutex_release(&rdev->lock);
597 }
598 }
600 /**
601 * rpmsg_ns_callback
602 *
603 * This callback handles name service announcement from the remote device
604 * and creates/deletes rpmsg channels.
605 *
606 * @param server_chnl - pointer to server channel control block.
607 * @param data - pointer to received messages
608 * @param len - length of received data
609 * @param priv - any private data
610 * @param src - source address
611 *
612 * @return - none
613 */
614 void rpmsg_ns_callback(struct rpmsg_channel *server_chnl, void *data, int len,
615 void *priv, unsigned long src)
616 {
617 struct remote_device *rdev;
618 struct rpmsg_channel *rp_chnl;
619 struct rpmsg_ns_msg *ns_msg;
621 (void)server_chnl;
622 (void)src;
624 rdev = (struct remote_device *)priv;
626 //FIXME: This assumes same name string size for channel name both on master
627 //and remote. If this is not the case then we will have to parse the
628 //message contents.
630 ns_msg = (struct rpmsg_ns_msg *)data;
631 ns_msg->name[len - 1] = '\0';
633 if (ns_msg->flags & RPMSG_NS_DESTROY) {
634 metal_mutex_acquire(&rdev->lock);
635 rp_chnl = rpmsg_rdev_get_chnl_from_id(rdev, ns_msg->name);
636 metal_mutex_release(&rdev->lock);
637 if (rp_chnl) {
638 if (rdev->channel_destroyed) {
639 rdev->channel_destroyed(rp_chnl);
640 }
641 rpmsg_destroy_ept(rp_chnl->rp_ept);
642 _rpmsg_delete_channel(rp_chnl);
643 }
644 } else {
645 rp_chnl =
646 _rpmsg_create_channel(rdev, ns_msg->name, 0x00,
647 ns_msg->addr);
648 if (rp_chnl) {
649 rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
650 /* Create default endpoint for channel */
651 rp_chnl->rp_ept =
652 rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
653 RPMSG_ADDR_ANY);
654 if (rp_chnl->rp_ept) {
655 rp_chnl->src = rp_chnl->rp_ept->addr;
656 /*
657 * Echo back the NS message to remote in order to
658 * complete the connection stage. Remote will know the endpoint
659 * address from this point onward which will enable it to send
660 * message without waiting for any application level message from
661 * master.
662 */
663 rpmsg_send(rp_chnl, data, len);
664 if (rdev->channel_created) {
665 rdev->channel_created(rp_chnl);
666 }
667 }
668 }
669 }
670 }
672 /**
673 * rpmsg_get_address
674 *
675 * This function provides unique 32 bit address.
676 *
677 * @param bitmap - bit map for addresses
678 * @param size - size of bitmap
679 *
680 * return - a unique address
681 */
682 int rpmsg_get_address(unsigned long *bitmap, int size)
683 {
684 int addr = -1;
685 int i, tmp32;
687 /* Find first available buffer */
688 for (i = 0; i < size; i++) {
689 tmp32 = get_first_zero_bit(bitmap[i]);
691 if (tmp32 < 32) {
692 addr = tmp32 + (i*32);
693 bitmap[i] |= (1 << tmp32);
694 break;
695 }
696 }
698 return addr;
699 }
701 /**
702 * rpmsg_release_address
703 *
704 * Frees the given address.
705 *
706 * @param bitmap - bit map for addresses
707 * @param size - size of bitmap
708 * @param addr - address to free
709 *
710 * return - none
711 */
712 int rpmsg_release_address(unsigned long *bitmap, int size, int addr)
713 {
714 unsigned int i, j;
715 unsigned long mask = 1;
717 if (addr >= size * 32)
718 return -1;
720 /* Mark the addr as available */
721 i = addr / 32;
722 j = addr % 32;
724 mask = mask << j;
725 bitmap[i] = bitmap[i] & (~mask);
727 return RPMSG_SUCCESS;
728 }
730 /**
731 * rpmsg_is_address_set
732 *
733 * Checks whether address is used or free.
734 *
735 * @param bitmap - bit map for addresses
736 * @param size - size of bitmap
737 * @param addr - address to free
738 *
739 * return - TRUE/FALSE
740 */
741 int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr)
742 {
743 int i, j;
744 unsigned long mask = 1;
746 if (addr >= size * 32)
747 return -1;
749 /* Mark the id as available */
750 i = addr / 32;
751 j = addr % 32;
752 mask = mask << j;
754 return (bitmap[i] & mask);
755 }
757 /**
758 * rpmsg_set_address
759 *
760 * Marks the address as consumed.
761 *
762 * @param bitmap - bit map for addresses
763 * @param size - size of bitmap
764 * @param addr - address to free
765 *
766 * return - none
767 */
768 int rpmsg_set_address(unsigned long *bitmap, int size, int addr)
769 {
770 int i, j;
771 unsigned long mask = 1;
773 if (addr >= size * 32)
774 return -1;
776 /* Mark the id as available */
777 i = addr / 32;
778 j = addr % 32;
779 mask = mask << j;
780 bitmap[i] |= mask;
782 return RPMSG_SUCCESS;
783 }