source: soft/giet_vm/libs/mwmr_channel.c @ 223

Last change on this file since 223 was 207, checked in by alain, 12 years ago

Several bugs have been fixed to support TSAR multi-cluster architecture
such as the "tsarv4-generic_mmu" platform.

File size: 13.0 KB
RevLine 
[159]1//////////////////////////////////////////////////////////////////////////////////
2// File     : mwmr_channel_.c         
3// Date     : 01/04/2012
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The mwmr_channel.c and mwmr_channel.h files are part of the GIET nano-kernel.
8// This  middleware implements a user level Multi-Writers / Multi-Readers
9// communication channel, that can be used by parallel multi-tasks applications
10// respecting the TCG (Tasks and Communications Graph) formalism.
11//
12// The mwmr_read() and mwmr_write() functions do not require a system call.
13// The channel itself must have been allocated in a non cacheable segment,
[165]14// if the platform does not provide hardware cache coherence.
[159]15//
16// ALL MWMR channels must be defined in the mapping_info data structure,
17// to be initialised by the GIET in the boot phase.
18// The vobj_get_vbase() system call (defined in stdio.c and stdio.h files)
19// can be used to get the virtual base address of the channel from it's name.
20//
21// An MWMR transaction transfer an integer number of items, and an item is
22// an integer number of unsigned int (32 bits words).
23// The max number of words that can be stored in a MWMR channel is defined by the
24// "depth" parameter, and the "width" parameter define the minimal number of
25// word contained in an atomic item. Therefore, the "depth" parameter must be
26// a multiple of the "width" parameter.
27//
28// Both the mwmr_read() and mwmr_write() functions are blocking functions.
29// A private lock provides exclusive access to the MWMR channel, that can have
30// a variable number of producers and a variable number of consumers.
31///////////////////////////////////////////////////////////////////////////////////
32
33#include <mwmr_channel.h>
34#include <stdio.h>
35
36//////////////////////////////////////////////////////////////////////////////
37//  mwmr_lock_aquire()
38// This blocking function returns only when the lock has been taken.
[165]39// If the lock is already taken a fixed delay is introduced before retry.
[159]40//////////////////////////////////////////////////////////////////////////////
[165]41void mwmr_lock_acquire(unsigned int* lock_address)
[159]42{
[165]43    register unsigned int*      plock = lock_address;
44    register unsigned int       delay = 100;
[159]45    asm volatile (
46            "mwmr_lock_try:                                     \n"
47            "ll   $2,    0(%0)                          \n" /* $2 <= lock current value */
[165]48            "bnez $2,    mwmr_lock_delay        \n" /* retry after delay if lock busy */
[159]49            "li   $3,    1                                      \n" /* $3 <= argument for sc */
50            "sc   $3,    0(%0)                          \n" /* try to get lock */
51            "bnez $3,    mwmr_lock_ok           \n" /* exit if atomic */
52            "mwmr_lock_delay:                           \n"
[165]53            "move $4,    %1                 \n" /* $4 <= delay */
54            "mwmr_lock_loop:                \n"
55            "beqz $4,    mwmr_lock_loop         \n" /* test end delay */
[159]56            "addi $4,    $4,  -1                        \n" /* $4 <= $4 - 1 */
[165]57            "j           mwmr_lock_try          \n" /* retry ll */
[159]58            "nop                                                        \n"
59            "mwmr_lock_ok:                                      \n"
60            :
[165]61            :"r"(plock), "r"(delay)
[159]62            :"$2", "$3", "$4");
63} 
[207]64//////////////////////////////////////////////////////////////////////////////
65//         nb_mwmr_write()
66// This is a non-blocking function.
67// The nitems parameter is the number of items to be transfered.
68// The requested transfer is therefore (nitems * width) words.
69// It takes the lock for exclusive access before testing the channel state.
70// If there is not enough data in mwmr channel to read nitems,
71// it reads as many items as possible, releases the lock, and returns
72// the number of read items (it can be 0).
73//////////////////////////////////////////////////////////////////////////////
74unsigned int nb_mwmr_write( mwmr_channel_t*     mwmr, 
75                            unsigned int*               buffer,
76                            unsigned int                nitems )
77{
78    unsigned int        x;
79    unsigned int        spaces;         // number of empty slots (in words)
80    unsigned int        nwords;         // requested transfer length (in words)
81    unsigned int    depth;              // channel depth (in words)
82    unsigned int    width;              // channel width (in words)
83    unsigned int    sts;        // channel sts
84    unsigned int    ptw;        // channel ptw
[159]85
[207]86    if(nitems == 0) return 0;
87
88    // get the lock
89    mwmr_lock_acquire( &mwmr->lock );
90
91    // access fifo status
92    depth  = mwmr->depth;
93    width  = mwmr->width;
94    sts    = mwmr->sts;
95    ptw    = mwmr->ptw;
96    spaces = depth - sts;
97    nwords = width * nitems;
98
99    if( spaces >= nwords )      // transfer nitems, release lock and return
100    {
101        for ( x = 0 ; x < nwords ; x++ ) 
102        {
103            mwmr->data[ptw] = buffer[x];
104            if ( (ptw + 1) == depth ) ptw = 0;
105            else                      ptw = ptw + 1;
106        }
107        mwmr->sts  = mwmr->sts + nwords;
108        mwmr->ptw  = ptw;
109        mwmr->lock = 0;
110        return nitems;
111    }
112   
113    else if ( spaces < width )  // release lock and return
114    {
115        mwmr->lock = 0;
116        return 0;
117    }
118    else        // transfer as many items as possible, release lock and return
119    {
120        nwords = (spaces/width) * width;        // integer number of items
121        for ( x = 0 ; x < nwords ; x++ ) 
122        {
123            mwmr->data[ptw] = buffer[x];
124            if ( (ptw + 1) == depth ) ptw = 0;
125            else                      ptw = ptw + 1;
126        }
127        mwmr->sts  = sts + nwords;
128        mwmr->ptw  = ptw;
129        mwmr->lock = 0;
130        return (nwords/width);
131    }
132} // end nb_mwmr_write()
133
[159]134//////////////////////////////////////////////////////////////////////////////
135//      mwmr_write()
136// This blocking function returns only when the transfer is completed.
137// The nitems parameter is the number of items to be transfered.
138// The requested transfer is therefore (nitems * width) words.
139// It takes the lock for exclusive access before testing the channel state.
140// If there is not enough space in mwmr channel to write nitems,
141// it writes as many items as possible, releases the lock, and retry
142// after a random delay.
143//////////////////////////////////////////////////////////////////////////////
[189]144void mwmr_write( mwmr_channel_t*        mwmr, 
145                 unsigned int*          buffer,
146                 unsigned int           nitems )
[159]147{
148    unsigned int        x;
149    unsigned int        spaces;         // number of empty slots (in words)
150    unsigned int        nwords;         // requested transfer length (in words)
151    unsigned int    depth;              // channel depth (in words)
152    unsigned int    width;              // channel width (in words)
153    unsigned int    sts;        // channel sts
154    unsigned int    ptw;        // channel ptw
155
[189]156    if(nitems == 0) return;
[175]157
[159]158    while(1)
159    {
160        // get the lock
161        mwmr_lock_acquire(&mwmr->lock);
162
163        // compute spaces and nwords
164        depth  = mwmr->depth;
165        width  = mwmr->width;
166        sts    = mwmr->sts;
167        ptw    = mwmr->ptw;
168        spaces = depth - sts;
169        nwords = width * nitems;
170
171        if( spaces >= nwords )  // write nwords, release lock and return
172        {
173            for ( x = 0 ; x < nwords ; x++ ) 
174            {
175                mwmr->data[ptw] = buffer[x];
176                if ( (ptw + 1) == depth ) ptw = 0;
177                else                      ptw = ptw + 1;
178            }
179            mwmr->ptw  = ptw;
180            mwmr->sts  = sts + nwords;
181            mwmr->lock = 0;
182            return;
183        }
184        else if ( spaces < width )      // release lock and retry after delay
185        {
186            mwmr->lock = 0;
[165]187            for ( x = giet_rand()>>8 ; x > 0 ; x-- ) asm volatile ( "nop" );
[159]188        }
189        else    // write as many items as possible, release lock and retry after delay
190        {
[175]191            nwords = (spaces/width) * width;  // integer number of items
[159]192            for ( x = 0 ; x < nwords ; x++ ) 
193            {
194                mwmr->data[ptw] = buffer[x];
195                if ( (ptw + 1) == depth ) ptw = 0;
196                else                      ptw = ptw + 1;
197            }
198            mwmr->sts  = sts + nwords;
199            mwmr->ptw  = ptw;
200            buffer     = buffer + nwords;
201            nitems     = nitems - (nwords/width);
202            mwmr->lock = 0;
203        }
204        // random delay before retry
[165]205        for ( x = giet_rand()>>6 ; x > 0 ; x-- ) asm volatile ( "nop" );
[159]206    }
[207]207} // end mwmr_write()
[159]208
209//////////////////////////////////////////////////////////////////////////////
[207]210//         nb_mwmr_read()
211// This is a non-blocking function.
212// The nitems parameter is the number of items to be transfered.
213// The requested transfer is therefore (nitems * width) words.
214// It takes the lock for exclusive access before testing the channel state.
215// If there is not enough data in mwmr channel to read nitems,
216// it reads as many items as possible, releases the lock, and returns
217// the number of read items (it can be 0).
218//////////////////////////////////////////////////////////////////////////////
219unsigned int nb_mwmr_read( mwmr_channel_t*      mwmr, 
220                           unsigned int*                buffer,
221                           unsigned int                 nitems )
222{
223    unsigned int        x;
224    unsigned int        nwords;         // requested transfer length (in words)
225    unsigned int    depth;              // channel depth (in words)
226    unsigned int    width;              // channel width (in words)
227    unsigned int    sts;        // channel sts
228    unsigned int    ptr;        // channel ptr
229
230    if(nitems == 0) return 0;
231
232    // get the lock
233    mwmr_lock_acquire( &mwmr->lock );
234
235    // access fifo status
236    depth  = mwmr->depth;
237    width  = mwmr->width;
238    sts    = mwmr->sts;
239    ptr    = mwmr->ptr;
240    nwords = width * nitems;
241
242    if( sts >= nwords )         // transfer nitems, release lock and return
243    {
244        for ( x = 0 ; x < nwords ; x++ ) 
245        {
246            buffer[x] = mwmr->data[ptr];
247            if ( (ptr + 1) == depth ) ptr = 0;
248            else                      ptr = ptr + 1;
249        }
250        mwmr->sts  = mwmr->sts - nwords;
251        mwmr->ptr  = ptr;
252        mwmr->lock = 0;
253        return nitems;
254    }
255   
256    else if ( sts < width )     // release lock and return
257    {
258        mwmr->lock = 0;
259        return 0;
260    }
261    else        // transfer as many items as possible, release lock and return
262    {
263        nwords = (sts/width) * width;   // integer number of items
264        for ( x = 0 ; x < nwords ; x++ ) 
265        {
266            buffer[x] = mwmr->data[ptr];
267            if ( (ptr + 1) == depth ) ptr = 0;
268            else                      ptr = ptr + 1;
269        }
270        mwmr->sts  = sts - nwords;
271        mwmr->ptr  = ptr;
272        mwmr->lock = 0;
273        return (nwords/width);
274    }
275} // nb_mwmr_read()
276
277//////////////////////////////////////////////////////////////////////////////
[159]278//      mwmr_read()
279// This blocking function returns only when the transfer is completed.
280// The nitems parameter is the number of items to be transfered.
281// The requested transfer is therefore (nitems * width) words.
282// It takes the lock for exclusive access before testing the channel state.
283// If there is not enough data in mwmr channel to read nitems,
284// it reads as many items as possible, releases the lock, and retry
285// after a random delay.
286//////////////////////////////////////////////////////////////////////////////
287void mwmr_read( mwmr_channel_t*         mwmr, 
288                unsigned int*           buffer,
289                unsigned int            nitems )
290{
291    unsigned int        x;
292    unsigned int        nwords;         // requested transfer length (in words)
293    unsigned int    depth;              // channel depth (in words)
294    unsigned int    width;              // channel width (in words)
295    unsigned int    sts;        // channel sts
[207]296    unsigned int    ptr;        // channel ptr
[159]297
[189]298    if(nitems == 0) return;
[175]299
[159]300    while(1)
301    {
302        // get the lock
303        mwmr_lock_acquire( &mwmr->lock );
304
305        // compute nwords
306        depth  = mwmr->depth;
307        width  = mwmr->width;
308        sts    = mwmr->sts;
309        ptr    = mwmr->ptr;
310        nwords = width * nitems;
311
312        if( sts >= nwords )     // read nwords, release lock and return
313        {
314            for ( x = 0 ; x < nwords ; x++ ) 
315            {
316                buffer[x] = mwmr->data[ptr];
317                if ( (ptr + 1) == depth ) ptr = 0;
318                else                      ptr = ptr + 1;
319            }
320            mwmr->sts  = mwmr->sts - nwords;
321            mwmr->ptr  = ptr;
322            mwmr->lock = 0;
323            return;
324        }
325        else if ( sts < width ) // release lock and retry after delay
326        {
327            mwmr->lock = 0;
[165]328            for ( x = giet_rand()>>8 ; x > 0 ; x-- ) asm volatile ( "nop" );
[159]329        }
330        else    // read as many items as possible, release lock and retry after delay
331        {
332            nwords = (sts/width) * width;       // integer number of items
333            for ( x = 0 ; x < nwords ; x++ ) 
334            {
[200]335                buffer[x] = mwmr->data[ptr];
[159]336                if ( (ptr + 1) == depth ) ptr = 0;
337                else                      ptr = ptr + 1;
338            }
339            mwmr->sts  = sts - nwords;
340            mwmr->ptr  = ptr;
341            buffer     = buffer + nwords;
342            nitems     = nitems - (nwords/width);
343            mwmr->lock = 0;
344        }
345        // random delay before retry
[165]346        for ( x = giet_rand()>>6 ; x > 0 ; x-- ) asm volatile ( "nop" );
[159]347    }
[207]348} // end mwmr_read()
[159]349
[207]350
Note: See TracBrowser for help on using the repository browser.