source: svn/branches/kctv/newcon3bcm2_21bu/magnum/basemodules/dbg/bdbg_fifo.c

Last change on this file was 2, checked in by phkim, 11 years ago

1.phkim

  1. revision copy newcon3sk r27
  • Property svn:executable set to *
File size: 9.7 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2003-2011, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile: bdbg_fifo.c $
11 * $brcm_Revision: Hydra_Software_Devel/5 $
12 * $brcm_Date: 6/6/11 4:16p $
13 *
14 * Module Description:
15 *
16 * Revision History:
17 *
18 * $brcm_Log: /magnum/basemodules/dbg/bdbg_fifo.c $
19 *
20 * Hydra_Software_Devel/5   6/6/11 4:16p vsilyaev
21 * SW7405-4477: Resolved another warning
22 *
23 * Hydra_Software_Devel/4   6/6/11 3:46p vsilyaev
24 * SW7405-4477: Fixed warning
25 *
26 * Hydra_Software_Devel/3   6/6/11 3:27p vsilyaev
27 * SW7405-4477: Routed all debug output through buffer and use external
28 * application to extract and print debug output
29 *
30 * Hydra_Software_Devel/2   4/13/11 7:33p vsilyaev
31 * SW7405-5221: Verify fifo status after copying data out
32 *
33 * Hydra_Software_Devel/1   4/4/11 6:09p vsilyaev
34 * SW7405-5221: Implementation of lock-free multi-writer/multi-reader FIFO
35 *
36 ***************************************************************************/
37
38#include "bstd.h"
39#include "bkni.h"
40#include "bdbg_fifo.h"
41
42#if defined(__mips__) && defined(__GNUC__)
43#define BDBG_P_LOG_SUPPORTED    1
44#endif
45
46
47#if BDBG_P_LOG_SUPPORTED
48#define BDBG_P_INLINE extern __inline__ __attribute__((always_inline))
49#else
50#define BDBG_P_INLINE static
51#endif
52
53BDBG_P_INLINE void 
54BDBG_P_Atomic_Set(BDBG_P_Atomic *a, long val) {
55        a->atomic = val;
56    return;
57}
58
59BDBG_P_INLINE long 
60BDBG_P_Atomic_Get(const BDBG_P_Atomic *a) {
61        return a->atomic;
62}
63
64BDBG_P_INLINE long
65BDBG_P_Atomic_AddReturnOld(BDBG_P_Atomic *a, long val)
66{
67        unsigned long result;
68#if BDBG_P_LOG_SUPPORTED && defined(__mips__)
69        unsigned long temp;
70        __asm__ __volatile__(
71                "       .set    mips32                                  \n"
72                "1:     ll      %1, %2          # BDBG_P_Atomic_AddReturn \n"
73                "       addu    %0, %1, %3                              \n"
74                "       sc      %0, %2                                  \n"
75                "       beqz    %0, 1b                                  \n"
76                "       move    %0, %1                              \n"
77                "       .set    mips0                                   \n"
78                : "=&r" (result), "=&r" (temp), "=m" (a->atomic)
79                : "Ir" (val), "m" (a->atomic)
80                : "memory");
81#else
82        a->atomic += val;
83        result = a->atomic;
84#endif
85        return result;
86}
87
88
89#define BDBG_P_LOG_TAG_EMPTY    0
90#define BDBG_P_LOG_TAG_ALLOCATED    1
91#define BDBG_P_LOG_TAG_COMPLETED    2
92
93
94struct BDBG_Fifo {
95    size_t element_size;
96    unsigned nelements;
97    bool buffer_allocated;
98    bool enabled;
99    BDBG_P_Atomic write_counter;
100    BDBG_OBJECT(BDBG_Fifo)
101    unsigned buffer[1]; /* variable size array */
102} BDBG_Fifo;
103
104BDBG_OBJECT_ID(BDBG_Fifo);
105
106struct BDBG_FifoReader  {
107    BDBG_OBJECT(BDBG_FifoReader)
108    BDBG_Fifo_CHandle writer;
109    long read_counter;
110};
111BDBG_OBJECT_ID(BDBG_FifoReader);
112
113
114
115void 
116BDBG_Fifo_GetDefaultCreateSettings(BDBG_Fifo_CreateSettings *createSettings)
117{
118    BDBG_ASSERT(createSettings);
119    BKNI_Memset(createSettings, 0, sizeof(*createSettings));
120    createSettings->nelements = 32;
121    return;
122}
123
124#if BDBG_P_LOG_SUPPORTED 
125/* acual element size should be power of 2 */
126static BERR_Code
127BDBG_Fifo_P_NearPow2(unsigned a, unsigned *result)
128{
129    unsigned n;
130    unsigned i;
131
132    for(i=0,n=1;n<a;i++,n*=2) {
133        if(i>=30) {
134            return BERR_TRACE(BERR_NOT_SUPPORTED);
135        }
136    }
137    *result = n;
138    return BERR_SUCCESS;
139}
140#endif
141
142BERR_Code
143BDBG_Fifo_Create(BDBG_Fifo_Handle *pFifo, const BDBG_Fifo_CreateSettings *createSettings)
144{
145    BDBG_Fifo_Handle fifo;
146    BERR_Code rc;
147    unsigned i;
148    size_t element_size;
149    unsigned nelements=0;
150
151    BDBG_ASSERT(pFifo);
152    BDBG_ASSERT(createSettings);
153    if(createSettings->elementSize == 0) {
154        return BERR_TRACE(BERR_INVALID_PARAMETER);
155    }
156    if(createSettings->bufferSize == 0 && createSettings->nelements == 0) {
157        return BERR_TRACE(BERR_INVALID_PARAMETER);
158    }
159    if(createSettings->bufferSize !=0 && createSettings->buffer == NULL) {
160        return BERR_TRACE(BERR_INVALID_PARAMETER);
161    }
162
163    element_size = createSettings->elementSize + 2*sizeof(BDBG_P_Atomic) - 1;
164    element_size = element_size - (element_size % sizeof(BDBG_P_Atomic));
165
166#if BDBG_P_LOG_SUPPORTED 
167    if(createSettings->buffer) {
168        unsigned nelementsLimit;
169        unsigned bufferLeft = createSettings->bufferSize;
170        if(bufferLeft<sizeof(*fifo)) {rc=BERR_TRACE(BERR_INVALID_PARAMETER);goto err_alloc;}
171        bufferLeft -= sizeof(fifo);
172        nelementsLimit = bufferLeft / element_size;
173        rc = BDBG_Fifo_P_NearPow2(nelementsLimit, &nelements);
174        if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc); goto err_nelements; }
175        if(nelements>nelementsLimit) {
176            nelements /=2;
177            BDBG_ASSERT(nelements<=nelementsLimit);
178            if(nelements==0) {rc = BERR_TRACE(BERR_NOT_SUPPORTED); goto err_nelements;}
179        }
180        fifo = createSettings->buffer;
181        BDBG_OBJECT_INIT(fifo, BDBG_Fifo);
182        fifo->buffer_allocated = false;
183     } else {
184        rc = BDBG_Fifo_P_NearPow2(createSettings->nelements, &nelements);
185        if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc); goto err_nelements; }
186        fifo = BKNI_Malloc(sizeof(*fifo) + nelements*element_size);
187        if(fifo==NULL) {rc=BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);goto err_alloc;}
188        BDBG_OBJECT_INIT(fifo, BDBG_Fifo);
189        fifo->buffer_allocated = true;
190    }
191#else
192    /* short circuit execution */
193    fifo = NULL; 
194    rc = BERR_TRACE(BERR_NOT_SUPPORTED);goto err_alloc;
195#endif
196    BDBG_ASSERT(nelements>0);
197    fifo->enabled = true;
198    fifo->nelements = nelements;
199    fifo->element_size = element_size;
200
201    BDBG_P_Atomic_Set(&fifo->write_counter, 0);
202    for(i=0;i<fifo->nelements;i++) {
203        BDBG_P_Atomic *atomic;
204
205        atomic = (void *)((uint8_t *)fifo->buffer + i*fifo->element_size);
206        BDBG_P_Atomic_Set(atomic, BDBG_P_LOG_TAG_EMPTY);
207    }
208    *pFifo = fifo;
209    return BERR_SUCCESS;
210
211    /* BKNI_Free(fifo); */
212err_alloc:
213#if BDBG_P_LOG_SUPPORTED 
214err_nelements:
215#endif
216    return rc;
217}
218
219void 
220BDBG_Fifo_Destroy(BDBG_Fifo_Handle fifo)
221{
222    BDBG_OBJECT_ASSERT(fifo, BDBG_Fifo);
223    if(fifo->buffer_allocated) {
224        BDBG_OBJECT_DESTROY(fifo, BDBG_Fifo); 
225        BKNI_Free(fifo);
226    }
227    return;
228}
229
230
231static void *
232BDBG_Fifo_P_GetElementPointer(BDBG_Fifo_CHandle fifo, unsigned long counter)
233{
234    unsigned offset;
235    void *buf;
236
237    offset = (unsigned) (counter % fifo->nelements);
238    offset = offset * fifo->element_size;
239    buf = (uint8_t *)fifo->buffer + offset;
240    return buf;
241}
242
243
244void *
245BDBG_Fifo_GetBuffer(BDBG_Fifo_Handle fifo, BDBG_Fifo_Token *token)
246{
247    void *buf;
248   
249    BDBG_OBJECT_ASSERT(fifo, BDBG_Fifo);
250    BDBG_ASSERT(token);
251    if(fifo->enabled) {
252        buf = BDBG_Fifo_P_GetElementPointer(fifo, BDBG_P_Atomic_AddReturnOld(&fifo->write_counter, 1));
253        token->marker = buf;
254        BDBG_P_Atomic_Set(token->marker, BDBG_P_LOG_TAG_EMPTY);
255        return (uint8_t *)buf + sizeof(token->marker);
256    } else {
257        return NULL;
258    }
259}
260
261void 
262BDBG_Fifo_CommitBuffer(const BDBG_Fifo_Token *token)
263{
264    BDBG_P_Atomic_Set(token->marker, BDBG_P_LOG_TAG_COMPLETED);
265    return;
266}
267
268
269BERR_Code
270BDBG_FifoReader_Create(BDBG_FifoReader_Handle *pReader, BDBG_Fifo_Handle fifo)
271{
272    BDBG_FifoReader_Handle reader;
273
274    BDBG_ASSERT(pReader);
275    /* BDBG_OBJECT_ASSERT(fifo, BDBG_Fifo); */
276
277    reader = BKNI_Malloc(sizeof(*reader));
278    if(!reader) {return BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);}
279
280    BDBG_OBJECT_INIT(reader, BDBG_FifoReader);
281    reader->writer = fifo;
282    reader->read_counter = 0;
283    *pReader = reader;
284
285    return BERR_SUCCESS;
286}
287
288void
289BDBG_FifoReader_Destroy(BDBG_FifoReader_Handle fifo)
290{
291    BDBG_OBJECT_DESTROY(fifo, BDBG_FifoReader);
292    BKNI_Free(fifo);
293    return;
294}
295
296BERR_Code
297BDBG_FifoReader_Read(BDBG_FifoReader_Handle fifo, void *buffer, size_t buffer_size)
298{
299    size_t element_size;
300    long distance;
301    BDBG_P_Atomic *marker;
302
303    BDBG_OBJECT_ASSERT(fifo, BDBG_FifoReader);
304    /* BDBG_OBJECT_ASSERT(fifo->writer, BDBG_Fifo); */
305    BDBG_ASSERT(buffer);
306    element_size = fifo->writer->element_size - sizeof(BDBG_P_Atomic);
307    if(buffer_size < element_size) { return BERR_TRACE(BERR_INVALID_PARAMETER); }
308    distance = BDBG_P_Atomic_Get(&fifo->writer->write_counter)-fifo->read_counter;
309    if(distance == 0) {
310        return BERR_FIFO_NO_DATA;
311    }
312    if(distance < 0 || distance >= (long)fifo->writer->nelements) {
313        return BERR_FIFO_OVERFLOW;
314    }
315    marker = BDBG_Fifo_P_GetElementPointer(fifo->writer, fifo->read_counter);
316    if(BDBG_P_Atomic_Get(marker)!=BDBG_P_LOG_TAG_COMPLETED) {
317        if(distance==1) {
318            return BERR_FIFO_BUSY;
319        } else {
320            return BERR_FIFO_NO_DATA;
321        }
322    }
323    BKNI_Memcpy(buffer, marker+1, element_size);
324    /* verify pointer after copying data */
325    distance = BDBG_P_Atomic_Get(&fifo->writer->write_counter)-fifo->read_counter;
326    if(distance < 0 || distance >= (long)fifo->writer->nelements) {
327        return BERR_FIFO_OVERFLOW;
328    }
329    fifo->read_counter++;
330    return BERR_SUCCESS;
331}
332
333BERR_Code
334BDBG_FifoReader_Resync(BDBG_FifoReader_Handle fifo)
335{
336    long distance;
337    long write_counter;
338
339    BDBG_OBJECT_ASSERT(fifo, BDBG_FifoReader);
340    /* BDBG_OBJECT_ASSERT(fifo->writer, BDBG_Fifo); */
341    write_counter = BDBG_P_Atomic_Get(&fifo->writer->write_counter);
342    distance = write_counter-fifo->read_counter;
343    if(distance == 0) {
344        /* do nothing */
345    } else if(distance < 0 || distance >= (long)fifo->writer->nelements) {
346        fifo->read_counter = write_counter;
347    } else {
348        BDBG_P_Atomic *marker;
349        marker = BDBG_Fifo_P_GetElementPointer(fifo->writer, fifo->read_counter);
350        if(BDBG_P_Atomic_Get(marker)==BDBG_P_LOG_TAG_ALLOCATED) {
351            fifo->read_counter++;
352        }
353    }
354    return BERR_SUCCESS;
355}
356
357
358
359
360
Note: See TracBrowser for help on using the repository browser.