cvmx-shmem.c revision 215976
1130561Sobrien/***********************license start***************
2130561Sobrien * Copyright (c) 2003-2010  Cavium Networks (support@cavium.com). All rights
3130561Sobrien * reserved.
4130561Sobrien *
5130561Sobrien *
6130561Sobrien * Redistribution and use in source and binary forms, with or without
7130561Sobrien * modification, are permitted provided that the following conditions are
8130561Sobrien * met:
9130561Sobrien *
10130561Sobrien *   * Redistributions of source code must retain the above copyright
11130561Sobrien *     notice, this list of conditions and the following disclaimer.
12130561Sobrien *
13130561Sobrien *   * Redistributions in binary form must reproduce the above
14130561Sobrien *     copyright notice, this list of conditions and the following
15130561Sobrien *     disclaimer in the documentation and/or other materials provided
16130561Sobrien *     with the distribution.
17130561Sobrien
18218822Sdim *   * Neither the name of Cavium Networks nor the names of
19130561Sobrien *     its contributors may be used to endorse or promote products
20130561Sobrien *     derived from this software without specific prior written
21130561Sobrien *     permission.
22130561Sobrien
23130561Sobrien * This Software, including technical data, may be subject to U.S. export  control
24130561Sobrien * laws, including the U.S. Export Administration Act and its  associated
25130561Sobrien * regulations, and may be subject to export or import  regulations in other
26130561Sobrien * countries.
27130561Sobrien
28130561Sobrien * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29130561Sobrien * AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR
30130561Sobrien * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31130561Sobrien * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32130561Sobrien * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33130561Sobrien * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34130561Sobrien * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35130561Sobrien * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36130561Sobrien * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37130561Sobrien * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38130561Sobrien ***********************license end**************************************/
39130561Sobrien
40130561Sobrien
41130561Sobrien
42130561Sobrien/**
43130561Sobrien * @file
44130561Sobrien *   cvmx-shmem supplies the cross application shared memory implementation
45130561Sobrien *
46130561Sobrien * <hr>$Revision: 41586 $<hr>
47130561Sobrien */
48130561Sobrien#include "cvmx.h"
49130561Sobrien#include "cvmx-bootmem.h"
50130561Sobrien#include "cvmx-tlb.h"
51130561Sobrien#include "cvmx-shmem.h"
52130561Sobrien
53130561Sobrien//#define DEBUG
54130561Sobrien
55130561Sobrienstruct cvmx_shmem_smdr *__smdr = NULL;
56130561Sobrien
57130561Sobrien#ifdef CVMX_BUILD_FOR_LINUX_USER
58130561Sobrienstatic int __cvmx_shmem_devmemfd = 0;   /* fd for /dev/mem */
59130561Sobrien#endif
60130561Sobrien
61130561Sobrien#define __CHECK_APP_SMDR  do { \
62130561Sobrien                if (__smdr == NULL) { \
63130561Sobrien                    cvmx_dprintf("cvmx_shmem: %s is not set up, Quit line %d \n", \
64130561Sobrien                        CVMX_SHMEM_DSCPTR_NAME, __LINE__ ); \
65130561Sobrien                    exit(-1); \
66130561Sobrien                } \
67130561Sobrien              }while(0)
68130561Sobrien
69130561Sobrien
70130561Sobrien
71130561Sobrien/**
72130561Sobrien * @INTERNAL
73130561Sobrien * Virtual sbrk, assigning virtual address in a global virtual address space.
74130561Sobrien *
75130561Sobrien * @param alignment   alignment requirement in bytes
76130561Sobrien * @param size        size in bytes
77130561Sobrien */
78130561Sobrienstatic inline void *__cvmx_shmem_vsbrk_64(uint64_t alignment, uint64_t size)
79130561Sobrien{
80130561Sobrien    uint64_t nbase_64 = CAST64(__smdr->break64);
81130561Sobrien    void *nbase = NULL;
82130561Sobrien
83130561Sobrien    /* Skip unaligned bytes */
84130561Sobrien    if (nbase_64 & alignment)
85130561Sobrien        nbase_64 += ~(nbase_64 & alignment) + 1;
86130561Sobrien
87130561Sobrien    if (nbase_64 + size  <  CVMX_SHMEM_VADDR64_END)
88130561Sobrien    {
89130561Sobrien        nbase = CASTPTR(void *, nbase_64);
90130561Sobrien        __smdr->break64 = nbase + size;
91130561Sobrien    }
92130561Sobrien
93130561Sobrien    return nbase;
94130561Sobrien}
95130561Sobrien
96130561Sobrien/**
97130561Sobrien * @INTERNAL
98130561Sobrien * Initialize all SMDR entries, only need to be called once
99130561Sobrien *
100130561Sobrien * @param smdr pointer to the SMDR
101130561Sobrien */
102130561Sobrienstatic inline void __smdr_new(struct cvmx_shmem_smdr *smdr) {
103130561Sobrien
104130561Sobrien    if (smdr != NULL)
105130561Sobrien    {
106130561Sobrien        int i;
107130561Sobrien
108130561Sobrien        cvmx_spinlock_init (&smdr->lock);
109130561Sobrien        cvmx_spinlock_lock (&smdr->lock);
110130561Sobrien
111130561Sobrien        for ( i = 0; i < CVMX_SHMEM_NUM_DSCPTR; i++ )
112130561Sobrien        {
113130561Sobrien            smdr -> shmd[i].owner = CVMX_SHMEM_OWNER_NONE;
114130561Sobrien            smdr -> shmd[i].is_named_block = 0;
115130561Sobrien            smdr -> shmd[i].use_count = 0;
116130561Sobrien            smdr -> shmd[i].name = NULL;
117130561Sobrien            smdr -> shmd[i].vaddr = NULL;
118130561Sobrien            smdr -> shmd[i].paddr = 0;
119130561Sobrien            smdr -> shmd[i].size = 0;
120130561Sobrien            smdr -> shmd[i].alignment = 0;
121130561Sobrien        };
122130561Sobrien
123130561Sobrien        /* Init vaddr */
124130561Sobrien        smdr->break64 = (void *)CVMX_SHMEM_VADDR64_START;
125130561Sobrien        cvmx_spinlock_unlock (&smdr->lock);
126130561Sobrien    }
127130561Sobrien
128130561Sobrien    /* Make sure the shmem descriptor region is created */
129130561Sobrien    __CHECK_APP_SMDR;
130130561Sobrien};
131130561Sobrien
132130561Sobrien
133130561Sobrien
134130561Sobrien/**
135130561Sobrien * @INTERNAL
136130561Sobrien * Initialize __smdr pointer, if SMDR exits already. If not, create a new
137130561Sobrien * one.  Once SMDR is created (as a bootmem named block), it is persistent.
138130561Sobrien */
139130561Sobrienstatic inline struct cvmx_shmem_smdr *__smdr_init()
140130561Sobrien{
141130561Sobrien    const cvmx_bootmem_named_block_desc_t *smdr_nblk = NULL;
142130561Sobrien    size_t smdr_size = sizeof(*__smdr);
143130561Sobrien    char *smdr_name = CVMX_SHMEM_DSCPTR_NAME;
144130561Sobrien
145130561Sobrien    __smdr = (struct cvmx_shmem_smdr *) cvmx_bootmem_alloc_named(smdr_size, 0x10000, smdr_name);
146130561Sobrien
147130561Sobrien    if (__smdr)
148130561Sobrien       __smdr_new (__smdr);
149130561Sobrien    else
150130561Sobrien    {
151130561Sobrien        /* Check if SMDR exists already */
152130561Sobrien        smdr_nblk = cvmx_bootmem_find_named_block(smdr_name);
153130561Sobrien        if (smdr_nblk)
154130561Sobrien        {
155130561Sobrien            __smdr = (struct cvmx_shmem_smdr *)
156130561Sobrien            (cvmx_phys_to_ptr(smdr_nblk->base_addr));
157130561Sobrien
158130561Sobrien            cvmx_spinlock_lock (&__smdr->lock);
159130561Sobrien            if (smdr_nblk->size != smdr_size)
160130561Sobrien            {
161130561Sobrien                cvmx_dprintf("SMDR named block is created by another "
162130561Sobrien                    "application with different size %lu, "
163130561Sobrien                    "expecting %lu \n",
164130561Sobrien                    (long unsigned int)smdr_nblk->size, (long unsigned int)smdr_size);
165130561Sobrien                __smdr = NULL;
166130561Sobrien            }
167130561Sobrien            cvmx_spinlock_unlock (&__smdr->lock);
168130561Sobrien        }
169130561Sobrien    }
170130561Sobrien
171130561Sobrien   if (!__smdr)
172130561Sobrien       cvmx_dprintf("cvmx_shmem: Failed to allocate or find SMDR from bootmem \n");
173130561Sobrien
174130561Sobrien   return __smdr;
175130561Sobrien};
176130561Sobrien
177130561Sobrien
178130561Sobrien/**
179130561Sobrien * @INTERNAL
180130561Sobrien * Generic Iterator function for all SMDR entries
181130561Sobrien *
182130561Sobrien * @param void(*f)(dscptr) the function to be invoked for every descriptor
183130561Sobrien * @param param
184130561Sobrien *
185130561Sobrien * @return the descriptor iterator stopped at.
186130561Sobrien */
187130561Sobrienstatic struct cvmx_shmem_dscptr *__smdr_iterator(struct cvmx_shmem_dscptr *(*f)(struct cvmx_shmem_dscptr *dscptr, void *p), void *param )
188130561Sobrien{
189130561Sobrien    struct cvmx_shmem_dscptr *d, *dscptr = NULL;
190130561Sobrien    int i;
191130561Sobrien
192130561Sobrien    __CHECK_APP_SMDR;
193130561Sobrien
194130561Sobrien    for (i = 0; i < CVMX_SHMEM_NUM_DSCPTR; i++)
195130561Sobrien    {
196130561Sobrien        d = &__smdr->shmd[i];
197130561Sobrien        if ((dscptr = (*f)(d, param)) != NULL)
198130561Sobrien            break;      /* stop iteration */
199130561Sobrien    }
200130561Sobrien
201130561Sobrien   return dscptr;
202130561Sobrien}
203130561Sobrien
204130561Sobrien
205130561Sobrien/**
206130561Sobrien * @INTERNAL
207130561Sobrien * SMDR name match functor. to be used for iterator.
208130561Sobrien *
209130561Sobrien * @param dscptr  descriptor passed in by the iterator
210130561Sobrien * @param   name    string to match against
211130561Sobrien *
212130561Sobrien * @return !NULL   descriptor matched
213130561Sobrien *     NULL    not match
214130561Sobrien */
215130561Sobrienstatic struct cvmx_shmem_dscptr *__cvmx_shmem_smdr_match_name(struct cvmx_shmem_dscptr *dscptr, void *name)
216130561Sobrien{
217130561Sobrien    char *name_to_match = (char *) name;
218130561Sobrien    struct cvmx_shmem_dscptr *ret = NULL;
219130561Sobrien
220130561Sobrien    if (dscptr->owner == CVMX_SHMEM_OWNER_NONE)
221130561Sobrien        return NULL;
222130561Sobrien
223130561Sobrien    if (strcmp(dscptr->name, name_to_match) == 0)
224130561Sobrien        ret =  dscptr;
225130561Sobrien
226130561Sobrien    return ret;
227130561Sobrien}
228130561Sobrien
229130561Sobrien/**
230130561Sobrien * @INTERNAL
231130561Sobrien * Find by name
232130561Sobrien *
233130561Sobrien * @param   name    string to match against
234130561Sobrien *
235130561Sobrien * @return !NULL    descriptor matched
236130561Sobrien *          NULL    not match
237130561Sobrien */
238130561Sobrienstatic struct cvmx_shmem_dscptr *__cvmx_shmem_smdr_find_by_name(char *name)
239130561Sobrien{
240130561Sobrien    return __smdr_iterator( __cvmx_shmem_smdr_match_name, name);
241130561Sobrien}
242130561Sobrien
243130561Sobrien/**
244130561Sobrien * @INTERNAL
245130561Sobrien * SMDR is free functor. to be used for iterator.
246130561Sobrien *
247130561Sobrien * @param dscptr  descriptor passed in by the iterator
248130561Sobrien * @param nouse
249130561Sobrien *
250130561Sobrien * @return !NULL  descriptor is free
251130561Sobrien *          NULL  descriptor is not free
252130561Sobrien */
253130561Sobrienstatic struct cvmx_shmem_dscptr *__cvmx_shmem_smdr_is_free(struct cvmx_shmem_dscptr* dscptr, void *nouse)
254130561Sobrien{
255130561Sobrien    if (dscptr->owner == CVMX_SHMEM_OWNER_NONE)
256130561Sobrien        return dscptr;
257130561Sobrien    else
258130561Sobrien        return NULL;
259130561Sobrien}
260130561Sobrien
261130561Sobrien/**
262130561Sobrien * @INTERNAL
263130561Sobrien * Search SMDR to find the first free descriptor
264130561Sobrien *
265130561Sobrien * @return !NULL   free descriptor found
266130561Sobrien *     NULL    nothing found
267130561Sobrien */
268130561Sobrienstruct cvmx_shmem_dscptr *__cvmx_shmem_smdr_find_free_dscptr(void)
269130561Sobrien{
270130561Sobrien    return __smdr_iterator(__cvmx_shmem_smdr_is_free, NULL);
271130561Sobrien}
272130561Sobrien
273130561Sobrien/**
274130561Sobrien * @INTERNAL
275130561Sobrien * free a descriptor
276130561Sobrien *
277130561Sobrien * @param dscptr  descriptor to be freed
278130561Sobrien */
279130561Sobrienstatic void __cvmx_shmem_smdr_free(struct cvmx_shmem_dscptr *dscptr)
280130561Sobrien{
281130561Sobrien    dscptr->owner = CVMX_SHMEM_OWNER_NONE;
282130561Sobrien}
283130561Sobrien
284130561Sobrien
285130561Sobrien/**
286130561Sobrien * Per core shmem init function
287130561Sobrien *
288130561Sobrien * @return  cvmx_shmem_smdr*   pointer to __smdr
289130561Sobrien */
290130561Sobrienstruct cvmx_shmem_smdr *cvmx_shmem_init()
291130561Sobrien{
292130561Sobrien    return __smdr_init();
293130561Sobrien}
294130561Sobrien
295130561Sobrien/**
296130561Sobrien * Open shared memory based on named block
297130561Sobrien *
298130561Sobrien * @return  dscptr descriptor of the opened named block
299130561Sobrien */
300130561Sobrienstruct cvmx_shmem_dscptr *cvmx_shmem_named_block_open(char *name, uint32_t size, int oflag)
301130561Sobrien{
302130561Sobrien    const cvmx_bootmem_named_block_desc_t *shmem_nblk = NULL;
303130561Sobrien    struct cvmx_shmem_dscptr *dscptr = NULL;
304130561Sobrien    int nblk_allocated = 0; /* Assume we don't need to allocate a new
305130561Sobrien                               bootmem block */
306130561Sobrien    void *vaddr = NULL;
307130561Sobrien    const uint64_t size_4k = 4*1024, size_512mb = 512*1024*1024;
308130561Sobrien
309130561Sobrien    __CHECK_APP_SMDR;
310130561Sobrien
311130561Sobrien    /* Check size, Make sure it is minimal 4K, no bigger than 512MB */
312130561Sobrien    if (size > size_512mb) {
313130561Sobrien        cvmx_dprintf("Shared memory size can not be bigger than 512MB \n");
314130561Sobrien        return NULL;
315130561Sobrien    }
316130561Sobrien    if (size < size_4k)
317130561Sobrien        size = size_4k;
318130561Sobrien
319130561Sobrien    size = __upper_power_of_two(size);
320130561Sobrien
321130561Sobrien    cvmx_spinlock_lock(&__smdr->lock);
322130561Sobrien
323130561Sobrien    shmem_nblk = cvmx_bootmem_find_named_block(name);
324130561Sobrien    if ((shmem_nblk == NULL) &&  (oflag & CVMX_SHMEM_O_CREAT))
325130561Sobrien    {
326130561Sobrien       void *p;
327130561Sobrien       /* The named block does not exist, create it if caller specifies
328130561Sobrien          the O_CREAT flag */
329130561Sobrien        nblk_allocated = 1;
330130561Sobrien        p = cvmx_bootmem_alloc_named(size, size, name);
331130561Sobrien        if (p)
332130561Sobrien            shmem_nblk = cvmx_bootmem_find_named_block(name);
333130561Sobrien#ifdef DEBUG
334130561Sobrien        cvmx_dprintf("cvmx-shmem-dbg:"
335130561Sobrien             "creating a new block %s: blk %p, shmem_nblk %p \n",
336130561Sobrien             name, p, shmem_nblk);
337130561Sobrien#endif
338130561Sobrien    }
339130561Sobrien
340130561Sobrien    if (shmem_nblk == NULL)
341130561Sobrien        goto err;
342130561Sobrien
343130561Sobrien    /* We are now holding a valid named block */
344130561Sobrien
345130561Sobrien    dscptr = __cvmx_shmem_smdr_find_by_name(name);
346130561Sobrien    if (dscptr)
347130561Sobrien    {
348130561Sobrien        if (nblk_allocated)
349130561Sobrien        {
350130561Sobrien            /* name conflict between bootmem name space and SMDR name space */
351130561Sobrien            cvmx_dprintf("cvmx-shmem: SMDR descriptor name conflict, %s \n", name);
352130561Sobrien            goto err;
353130561Sobrien        }
354130561Sobrien        /* Make sure size and alignment matches with existing descriptor */
355130561Sobrien        if ((size != dscptr->size) ||  (size != dscptr -> alignment))
356130561Sobrien            goto err;
357130561Sobrien    }
358130561Sobrien    else
359130561Sobrien    {
360130561Sobrien        /* Create a new descriptor */
361130561Sobrien        dscptr = __cvmx_shmem_smdr_find_free_dscptr();
362130561Sobrien        if (dscptr)
363130561Sobrien            goto init;
364130561Sobrien        else
365130561Sobrien        {
366130561Sobrien            cvmx_dprintf("cvmx-shmem: SMDR out of descriptors \n");
367130561Sobrien            goto err;
368130561Sobrien        }
369130561Sobrien    }
370130561Sobrien
371130561Sobrien    /* Maintain the reference count */
372130561Sobrien    if (dscptr != NULL)
373130561Sobrien        dscptr->use_count += 1;
374130561Sobrien
375130561Sobrien    cvmx_spinlock_unlock(&__smdr->lock);
376130561Sobrien    return dscptr;
377130561Sobrien
378130561Sobrienerr:
379130561Sobrien#ifdef DEBUG
380130561Sobrien    cvmx_dprintf("cvmx-shmem-dbg: named block open failed \n");
381130561Sobrien#endif
382130561Sobrien
383130561Sobrien    if (dscptr)
384130561Sobrien        __cvmx_shmem_smdr_free(dscptr);
385130561Sobrien    if (shmem_nblk && nblk_allocated)
386130561Sobrien        cvmx_bootmem_free_named(name);
387130561Sobrien    cvmx_spinlock_unlock(&__smdr->lock);
388130561Sobrien
389130561Sobrien    return NULL;
390130561Sobrien
391130561Sobrieninit:
392130561Sobrien
393130561Sobrien#ifdef DEBUG
394130561Sobrien    cvmx_dprintf("cvmx-shmem-dbg: init SMDR descriptor %p \n", dscptr);
395130561Sobrien#endif
396130561Sobrien
397130561Sobrien    /* Assign vaddr for single address space mapping */
398130561Sobrien    vaddr = __cvmx_shmem_vsbrk_64(size, size);
399130561Sobrien    if (vaddr == NULL) {
400130561Sobrien        /* Failed to allocate virtual address, clean up */
401130561Sobrien        goto err;
402130561Sobrien    }
403130561Sobrien
404130561Sobrien#ifdef DEBUG
405130561Sobrien    cvmx_dprintf("cmvx-shmem-dbg: allocated vaddr %p \n", vaddr);
406130561Sobrien#endif
407130561Sobrien    dscptr->vaddr = vaddr;
408130561Sobrien
409130561Sobrien    /* Store descriptor information,  name, alignment,size... */
410130561Sobrien    dscptr->owner = cvmx_get_core_num();
411130561Sobrien    dscptr->is_named_block = 1;
412130561Sobrien    dscptr->use_count = 1;
413130561Sobrien    dscptr->name =shmem_nblk->name ;
414130561Sobrien    dscptr->paddr = shmem_nblk->base_addr;
415130561Sobrien    dscptr->size = size;
416130561Sobrien    dscptr->alignment = size;
417130561Sobrien
418130561Sobrien    /* Store permission bits */
419130561Sobrien    if (oflag & CVMX_SHMEM_O_WRONLY)
420130561Sobrien        dscptr->p_wronly = 1;
421130561Sobrien    if (oflag & CVMX_SHMEM_O_RDWR)
422130561Sobrien        dscptr->p_rdwr = 1;
423
424   cvmx_spinlock_unlock(&__smdr->lock);
425   return dscptr;
426}
427
428/**
429 * @INTERNAL
430 *
431 *  For stand along SE application only.
432 *
433 *  Add TLB mapping to map the shared memory
434 *
435 *  @param dscptr  shared memory descriptor
436 *  @param pflag   protection flags
437 *
438 *  @return vaddr  the virtual address mapped for the shared memory
439 */
440#ifndef CVMX_BUILD_FOR_LINUX_USER
441void *__cvmx_shmem_map_standalone(struct cvmx_shmem_dscptr *dscptr, int pflag)
442{
443    int free_index;
444
445    /* Find a free tlb entry */
446    free_index = cvmx_tlb_allocate_runtime_entry();
447
448    if (free_index < 0 )
449    {
450        cvmx_dprintf("cvmx-shmem: shmem_map failed, out TLB entries \n");
451        return NULL;
452    }
453
454#ifdef DEBUG
455    cvmx_dprintf("cmvx-shmem-dbg:"
456         "shmem_map TLB %d: vaddr %p paddr %lx, size %x \n",
457         free_index, dscptr->vaddr, dscptr->paddr, dscptr->size );
458#endif
459
460    cvmx_tlb_write_runtime_entry(free_index, CAST64(dscptr->vaddr),
461            dscptr->paddr, dscptr->size,
462            TLB_DIRTY | TLB_VALID | TLB_GLOBAL);
463
464    return dscptr -> vaddr;
465}
466#endif
467
468/**
469 * @INTERNAL
470 *
471 *  For Linux user application only
472 *
473 *  Add mmap the shared memory
474 *
475 *  @param dscptr  shared memory descriptor
476 *  @param pflag   protection flags
477 *
478 *  @return vaddr  the virtual address mapped for the shared memory
479 */
480#ifdef CVMX_BUILD_FOR_LINUX_USER
481static inline void *__cvmx_shmem_map_linux(struct cvmx_shmem_dscptr *dscptr, int pflag)
482{
483    void *vaddr = NULL;
484
485    if(__cvmx_shmem_devmemfd == 0)
486    {
487        __cvmx_shmem_devmemfd = open("/dev/mem", O_RDWR);
488        if (__cvmx_shmem_devmemfd < 0)
489        {
490            cvmx_dprintf("Failed to open /dev/mem\n");
491            exit(-1);
492        }
493    }
494
495    vaddr = mmap(dscptr->vaddr, dscptr->size, PROT_READ|PROT_WRITE,
496                 MAP_SHARED, __cvmx_shmem_devmemfd, 0);
497
498    /* Make sure the mmap maps to the same virtual address specified in
499     * descriptor
500     */
501    if ((vaddr!=NULL) && (vaddr != dscptr->vaddr))
502    {
503        munmap(vaddr, dscptr->size);
504        vaddr = NULL;
505    }
506    return vaddr;
507}
508#endif
509
510/**
511 *  cvmx_shmem API
512 *
513 *  Add mapping for the shared memory
514 *
515 *  @param dscptr  shared memory descriptor
516 *  @param pflag   protection flags
517 *
518 *  @return vaddr  the virtual address mapped for the shared memory
519 */
520void *cvmx_shmem_map(struct cvmx_shmem_dscptr *dscptr, int pflag)
521{
522    void *vaddr = NULL;
523#ifdef CVMX_BUILD_FOR_LINUX_USER
524    vaddr = __cvmx_shmem_map_linux(dscptr, pflag);
525#else
526    vaddr = __cvmx_shmem_map_standalone(dscptr, pflag);
527#endif
528    return vaddr;
529}
530
531
532/**
533 * @INTERNAL
534 *
535 *  For Linux user application only
536 *
537 *  ummap the shared memory
538 *
539 *  @param dscptr  shared memory descriptor
540 *
541 */
542#ifdef CVMX_BUILD_FOR_LINUX_USER
543static inline void __cvmx_shmem_unmap_linux(struct cvmx_shmem_dscptr* dscptr)
544{
545    if (__cvmx_shmem_devmemfd && dscptr)
546        munmap(dscptr->vaddr, dscptr->size);
547}
548#endif
549
550
551/**
552 * @INTERNAL
553 *
554 *  For stand along SE application only.
555 *
556 *  ummap the shared memory
557 *
558 *  @param dscptr  shared memory descriptor
559 *
560 */
561#ifndef CVMX_BUILD_FOR_LINUX_USER
562static inline void
563__cvmx_shmem_unmap_standalone(struct cvmx_shmem_dscptr *dscptr)
564{
565    int index;
566
567    index = cvmx_tlb_lookup(CAST64(dscptr->vaddr));
568
569#ifdef DEBUG
570    cvmx_dprintf("cmvx-shmem-dbg:"
571             "shmem_unmap TLB %d \n", index);
572#endif
573    cvmx_tlb_free_runtime_entry(index);
574}
575#endif
576
577/**
578 *  ummap the shared memory
579 *
580 *  @param dscptr  shared memory descriptor
581 *
582 */
583void cvmx_shmem_unmap(struct cvmx_shmem_dscptr *dscptr)
584{
585#ifdef CVMX_BUILD_FOR_LINUX_USER
586    __cvmx_shmem_unmap_linux(dscptr);
587#else
588    __cvmx_shmem_unmap_standalone(dscptr);
589#endif
590}
591
592/**
593 * @INTERNAL
594 *
595 *  Common implementation of closing a descriptor.
596 *
597 *  @param dscptr  shared memory descriptor
598 *  @param remove  1:  remove the descriptor and named block if this
599 *                  this is the last user of the descriptor
600 *             0:  do not remove
601 *  @return  0:   Success
602 *          !0:   Failed
603 *
604 */
605static inline int __cvmx_shmem_close_dscptr(struct cvmx_shmem_dscptr *dscptr, int remove)
606{
607    cvmx_spinlock_lock(&dscptr->lock);
608
609    if (dscptr->use_count >0)
610        dscptr->use_count-= 1;
611
612    if ((dscptr->use_count == 0) && remove)
613    {
614        /* Free this descriptor */
615        __cvmx_shmem_smdr_free(dscptr);
616
617        /* Free named block if this is the last user, and the block
618           is created by the application */
619        if (dscptr->is_named_block)
620        {
621#ifdef DEBUG
622            cvmx_dprintf("cvmx-shmem-dbg: remove named block %s \n", dscptr->name);
623#endif
624            cvmx_bootmem_phy_named_block_free(dscptr->name, 0);
625        }
626    }
627    cvmx_spinlock_unlock(&dscptr->lock);
628    return 0;
629}
630
631
632/**
633 * @INTERNAL
634 *
635 *  For stand along SE application only.
636 *
637 *  close a descriptor.
638 *
639 *  @param dscptr  shared memory descriptor
640 *  @param remove  1:  remove the descriptor and named block if this
641 *                  this is the last user of the descriptor
642 *             0:  do not remove
643 *  @return  0:   Success
644 *          !0:   Failed
645 *
646 */
647#ifndef CVMX_BUILD_FOR_LINUX_USER
648static inline int __cvmx_shmem_close_standalone(struct cvmx_shmem_dscptr *dscptr, int remove)
649{
650    return __cvmx_shmem_close_dscptr(dscptr, remove);
651}
652#endif
653
654/**
655 * @INTERNAL
656 *
657 *  For Linux user application only.
658 *
659 *  close a descriptor.
660 *
661 *  @param dscptr  shared memory descriptor
662 *  @param remove  1:  remove the descriptor and named block if this
663 *                  this is the last user of the descriptor
664 *             0:  do not remove
665 *  @return  0:   Success
666 *          !0:   Failed
667 *
668 */
669#ifdef CVMX_BUILD_FOR_LINUX_USER
670int __cvmx_shmem_close_linux(struct cvmx_shmem_dscptr *dscptr, int remove)
671{
672    int ret;
673    ret = __cvmx_shmem_close_dscptr(dscptr, remove);
674
675    if (ret && __cvmx_shmem_devmemfd)
676    {
677        close(__cvmx_shmem_devmemfd);
678         __cvmx_shmem_devmemfd=0;
679    }
680
681    return ret;
682
683}
684#endif
685
686/**
687 *
688 *  close a descriptor.
689 *
690 *  @param dscptr  shared memory descriptor
691 *  @param remove  1:  remove the descriptor and named block if this
692 *                  this is the last user of the descriptor
693 *             0:  do not remove
694 *  @return  0:   Success
695 *          !0:   Failed
696 *
697 */
698int cvmx_shmem_close(struct cvmx_shmem_dscptr *dscptr, int remove)
699{
700    int ret;
701#ifdef CVMX_BUILD_FOR_LINUX_USER
702    ret = __cvmx_shmem_close_linux(dscptr, remove);
703#else
704    ret = __cvmx_shmem_close_standalone(dscptr, remove);
705#endif
706    return ret;
707}
708
709#ifdef DEBUG
710/**
711 * @INTERNAL
712 *  SMDR non-free descriptor dump functor. to be used for iterator.
713 *
714 * @param dscptr  descriptor passed in by the iterator
715 *
716 * @return NULL  always
717 */
718static struct cvmx_shmem_dscptr *__cvmx_shmem_smdr_display_dscptr(struct cvmx_shmem_dscptr *dscptr, void *nouse)
719{
720    if ((dscptr != NULL ) && (dscptr -> owner != CVMX_SHMEM_OWNER_NONE))
721    {
722        cvmx_dprintf("  %s: phy: %lx, size %d, alignment %lx, virt %p use_count %d\n",
723            dscptr->name, dscptr-> paddr,
724            dscptr->size, dscptr-> alignment,
725            dscptr->vaddr, dscptr->use_count);
726    }
727
728    return NULL;
729}
730#endif
731
732/**
733 *  SMDR descriptor show
734 *
735 *  list all non-free descriptors
736 */
737void cvmx_shmem_show(void)
738{
739    __CHECK_APP_SMDR;
740
741#ifdef DEBUG
742    cvmx_dprintf("SMDR descriptor list: \n");
743    cvmx_spinlock_lock(&__smdr->lock);
744    __smdr_iterator(__cvmx_shmem_smdr_display_dscptr, NULL);
745    cvmx_spinlock_unlock(&__smdr->lock);
746    cvmx_dprintf("\n\n");
747#endif
748}
749