rpmsg: rdev_init: do not create rpmsg channels before remote is OK
[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"
55 #include "metal/cpu.h"
57 /* Internal functions */
58 static void rpmsg_rx_callback(struct virtqueue *vq);
59 static void rpmsg_tx_callback(struct virtqueue *vq);
61 /**
62  * rpmsg_start_ipc
63  *
64  * This function creates communication links(virtqueues) for remote device
65  * and notifies it to start IPC.
66  *
67  * @param rdev - remote device handle
68  *
69  * @return - status of function execution
70  *
71  */
72 int rpmsg_start_ipc(struct remote_device *rdev)
73 {
74         struct virtio_device *virt_dev;
75         struct rpmsg_endpoint *ns_ept;
76         void (*callback[2]) (struct virtqueue * vq);
77         const char *vq_names[2];
78         unsigned long dev_features;
79         int status;
80         struct virtqueue *vqs[2];
81         int i;
83         virt_dev = &rdev->virt_dev;
85         /* Initialize names and callbacks based on the device role */
86         if (rdev->role == RPMSG_MASTER) {
87                 vq_names[0] = "tx_vq";
88                 vq_names[1] = "rx_vq";
89                 callback[0] = rpmsg_tx_callback;
90                 callback[1] = rpmsg_rx_callback;
91         } else {
92                 vq_names[0] = "rx_vq";
93                 vq_names[1] = "tx_vq";
94                 callback[0] = rpmsg_rx_callback;
95                 callback[1] = rpmsg_tx_callback;
96         }
98         /* Create virtqueues for remote device */
99         status = virt_dev->func->create_virtqueues(virt_dev, 0,
100                                                    RPMSG_MAX_VQ_PER_RDEV,
101                                                    vq_names, callback,
102                                                    RPMSG_NULL);
103         if (status != RPMSG_SUCCESS) {
104                 return status;
105         }
107         dev_features = virt_dev->func->get_features(virt_dev);
109         /*
110          * Create name service announcement endpoint if device supports name
111          * service announcement feature.
112          */
113         if ((dev_features & (1 << VIRTIO_RPMSG_F_NS))) {
114                 rdev->support_ns = RPMSG_TRUE;
115                 ns_ept = _create_endpoint(rdev, rpmsg_ns_callback, rdev,
116                                           RPMSG_NS_EPT_ADDR);
117                 if (!ns_ept) {
118                         return RPMSG_ERR_NO_MEM;
119                 }
120         }
122         /* Initialize notifications for vring. */
123         if (rdev->role == RPMSG_MASTER) {
124                 vqs[0] = rdev->tvq;
125                 vqs[1] = rdev->rvq;
126         } else {
127                 vqs[0] = rdev->rvq;
128                 vqs[1] = rdev->tvq;
129         }
130         for (i = 0; i <= 1; i++) {
131                 status = hil_enable_vring_notifications(i, vqs[i]);
132                 if (status != RPMSG_SUCCESS) {
133                         return status;
134                 }
135         }
137         status = rpmsg_rdev_notify(rdev);
139         return status;
142 /**
143  * _rpmsg_create_channel
144  *
145  * Creates new rpmsg channel with the given parameters.
146  *
147  * @param rdev - pointer to remote device which contains the channel
148  * @param name - name of the device
149  * @param src  - source address for the rpmsg channel
150  * @param dst  - destination address for the rpmsg channel
151  *
152  * @return - pointer to new rpmsg channel
153  *
154  */
155 struct rpmsg_channel *_rpmsg_create_channel(struct remote_device *rdev,
156                                             char *name, unsigned long src,
157                                             unsigned long dst)
159         struct rpmsg_channel *rp_chnl;
161         rp_chnl = metal_allocate_memory(sizeof(struct rpmsg_channel));
162         if (rp_chnl) {
163                 memset(rp_chnl, 0x00, sizeof(struct rpmsg_channel));
164                 strncpy(rp_chnl->name, name, sizeof(rp_chnl->name));
165                 rp_chnl->src = src;
166                 rp_chnl->dst = dst;
167                 rp_chnl->rdev = rdev;
168                 /* Place channel on channels list */
169                 metal_mutex_acquire(&rdev->lock);
170                 metal_list_add_tail(&rdev->rp_channels, &rp_chnl->node);
171                 metal_mutex_release(&rdev->lock);
172         }
174         return rp_chnl;
177 /**
178  * _rpmsg_delete_channel
179  *
180  * Deletes given rpmsg channel.
181  *
182  * @param rp_chnl -  pointer to rpmsg channel to delete
183  *
184  * return - none
185  */
186 void _rpmsg_delete_channel(struct rpmsg_channel *rp_chnl)
188         if (rp_chnl) {
189                 metal_mutex_acquire(&rp_chnl->rdev->lock);
190                 metal_list_del(&rp_chnl->node);
191                 metal_mutex_release(&rp_chnl->rdev->lock);
192                 metal_free_memory(rp_chnl);
193         }
196 /**
197  * _create_endpoint
198  *
199  * This function creates rpmsg endpoint.
200  *
201  * @param rdev    - pointer to remote device
202  * @param cb      - Rx completion call back
203  * @param priv    - private data
204  * @param addr    - endpoint src address
205  *
206  * @return - pointer to endpoint control block
207  *
208  */
209 struct rpmsg_endpoint *_create_endpoint(struct remote_device *rdev,
210                                         rpmsg_rx_cb_t cb, void *priv,
211                                         unsigned long addr)
214         struct rpmsg_endpoint *rp_ept;
215         int status = RPMSG_SUCCESS;
217         rp_ept = metal_allocate_memory(sizeof(struct rpmsg_endpoint));
218         if (!rp_ept) {
219                 return RPMSG_NULL;
220         }
221         memset(rp_ept, 0x00, sizeof(struct rpmsg_endpoint));
223         metal_mutex_acquire(&rdev->lock);
225         if (addr != RPMSG_ADDR_ANY) {
226                 /*
227                  * Application has requested a particular src address for endpoint,
228                  * first check if address is available.
229                  */
230                 if (!rpmsg_is_address_set
231                     (rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr)) {
232                         /* Mark the address as used in the address bitmap. */
233                         rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
234                                           addr);
236                 } else {
237                         status = RPMSG_ERR_DEV_ADDR;
238                 }
239         } else {
240                 addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE);
241                 if ((int)addr < 0) {
242                         status = RPMSG_ERR_DEV_ADDR;
243                 }
244         }
246         /* Do cleanup in case of error and return */
247         if (RPMSG_SUCCESS != status) {
248                 metal_free_memory(rp_ept);
249                 metal_mutex_release(&rdev->lock);
250                 return RPMSG_NULL;
251         }
253         rp_ept->addr = addr;
254         rp_ept->cb = cb;
255         rp_ept->priv = priv;
257         metal_list_add_tail(&rdev->rp_endpoints, &rp_ept->node);
259         metal_mutex_release(&rdev->lock);
261         return rp_ept;
264 /**
265  * rpmsg_destroy_ept
266  *
267  * This function deletes rpmsg endpoint and performs cleanup.
268  *
269  * @param rdev   - pointer to remote device
270  * @param rp_ept - pointer to endpoint to destroy
271  *
272  */
273 void _destroy_endpoint(struct remote_device *rdev,
274                        struct rpmsg_endpoint *rp_ept)
276         metal_mutex_acquire(&rdev->lock);
277         rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
278                               rp_ept->addr);
279         metal_list_del(&rp_ept->node);
280         metal_mutex_release(&rdev->lock);
281         /* free node and rp_ept */
282         metal_free_memory(rp_ept);
285 /**
286  * rpmsg_send_ns_message
287  *
288  * Sends name service announcement to remote device
289  *
290  * @param rdev    - pointer to remote device
291  * @param rp_chnl - pointer to rpmsg channel
292  * @param flags   - Channel creation/deletion flags
293  *
294  */
295 int rpmsg_send_ns_message(struct remote_device *rdev,
296                            struct rpmsg_channel *rp_chnl, unsigned long flags)
299         struct rpmsg_hdr *rp_hdr;
300         struct rpmsg_ns_msg *ns_msg;
301         unsigned short idx;
302         unsigned long len;
304         metal_mutex_acquire(&rdev->lock);
306         /* Get Tx buffer. */
307         rp_hdr = (struct rpmsg_hdr *)rpmsg_get_tx_buffer(rdev, &len, &idx);
308         if (!rp_hdr) {
309                 metal_mutex_release(&rdev->lock);
310                 return -RPMSG_ERR_NO_BUFF;
311         }
313         /* Fill out name service data. */
314         rp_hdr->dst = RPMSG_NS_EPT_ADDR;
315         rp_hdr->len = sizeof(struct rpmsg_ns_msg);
316         ns_msg = (struct rpmsg_ns_msg *) RPMSG_LOCATE_DATA(rp_hdr);
317         strncpy(ns_msg->name, rp_chnl->name, sizeof(rp_chnl->name));
318         ns_msg->flags = flags;
319         ns_msg->addr = rp_chnl->src;
321         /* Place the buffer on virtqueue. */
322         rpmsg_enqueue_buffer(rdev, rp_hdr, len, idx);
324         /* Notify the other side that it has data to process. */
325         virtqueue_kick(rdev->tvq);
327         metal_mutex_release(&rdev->lock);
328         return RPMSG_SUCCESS;
331 /**
332  * rpmsg_enqueue_buffers
333  *
334  * Places buffer on the virtqueue for consumption by the other side.
335  *
336  * @param rdev   - pointer to remote core
337  * @param buffer - buffer pointer
338  * @param len    - buffer length
339  * @idx          - buffer index
340  *
341  * @return - status of function execution
342  *
343  */
344 int rpmsg_enqueue_buffer(struct remote_device *rdev, void *buffer,
345                          unsigned long len, unsigned short idx)
347         int status;
348         struct metal_sg sg;
349         struct metal_io_region *io;
351         io = rdev->proc->sh_buff.io;
352         if (io) {
353                 if (! (io->mem_flags & METAL_UNCACHED))
354                         metal_cache_flush(buffer, (unsigned int)len);
355         }
356         if (rdev->role == RPMSG_REMOTE) {
357                 /* Initialize buffer node */
358                 sg.virt = buffer;
359                 sg.len = len;
360                 sg.io = io;
361                 status = virtqueue_add_buffer(rdev->tvq, &sg, 0, 1, buffer);
362         } else {
363                 (void)sg;
364                 status = virtqueue_add_consumed_buffer(rdev->tvq, idx, len);
365         }
367         return status;
370 /**
371  * rpmsg_return_buffer
372  *
373  * Places the used buffer back on the virtqueue.
374  *
375  * @param rdev   - pointer to remote core
376  * @param buffer - buffer pointer
377  * @param len    - buffer length
378  * @param idx    - buffer index
379  *
380  */
381 void rpmsg_return_buffer(struct remote_device *rdev, void *buffer,
382                          unsigned long len, unsigned short idx)
384         struct metal_sg sg;
386         if (rdev->role == RPMSG_REMOTE) {
387                 /* Initialize buffer node */
388                 sg.virt = buffer;
389                 sg.len = len;
390                 sg.io = rdev->proc->sh_buff.io;
391                 virtqueue_add_buffer(rdev->rvq, &sg, 0, 1, buffer);
392         } else {
393                 (void)sg;
394                 virtqueue_add_consumed_buffer(rdev->rvq, idx, len);
395         }
398 /**
399  * rpmsg_get_tx_buffer
400  *
401  * Provides buffer to transmit messages.
402  *
403  * @param rdev - pointer to remote device
404  * @param len  - length of returned buffer
405  * @param idx  - buffer index
406  *
407  * return - pointer to buffer.
408  */
409 void *rpmsg_get_tx_buffer(struct remote_device *rdev, unsigned long *len,
410                           unsigned short *idx)
412         void *data;
414         if (rdev->role == RPMSG_REMOTE) {
415                 data = virtqueue_get_buffer(rdev->tvq, (uint32_t *) len, idx);
416                 if (data == RPMSG_NULL) {
417                         data = sh_mem_get_buffer(rdev->mem_pool);
418                         *len = RPMSG_BUFFER_SIZE;
419                 }
420         } else {
421                 data =
422                     virtqueue_get_available_buffer(rdev->tvq, idx,
423                                                    (uint32_t *) len);
424         }
425         return data;
428 /**
429  * rpmsg_get_rx_buffer
430  *
431  * Retrieves the received buffer from the virtqueue.
432  *
433  * @param rdev - pointer to remote device
434  * @param len  - size of received buffer
435  * @param idx  - index of buffer
436  *
437  * @return - pointer to received buffer
438  *
439  */
440 void *rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len,
441                           unsigned short *idx)
444         void *data;
445         if (rdev->role == RPMSG_REMOTE) {
446                 data = virtqueue_get_buffer(rdev->rvq, (uint32_t *) len, idx);
447         } else {
448                 data =
449                     virtqueue_get_available_buffer(rdev->rvq, idx,
450                                                    (uint32_t *) len);
451         }
452         if (data) {
453                 struct metal_io_region *io;
454                 io = rdev->proc->sh_buff.io;
455                 if (io) {
456                         if (! (io->mem_flags & METAL_UNCACHED))
457                                 metal_cache_invalidate(data,
458                                         (unsigned int)(*len));
459                 }
460         }
462         return data;
465 /**
466  * rpmsg_free_buffer
467  *
468  * Frees the allocated buffers.
469  *
470  * @param rdev   - pointer to remote device
471  * @param buffer - pointer to buffer to free
472  *
473  */
474 void rpmsg_free_buffer(struct remote_device *rdev, void *buffer)
476         if (rdev->role == RPMSG_REMOTE) {
477                 sh_mem_free_buffer(buffer, rdev->mem_pool);
478         }
481 /**
482  * rpmsg_tx_callback
483  *
484  * Tx callback function.
485  *
486  * @param vq - pointer to virtqueue on which Tx is has been
487  *             completed.
488  *
489  */
490 static void rpmsg_tx_callback(struct virtqueue *vq)
492         struct remote_device *rdev;
493         struct virtio_device *vdev;
494         struct rpmsg_channel *rp_chnl;
495         struct metal_list *node;
497         vdev = (struct virtio_device *)vq->vq_dev;
498         rdev = (struct remote_device *)vdev;
500         /* Check if the remote device is master. */
501         if (rdev->role == RPMSG_MASTER) {
503                 /* Notification is received from the master. Now the remote(us) can
504                  * performs one of two operations;
505                  *
506                  * a. If name service announcement is supported then it will send NS message.
507                  *    else
508                  * b. It will update the channel state to active so that further communication
509                  *    can take place.
510                  */
511                 metal_list_for_each(&rdev->rp_channels, node) {
512                         rp_chnl = metal_container_of(node,
513                                 struct rpmsg_channel, node);
515                         if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
517                                 if (rdev->support_ns) {
518                                         if (rpmsg_send_ns_message(rdev, rp_chnl,
519                                                       RPMSG_NS_CREATE) ==
520                                                 RPMSG_SUCCESS)
521                                                 rp_chnl->state =
522                                                         RPMSG_CHNL_STATE_NS;
523                                 } else {
524                                         rp_chnl->state =
525                                             RPMSG_CHNL_STATE_ACTIVE;
526                                 }
528                         }
530                 }
531         }
534 /**
535  * rpmsg_rx_callback
536  *
537  * Rx callback function.
538  *
539  * @param vq - pointer to virtqueue on which messages is received
540  *
541  */
542 void rpmsg_rx_callback(struct virtqueue *vq)
544         struct remote_device *rdev;
545         struct virtio_device *vdev;
546         struct rpmsg_channel *rp_chnl;
547         struct rpmsg_endpoint *rp_ept;
548         struct rpmsg_hdr *rp_hdr;
549         struct rpmsg_hdr_reserved *reserved;
550         struct metal_list *node;
551         unsigned long len;
552         unsigned short idx;
554         vdev = (struct virtio_device *)vq->vq_dev;
555         rdev = (struct remote_device *)vdev;
557         if (rdev->role == RPMSG_MASTER) {
558                 metal_list_for_each(&rdev->rp_channels, node) {
559                         rp_chnl = metal_container_of(node,
560                                 struct rpmsg_channel, node);
561                         if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
562                                 if (rdev->support_ns) {
563                                         if (rpmsg_send_ns_message(rdev, rp_chnl,
564                                                       RPMSG_NS_CREATE) ==
565                                                 RPMSG_SUCCESS)
566                                                 rp_chnl->state =
567                                                         RPMSG_CHNL_STATE_NS;
568                                 } else {
569                                         rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
570                                 }
571                                 return;
572                         }
573                 }
574         }
576         metal_mutex_acquire(&rdev->lock);
578         /* Process the received data from remote node */
579         rp_hdr = (struct rpmsg_hdr *)rpmsg_get_rx_buffer(rdev, &len, &idx);
581         metal_mutex_release(&rdev->lock);
583         while (rp_hdr) {
585                 /* Get the channel node from the remote device channels list. */
586                 metal_mutex_acquire(&rdev->lock);
587                 rp_ept = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst);
588                 metal_mutex_release(&rdev->lock);
590                 if (!rp_ept)
591                         /* Fatal error no endpoint for the given dst addr. */
592                         return;
594                 rp_chnl = rp_ept->rp_chnl;
596                 if ((rp_chnl) && (rp_chnl->state == RPMSG_CHNL_STATE_NS)) {
597                         /* First message from RPMSG Master, update channel
598                          * destination address and state */
599                         rp_chnl->dst = rp_hdr->src;
600                         rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
602                         /* Notify channel creation to application */
603                         if (rdev->channel_created) {
604                                 rdev->channel_created(rp_chnl);
605                         }
606                 } else {
607                         rp_ept->cb(rp_chnl, (void *)RPMSG_LOCATE_DATA(rp_hdr), rp_hdr->len,
608                                    rp_ept->priv, rp_hdr->src);
609                 }
611                 metal_mutex_acquire(&rdev->lock);
613                 /* Check whether callback wants to hold buffer */
614                 if (rp_hdr->reserved & RPMSG_BUF_HELD)
615                 {
616                         /* 'rp_hdr->reserved' field is now used as storage for
617                          * 'idx' to release buffer later */
618                         reserved = (struct rpmsg_hdr_reserved*)&rp_hdr->reserved;
619                         reserved->idx = (uint16_t)idx;
620                 } else {
621                         /* Return used buffers. */
622                         rpmsg_return_buffer(rdev, rp_hdr, len, idx);
623                 }
625                 rp_hdr =
626                     (struct rpmsg_hdr *)rpmsg_get_rx_buffer(rdev, &len, &idx);
627                 metal_mutex_release(&rdev->lock);
628         }
631 /**
632  * rpmsg_ns_callback
633  *
634  * This callback handles name service announcement from the remote device
635  * and creates/deletes rpmsg channels.
636  *
637  * @param server_chnl - pointer to server channel control block.
638  * @param data        - pointer to received messages
639  * @param len         - length of received data
640  * @param priv        - any private data
641  * @param src         - source address
642  *
643  * @return - none
644  */
645 void rpmsg_ns_callback(struct rpmsg_channel *server_chnl, void *data, int len,
646                        void *priv, unsigned long src)
648         struct remote_device *rdev;
649         struct rpmsg_channel *rp_chnl;
650         struct rpmsg_ns_msg *ns_msg;
652         (void)server_chnl;
653         (void)src;
655         rdev = (struct remote_device *)priv;
657         //FIXME: This assumes same name string size for channel name both on master
658         //and remote. If this is not the case then we will have to parse the
659         //message contents.
661         ns_msg = (struct rpmsg_ns_msg *)data;
662         ns_msg->name[len - 1] = '\0';
664         if (ns_msg->flags & RPMSG_NS_DESTROY) {
665                 metal_mutex_acquire(&rdev->lock);
666                 rp_chnl = rpmsg_rdev_get_chnl_from_id(rdev, ns_msg->name);
667                 metal_mutex_release(&rdev->lock);
668                 if (rp_chnl) {
669                         if (rdev->channel_destroyed) {
670                                 rdev->channel_destroyed(rp_chnl);
671                         }
672                         rpmsg_destroy_ept(rp_chnl->rp_ept);
673                         _rpmsg_delete_channel(rp_chnl);
674                 }
675         } else {
676                 rp_chnl =
677                     _rpmsg_create_channel(rdev, ns_msg->name, 0x00,
678                                           ns_msg->addr);
679                 if (rp_chnl) {
680                         rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
681                         /* Create default endpoint for channel */
682                         rp_chnl->rp_ept =
683                             rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
684                                              RPMSG_ADDR_ANY);
685                         if (rp_chnl->rp_ept) {
686                                 rp_chnl->src = rp_chnl->rp_ept->addr;
687                                 /*
688                                  * Echo back the NS message to remote in order to
689                                  * complete the connection stage. Remote will know the endpoint
690                                  * address from this point onward which will enable it to send
691                                  * message without waiting for any application level message from
692                                  * master.
693                                  */
694                                 rpmsg_send(rp_chnl, data, len);
695                                 if (rdev->channel_created) {
696                                         rdev->channel_created(rp_chnl);
697                                 }
698                         }
699                 }
700         }
703 /**
704  * rpmsg_get_address
705  *
706  * This function provides unique 32 bit address.
707  *
708  * @param bitmap - bit map for addresses
709  * @param size   - size of bitmap
710  *
711  * return - a unique address
712  */
713 int rpmsg_get_address(unsigned long *bitmap, int size)
715         int addr = -1;
716         int i, tmp32;
718         /* Find first available buffer */
719         for (i = 0; i < size; i++) {
720                 tmp32 = get_first_zero_bit(bitmap[i]);
722                 if (tmp32 < 32) {
723                         addr = tmp32 + (i*32);
724                         bitmap[i] |= (1 << tmp32);
725                         break;
726                 }
727         }
729         return addr;
732 /**
733  * rpmsg_release_address
734  *
735  * Frees the given address.
736  *
737  * @param bitmap - bit map for addresses
738  * @param size   - size of bitmap
739  * @param addr   - address to free
740  *
741  * return - none
742  */
743 int rpmsg_release_address(unsigned long *bitmap, int size, int addr)
745         unsigned int i, j;
746         unsigned long mask = 1;
748         if (addr >= size * 32)
749                 return -1;
751         /* Mark the addr as available */
752         i = addr / 32;
753         j = addr % 32;
755         mask = mask << j;
756         bitmap[i] = bitmap[i] & (~mask);
758         return RPMSG_SUCCESS;
761 /**
762  * rpmsg_is_address_set
763  *
764  * Checks whether address is used or free.
765  *
766  * @param bitmap - bit map for addresses
767  * @param size   - size of bitmap
768  * @param addr   - address to free
769  *
770  * return - TRUE/FALSE
771  */
772 int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr)
774         int i, j;
775         unsigned long mask = 1;
777         if (addr >= size * 32)
778                 return -1;
780         /* Mark the id as available */
781         i = addr / 32;
782         j = addr % 32;
783         mask = mask << j;
785         return (bitmap[i] & mask);
788 /**
789  * rpmsg_set_address
790  *
791  * Marks the address as consumed.
792  *
793  * @param bitmap - bit map for addresses
794  * @param size   - size of bitmap
795  * @param addr   - address to free
796  *
797  * return - none
798  */
799 int rpmsg_set_address(unsigned long *bitmap, int size, int addr)
801         int i, j;
802         unsigned long mask = 1;
804         if (addr >= size * 32)
805                 return -1;
807         /* Mark the id as available */
808         i = addr / 32;
809         j = addr % 32;
810         mask = mask << j;
811         bitmap[i] |= mask;
813         return RPMSG_SUCCESS;