]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - lib/rpmsg/rpmsg_core.c
Adding RPMsg Extension layer implementing zero-copy send and receive.
[processor-sdk/open-amp.git] / lib / rpmsg / rpmsg_core.c
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"
52 #include "metal/io.h"
53 #include "metal/cache.h"
54 #include "metal/alloc.h"
56 /* Internal functions */
57 static void rpmsg_rx_callback(struct virtqueue *vq);
58 static void rpmsg_tx_callback(struct virtqueue *vq);
60 /**
61  * rpmsg_start_ipc
62  *
63  * This function creates communication links(virtqueues) for remote device
64  * and notifies it to start IPC.
65  *
66  * @param rdev - remote device handle
67  *
68  * @return - status of function execution
69  *
70  */
71 int rpmsg_start_ipc(struct remote_device *rdev)
72 {
73         struct virtio_device *virt_dev;
74         struct rpmsg_endpoint *ns_ept;
75         void (*callback[2]) (struct virtqueue * vq);
76         const char *vq_names[2];
77         unsigned long dev_features;
78         int status;
79         struct virtqueue *vqs[2];
80         int i;
82         virt_dev = &rdev->virt_dev;
84         /* Initialize names and callbacks based on the device role */
85         if (rdev->role == RPMSG_MASTER) {
86                 vq_names[0] = "tx_vq";
87                 vq_names[1] = "rx_vq";
88                 callback[0] = rpmsg_tx_callback;
89                 callback[1] = rpmsg_rx_callback;
90         } else {
91                 vq_names[0] = "rx_vq";
92                 vq_names[1] = "tx_vq";
93                 callback[0] = rpmsg_rx_callback;
94                 callback[1] = rpmsg_tx_callback;
95         }
97         /* Create virtqueues for remote device */
98         status = virt_dev->func->create_virtqueues(virt_dev, 0,
99                                                    RPMSG_MAX_VQ_PER_RDEV,
100                                                    vq_names, callback,
101                                                    RPMSG_NULL);
102         if (status != RPMSG_SUCCESS) {
103                 return status;
104         }
106         dev_features = virt_dev->func->get_features(virt_dev);
108         /*
109          * Create name service announcement endpoint if device supports name
110          * service announcement feature.
111          */
112         if ((dev_features & (1 << VIRTIO_RPMSG_F_NS))) {
113                 rdev->support_ns = RPMSG_TRUE;
114                 ns_ept = _create_endpoint(rdev, rpmsg_ns_callback, rdev,
115                                           RPMSG_NS_EPT_ADDR);
116                 if (!ns_ept) {
117                         return RPMSG_ERR_NO_MEM;
118                 }
119         }
121         /* Initialize notifications for vring. */
122         if (rdev->role == RPMSG_MASTER) {
123                 vqs[0] = rdev->tvq;
124                 vqs[1] = rdev->rvq;
125         } else {
126                 vqs[0] = rdev->rvq;
127                 vqs[1] = rdev->tvq;
128         }
129         for (i = 0; i <= 1; i++) {
130                 status = hil_enable_vring_notifications(i, vqs[i]);
131                 if (status != RPMSG_SUCCESS) {
132                         return status;
133                 }
134         }
136         status = rpmsg_rdev_notify(rdev);
138         return status;
141 /**
142  * _rpmsg_create_channel
143  *
144  * Creates new rpmsg channel with the given parameters.
145  *
146  * @param rdev - pointer to remote device which contains the channel
147  * @param name - name of the device
148  * @param src  - source address for the rpmsg channel
149  * @param dst  - destination address for the rpmsg channel
150  *
151  * @return - pointer to new rpmsg channel
152  *
153  */
154 struct rpmsg_channel *_rpmsg_create_channel(struct remote_device *rdev,
155                                             char *name, unsigned long src,
156                                             unsigned long dst)
158         struct rpmsg_channel *rp_chnl;
160         rp_chnl = metal_allocate_memory(sizeof(struct rpmsg_channel));
161         if (rp_chnl) {
162                 memset(rp_chnl, 0x00, sizeof(struct rpmsg_channel));
163                 strncpy(rp_chnl->name, name, sizeof(rp_chnl->name));
164                 rp_chnl->src = src;
165                 rp_chnl->dst = dst;
166                 rp_chnl->rdev = rdev;
167                 /* Place channel on channels list */
168                 metal_mutex_acquire(&rdev->lock);
169                 metal_list_add_tail(&rdev->rp_channels, &rp_chnl->node);
170                 metal_mutex_release(&rdev->lock);
171         }
173         return rp_chnl;
176 /**
177  * _rpmsg_delete_channel
178  *
179  * Deletes given rpmsg channel.
180  *
181  * @param rp_chnl -  pointer to rpmsg channel to delete
182  *
183  * return - none
184  */
185 void _rpmsg_delete_channel(struct rpmsg_channel *rp_chnl)
187         if (rp_chnl) {
188                 metal_mutex_acquire(&rp_chnl->rdev->lock);
189                 metal_list_del(&rp_chnl->node);
190                 metal_mutex_release(&rp_chnl->rdev->lock);
191                 metal_free_memory(rp_chnl);
192         }
195 /**
196  * _create_endpoint
197  *
198  * This function creates rpmsg endpoint.
199  *
200  * @param rdev    - pointer to remote device
201  * @param cb      - Rx completion call back
202  * @param priv    - private data
203  * @param addr    - endpoint src address
204  *
205  * @return - pointer to endpoint control block
206  *
207  */
208 struct rpmsg_endpoint *_create_endpoint(struct remote_device *rdev,
209                                         rpmsg_rx_cb_t cb, void *priv,
210                                         unsigned long addr)
213         struct rpmsg_endpoint *rp_ept;
214         int status = RPMSG_SUCCESS;
216         rp_ept = metal_allocate_memory(sizeof(struct rpmsg_endpoint));
217         if (!rp_ept) {
218                 return RPMSG_NULL;
219         }
220         memset(rp_ept, 0x00, sizeof(struct rpmsg_endpoint));
222         metal_mutex_acquire(&rdev->lock);
224         if (addr != RPMSG_ADDR_ANY) {
225                 /*
226                  * Application has requested a particular src address for endpoint,
227                  * first check if address is available.
228                  */
229                 if (!rpmsg_is_address_set
230                     (rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr)) {
231                         /* Mark the address as used in the address bitmap. */
232                         rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
233                                           addr);
235                 } else {
236                         status = RPMSG_ERR_DEV_ADDR;
237                 }
238         } else {
239                 addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE);
240                 if ((int)addr < 0) {
241                         status = RPMSG_ERR_DEV_ADDR;
242                 }
243         }
245         /* Do cleanup in case of error and return */
246         if (RPMSG_SUCCESS != status) {
247                 metal_free_memory(rp_ept);
248                 metal_mutex_release(&rdev->lock);
249                 return RPMSG_NULL;
250         }
252         rp_ept->addr = addr;
253         rp_ept->cb = cb;
254         rp_ept->priv = priv;
256         metal_list_add_tail(&rdev->rp_endpoints, &rp_ept->node);
258         metal_mutex_release(&rdev->lock);
260         return rp_ept;
263 /**
264  * rpmsg_destroy_ept
265  *
266  * This function deletes rpmsg endpoint and performs cleanup.
267  *
268  * @param rdev   - pointer to remote device
269  * @param rp_ept - pointer to endpoint to destroy
270  *
271  */
272 void _destroy_endpoint(struct remote_device *rdev,
273                        struct rpmsg_endpoint *rp_ept)
275         metal_mutex_acquire(&rdev->lock);
276         rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
277                               rp_ept->addr);
278         metal_list_del(&rp_ept->node);
279         metal_mutex_release(&rdev->lock);
280         /* free node and rp_ept */
281         metal_free_memory(rp_ept);
284 /**
285  * rpmsg_send_ns_message
286  *
287  * Sends name service announcement to remote device
288  *
289  * @param rdev    - pointer to remote device
290  * @param rp_chnl - pointer to rpmsg channel
291  * @param flags   - Channel creation/deletion flags
292  *
293  */
294 void rpmsg_send_ns_message(struct remote_device *rdev,
295                            struct rpmsg_channel *rp_chnl, unsigned long flags)
298         struct rpmsg_hdr *rp_hdr;
299         struct rpmsg_ns_msg *ns_msg;
300         unsigned short idx;
301         unsigned long len;
303         metal_mutex_acquire(&rdev->lock);
305         /* Get Tx buffer. */
306         rp_hdr = (struct rpmsg_hdr *)rpmsg_get_tx_buffer(rdev, &len, &idx);
307         if (!rp_hdr) {
308                 metal_mutex_release(&rdev->lock);
309                 return;
310         }
312         /* Fill out name service data. */
313         rp_hdr->dst = RPMSG_NS_EPT_ADDR;
314         rp_hdr->len = sizeof(struct rpmsg_ns_msg);
315         ns_msg = (struct rpmsg_ns_msg *) RPMSG_LOCATE_DATA(rp_hdr);
316         strncpy(ns_msg->name, rp_chnl->name, sizeof(rp_chnl->name));
317         ns_msg->flags = flags;
318         ns_msg->addr = rp_chnl->src;
320         /* Place the buffer on virtqueue. */
321         rpmsg_enqueue_buffer(rdev, rp_hdr, len, idx);
323         /* Notify the other side that it has data to process. */
324         virtqueue_kick(rdev->tvq);
326         metal_mutex_release(&rdev->lock);
329 /**
330  * rpmsg_enqueue_buffers
331  *
332  * Places buffer on the virtqueue for consumption by the other side.
333  *
334  * @param rdev   - pointer to remote core
335  * @param buffer - buffer pointer
336  * @param len    - buffer length
337  * @idx          - buffer index
338  *
339  * @return - status of function execution
340  *
341  */
342 int rpmsg_enqueue_buffer(struct remote_device *rdev, void *buffer,
343                          unsigned long len, unsigned short idx)
345         int status;
346         struct metal_sg sg;
347         struct metal_io_region *io;
349         io = rdev->proc->sh_buff.io;
350         if (io) {
351                 if (! (io->mem_flags & METAL_UNCACHED))
352                         metal_cache_flush(buffer, (unsigned int)len);
353         }
354         if (rdev->role == RPMSG_REMOTE) {
355                 /* Initialize buffer node */
356                 sg.virt = buffer;
357                 sg.len = len;
358                 sg.io = io;
359                 status = virtqueue_add_buffer(rdev->tvq, &sg, 0, 1, buffer);
360         } else {
361                 (void)sg;
362                 status = virtqueue_add_consumed_buffer(rdev->tvq, idx, len);
363         }
365         return status;
368 /**
369  * rpmsg_return_buffer
370  *
371  * Places the used buffer back on the virtqueue.
372  *
373  * @param rdev   - pointer to remote core
374  * @param buffer - buffer pointer
375  * @param len    - buffer length
376  * @param idx    - buffer index
377  *
378  */
379 void rpmsg_return_buffer(struct remote_device *rdev, void *buffer,
380                          unsigned long len, unsigned short idx)
382         struct metal_sg sg;
384         if (rdev->role == RPMSG_REMOTE) {
385                 /* Initialize buffer node */
386                 sg.virt = buffer;
387                 sg.len = len;
388                 sg.io = rdev->proc->sh_buff.io;
389                 virtqueue_add_buffer(rdev->rvq, &sg, 0, 1, buffer);
390         } else {
391                 (void)sg;
392                 virtqueue_add_consumed_buffer(rdev->rvq, idx, len);
393         }
396 /**
397  * rpmsg_get_tx_buffer
398  *
399  * Provides buffer to transmit messages.
400  *
401  * @param rdev - pointer to remote device
402  * @param len  - length of returned buffer
403  * @param idx  - buffer index
404  *
405  * return - pointer to buffer.
406  */
407 void *rpmsg_get_tx_buffer(struct remote_device *rdev, unsigned long *len,
408                           unsigned short *idx)
410         void *data;
412         if (rdev->role == RPMSG_REMOTE) {
413                 data = virtqueue_get_buffer(rdev->tvq, (uint32_t *) len, idx);
414                 if (data == RPMSG_NULL) {
415                         data = sh_mem_get_buffer(rdev->mem_pool);
416                         *len = RPMSG_BUFFER_SIZE;
417                 }
418         } else {
419                 data =
420                     virtqueue_get_available_buffer(rdev->tvq, idx,
421                                                    (uint32_t *) len);
422         }
423         return data;
426 /**
427  * rpmsg_get_rx_buffer
428  *
429  * Retrieves the received buffer from the virtqueue.
430  *
431  * @param rdev - pointer to remote device
432  * @param len  - size of received buffer
433  * @param idx  - index of buffer
434  *
435  * @return - pointer to received buffer
436  *
437  */
438 void *rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len,
439                           unsigned short *idx)
442         void *data;
443         if (rdev->role == RPMSG_REMOTE) {
444                 data = virtqueue_get_buffer(rdev->rvq, (uint32_t *) len, idx);
445         } else {
446                 data =
447                     virtqueue_get_available_buffer(rdev->rvq, idx,
448                                                    (uint32_t *) len);
449         }
450         if (data) {
451                 struct metal_io_region *io;
452                 io = rdev->proc->sh_buff.io;
453                 if (io) {
454                         if (! (io->mem_flags & METAL_UNCACHED))
455                                 metal_cache_invalidate(data,
456                                         (unsigned int)(*len));
457                 }
458         }
460         return data;
463 /**
464  * rpmsg_free_buffer
465  *
466  * Frees the allocated buffers.
467  *
468  * @param rdev   - pointer to remote device
469  * @param buffer - pointer to buffer to free
470  *
471  */
472 void rpmsg_free_buffer(struct remote_device *rdev, void *buffer)
474         if (rdev->role == RPMSG_REMOTE) {
475                 sh_mem_free_buffer(buffer, rdev->mem_pool);
476         }
479 /**
480  * rpmsg_tx_callback
481  *
482  * Tx callback function.
483  *
484  * @param vq - pointer to virtqueue on which Tx is has been
485  *             completed.
486  *
487  */
488 static void rpmsg_tx_callback(struct virtqueue *vq)
490         struct remote_device *rdev;
491         struct virtio_device *vdev;
492         struct rpmsg_channel *rp_chnl;
493         struct metal_list *node;
495         vdev = (struct virtio_device *)vq->vq_dev;
496         rdev = (struct remote_device *)vdev;
498         /* Check if the remote device is master. */
499         if (rdev->role == RPMSG_MASTER) {
501                 /* Notification is received from the master. Now the remote(us) can
502                  * performs one of two operations;
503                  *
504                  * a. If name service announcement is supported then it will send NS message.
505                  *    else
506                  * b. It will update the channel state to active so that further communication
507                  *    can take place.
508                  */
509                 metal_list_for_each(&rdev->rp_channels, node) {
510                         rp_chnl = metal_container_of(node,
511                                 struct rpmsg_channel, node);
513                         if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
515                                 if (rdev->support_ns) {
516                                         rp_chnl->state = RPMSG_CHNL_STATE_NS;
517                                 } else {
518                                         rp_chnl->state =
519                                             RPMSG_CHNL_STATE_ACTIVE;
520                                 }
522                                 if (rp_chnl->state == RPMSG_CHNL_STATE_NS) {
523                                         rpmsg_send_ns_message(rdev, rp_chnl,
524                                                               RPMSG_NS_CREATE);
525                                 }
526                         }
528                 }
529         }
532 /**
533  * rpmsg_rx_callback
534  *
535  * Rx callback function.
536  *
537  * @param vq - pointer to virtqueue on which messages is received
538  *
539  */
540 void rpmsg_rx_callback(struct virtqueue *vq)
542         struct remote_device *rdev;
543         struct virtio_device *vdev;
544         struct rpmsg_channel *rp_chnl;
545         struct rpmsg_endpoint *rp_ept;
546         struct rpmsg_hdr *rp_hdr;
547         struct rpmsg_hdr_reserved *reserved;
548         struct metal_list *node;
549         unsigned long len;
550         unsigned short idx;
552         vdev = (struct virtio_device *)vq->vq_dev;
553         rdev = (struct remote_device *)vdev;
555         if (rdev->role == RPMSG_MASTER) {
556                 metal_list_for_each(&rdev->rp_channels, node) {
557                         rp_chnl = metal_container_of(node,
558                                 struct rpmsg_channel, node);
559                         if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
560                                 if (rdev->support_ns) {
561                                         rp_chnl->state = RPMSG_CHNL_STATE_NS;
562                                         rpmsg_send_ns_message(rdev, rp_chnl,
563                                                       RPMSG_NS_CREATE);
564                                 } else {
565                                         rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
566                                 }
567                                 return;
568                         }
569                 }
570         }
572         metal_mutex_acquire(&rdev->lock);
574         /* Process the received data from remote node */
575         rp_hdr = (struct rpmsg_hdr *)rpmsg_get_rx_buffer(rdev, &len, &idx);
577         metal_mutex_release(&rdev->lock);
579         while (rp_hdr) {
581                 /* Get the channel node from the remote device channels list. */
582                 metal_mutex_acquire(&rdev->lock);
583                 rp_ept = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst);
584                 metal_mutex_release(&rdev->lock);
586                 if (!rp_ept)
587                         /* Fatal error no endpoint for the given dst addr. */
588                         return;
590                 rp_chnl = rp_ept->rp_chnl;
592                 if ((rp_chnl) && (rp_chnl->state == RPMSG_CHNL_STATE_NS)) {
593                         /* First message from RPMSG Master, update channel
594                          * destination address and state */
595                         rp_chnl->dst = rp_hdr->src;
596                         rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
598                         /* Notify channel creation to application */
599                         if (rdev->channel_created) {
600                                 rdev->channel_created(rp_chnl);
601                         }
602                 } else {
603                         rp_ept->cb(rp_chnl, (void *)RPMSG_LOCATE_DATA(rp_hdr), rp_hdr->len,
604                                    rp_ept->priv, rp_hdr->src);
605                 }
607                 metal_mutex_acquire(&rdev->lock);
609                 /* Check whether callback wants to hold buffer */
610                 if (rp_hdr->reserved & RPMSG_BUF_HELD)
611                 {
612                         /* 'rp_hdr->reserved' field is now used as storage for
613                          * 'idx' to release buffer later */
614                         reserved = (struct rpmsg_hdr_reserved*)&rp_hdr->reserved;
615                         reserved->idx = (uint16_t)idx;
616                 } else {
617                         /* Return used buffers. */
618                         rpmsg_return_buffer(rdev, rp_hdr, len, idx);
619                 }
621                 rp_hdr =
622                     (struct rpmsg_hdr *)rpmsg_get_rx_buffer(rdev, &len, &idx);
623                 metal_mutex_release(&rdev->lock);
624         }
627 /**
628  * rpmsg_ns_callback
629  *
630  * This callback handles name service announcement from the remote device
631  * and creates/deletes rpmsg channels.
632  *
633  * @param server_chnl - pointer to server channel control block.
634  * @param data        - pointer to received messages
635  * @param len         - length of received data
636  * @param priv        - any private data
637  * @param src         - source address
638  *
639  * @return - none
640  */
641 void rpmsg_ns_callback(struct rpmsg_channel *server_chnl, void *data, int len,
642                        void *priv, unsigned long src)
644         struct remote_device *rdev;
645         struct rpmsg_channel *rp_chnl;
646         struct rpmsg_ns_msg *ns_msg;
648         (void)server_chnl;
649         (void)src;
651         rdev = (struct remote_device *)priv;
653         //FIXME: This assumes same name string size for channel name both on master
654         //and remote. If this is not the case then we will have to parse the
655         //message contents.
657         ns_msg = (struct rpmsg_ns_msg *)data;
658         ns_msg->name[len - 1] = '\0';
660         if (ns_msg->flags & RPMSG_NS_DESTROY) {
661                 metal_mutex_acquire(&rdev->lock);
662                 rp_chnl = rpmsg_rdev_get_chnl_from_id(rdev, ns_msg->name);
663                 metal_mutex_release(&rdev->lock);
664                 if (rp_chnl) {
665                         if (rdev->channel_destroyed) {
666                                 rdev->channel_destroyed(rp_chnl);
667                         }
668                         rpmsg_destroy_ept(rp_chnl->rp_ept);
669                         _rpmsg_delete_channel(rp_chnl);
670                 }
671         } else {
672                 rp_chnl =
673                     _rpmsg_create_channel(rdev, ns_msg->name, 0x00,
674                                           ns_msg->addr);
675                 if (rp_chnl) {
676                         rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
677                         /* Create default endpoint for channel */
678                         rp_chnl->rp_ept =
679                             rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
680                                              RPMSG_ADDR_ANY);
681                         if (rp_chnl->rp_ept) {
682                                 rp_chnl->src = rp_chnl->rp_ept->addr;
683                                 /*
684                                  * Echo back the NS message to remote in order to
685                                  * complete the connection stage. Remote will know the endpoint
686                                  * address from this point onward which will enable it to send
687                                  * message without waiting for any application level message from
688                                  * master.
689                                  */
690                                 rpmsg_send(rp_chnl, data, len);
691                                 if (rdev->channel_created) {
692                                         rdev->channel_created(rp_chnl);
693                                 }
694                         }
695                 }
696         }
699 /**
700  * rpmsg_get_address
701  *
702  * This function provides unique 32 bit address.
703  *
704  * @param bitmap - bit map for addresses
705  * @param size   - size of bitmap
706  *
707  * return - a unique address
708  */
709 int rpmsg_get_address(unsigned long *bitmap, int size)
711         int addr = -1;
712         int i, tmp32;
714         /* Find first available buffer */
715         for (i = 0; i < size; i++) {
716                 tmp32 = get_first_zero_bit(bitmap[i]);
718                 if (tmp32 < 32) {
719                         addr = tmp32 + (i*32);
720                         bitmap[i] |= (1 << tmp32);
721                         break;
722                 }
723         }
725         return addr;
728 /**
729  * rpmsg_release_address
730  *
731  * Frees the given address.
732  *
733  * @param bitmap - bit map for addresses
734  * @param size   - size of bitmap
735  * @param addr   - address to free
736  *
737  * return - none
738  */
739 int rpmsg_release_address(unsigned long *bitmap, int size, int addr)
741         unsigned int i, j;
742         unsigned long mask = 1;
744         if (addr >= size * 32)
745                 return -1;
747         /* Mark the addr as available */
748         i = addr / 32;
749         j = addr % 32;
751         mask = mask << j;
752         bitmap[i] = bitmap[i] & (~mask);
754         return RPMSG_SUCCESS;
757 /**
758  * rpmsg_is_address_set
759  *
760  * Checks whether address is used or free.
761  *
762  * @param bitmap - bit map for addresses
763  * @param size   - size of bitmap
764  * @param addr   - address to free
765  *
766  * return - TRUE/FALSE
767  */
768 int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr)
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;
781         return (bitmap[i] & mask);
784 /**
785  * rpmsg_set_address
786  *
787  * Marks the address as consumed.
788  *
789  * @param bitmap - bit map for addresses
790  * @param size   - size of bitmap
791  * @param addr   - address to free
792  *
793  * return - none
794  */
795 int rpmsg_set_address(unsigned long *bitmap, int size, int addr)
797         int i, j;
798         unsigned long mask = 1;
800         if (addr >= size * 32)
801                 return -1;
803         /* Mark the id as available */
804         i = addr / 32;
805         j = addr % 32;
806         mask = mask << j;
807         bitmap[i] |= mask;
809         return RPMSG_SUCCESS;