source: trunk/kernel/mm/kcm.c

Last change on this file was 683, checked in by alain, 13 months ago

All modifications required to support the <tcp_chat> application
including error recovery in case of packet loss.A

File size: 26.1 KB
RevLine 
[1]1/*
[635]2 * kcm.c -  Kernel Cache Manager implementation.
[18]3 *
[672]4 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
[1]5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
[14]24#include <kernel_config.h>
[457]25#include <hal_kernel_types.h>
[1]26#include <hal_special.h>
[567]27#include <busylock.h>
[1]28#include <list.h>
29#include <printk.h>
30#include <bits.h>
31#include <ppm.h>
32#include <thread.h>
33#include <page.h>
34#include <cluster.h>
[7]35#include <kmem.h>
[1]36#include <kcm.h>
37
[683]38///////////////////////////////////////////////////////////////////////////////////////////
39//         global variables
40///////////////////////////////////////////////////////////////////////////////////////////
[567]41
[683]42extern chdev_directory_t    chdev_dir;          // allocated in kernel_init.c
43
44
[635]45/////////////////////////////////////////////////////////////////////////////////////
46//        Local access functions
47/////////////////////////////////////////////////////////////////////////////////////
48
[1]49//////////////////////////////////////////////////////////////////////////////////////
[683]50// This static function is called by the kcm_alloc() function.
[657]51// It returns a pointer on a block allocated from an active kcm_page.
52// It makes a panic if no block is available in the selected page.
[635]53// It changes the page status as required.
[1]54//////////////////////////////////////////////////////////////////////////////////////
[635]55// @ kcm      : pointer on KCM allocator.
[657]56// @ kcm_page : pointer on an active kcm_page.
[635]57// @ return pointer on allocated block.
[7]58/////////////////////////////////////////////////////////////////////////////////////
[635]59static void * __attribute__((noinline)) kcm_get_block( kcm_t      * kcm,
60                                                       kcm_page_t * kcm_page )
[1]61{
[635]62    // initialise variables
[683]63    uint32_t order  = kcm->order;
[635]64    uint32_t count  = kcm_page->count;
65    uint64_t status = kcm_page->status;
[1]66
[683]67// check kcm page not full
68assert( __FUNCTION__, (count < 63) ,
69"kcm_page should not be full / cxy %x / order %d / count %d", local_cxy, order, count );
[433]70
[635]71    uint32_t index  = 1;
72    uint64_t mask   = (uint64_t)0x2;
[50]73
[635]74        // allocate first free block in kcm_page, update status,
75    // and count , compute index of allocated block in kcm_page
[683]76    while( index <= 63 )
[635]77    {
[657]78        if( (status & mask) == 0 )   // block found
[635]79        {
[657]80            // update page count and status
[635]81            kcm_page->status = status | mask;
82            kcm_page->count  = count + 1;
83            break;     
84        }
85       
86        index++;
87        mask <<= 1;
88    }
[18]89
[683]90    // switch page to full if last block
91    if( (count + 1) == 63 )
[635]92    {
[50]93                list_unlink( &kcm_page->list);
[635]94                kcm->active_pages_nr--;
[1]95
[635]96        list_add_first( &kcm->full_root , &kcm_page->list );
97                kcm->full_pages_nr ++;
98    }
[1]99
[161]100        // compute return pointer
[683]101        void * ptr = (void *)((intptr_t)kcm_page + (index << order));
[1]102
[50]103        return ptr;
104
[635]105}  // end kcm_get_block()
106
[1]107/////////////////////////////////////////////////////////////////////////////////////
[683]108// This static function is called by the kcm_free() function.
[635]109// It releases a previously allocated block to the relevant kcm_page.
110// It makes a panic if the released block is not allocated in this page.
111// It changes the kcm_page status as required.
[1]112/////////////////////////////////////////////////////////////////////////////////////
[635]113// @ kcm        : pointer on kcm allocator.
114// @ kcm_page   : pointer on kcm_page.
115// @ block_ptr  : pointer on block to be released.
[7]116/////////////////////////////////////////////////////////////////////////////////////
[635]117static void __attribute__((noinline)) kcm_put_block ( kcm_t      * kcm,
118                                                      kcm_page_t * kcm_page,
119                                                      void       * block_ptr )
[1]120{
[635]121    // initialise variables
[683]122    uint32_t order  = kcm->order;
[635]123    uint32_t count  = kcm_page->count;
124    uint64_t status = kcm_page->status;
125   
[683]126        // compute block index from block pointer and kcm_page pointer
127        uint32_t index = ((intptr_t)block_ptr - (intptr_t)kcm_page) >> order;
[18]128
[635]129    // compute mask in bit vector
130    uint64_t mask = ((uint64_t)0x1) << index;
[176]131
[672]132    if( (status & mask) == 0 )
133    {
134        printk("\n[WARNING] in %s : block[%x,%x] not allocated / kcm %x / kcm_page %x\n",
135        __FUNCTION__, local_cxy, block_ptr, kcm, kcm_page );
136        kcm_remote_display( local_cxy , kcm );
137        return;
138    }
[619]139
[635]140    // update status & count in kcm_page
141        kcm_page->status = status & ~mask;
142        kcm_page->count  = count - 1;
[50]143
[683]144        // switch page to active if it was full
145        if( count == 63 )
[1]146        {
[50]147                list_unlink( &kcm_page->list );
[635]148                kcm->full_pages_nr --;
[1]149
[50]150                list_add_last( &kcm->active_root, &kcm_page->list );
[1]151                kcm->active_pages_nr ++;
152        }
153
[635]154}  // kcm_put_block()
[1]155
156/////////////////////////////////////////////////////////////////////////////////////
[683]157// This static function  returns one non-full kcm_page with the following policy :
[635]158// - if the "active_list" is non empty, it returns the first "active" page,
159//   without modifying the KCM state.
[657]160// - if the "active_list" is empty, it allocates a new page from PPM, inserts
[635]161//   this page in the active_list, and returns it.
[1]162/////////////////////////////////////////////////////////////////////////////////////
[635]163// @ kcm      : local pointer on local KCM allocator.
164// @ return pointer on a non-full kcm page if success / returns NULL if no memory.
165/////////////////////////////////////////////////////////////////////////////////////
166static kcm_page_t * __attribute__((noinline)) kcm_get_page( kcm_t * kcm )
[1]167{
[635]168    kcm_page_t * kcm_page;
[1]169
[635]170    uint32_t active_pages_nr = kcm->active_pages_nr;
[18]171
[635]172    if( active_pages_nr > 0 )       // return first active page
173    {
174        kcm_page = LIST_FIRST( &kcm->active_root , kcm_page_t , list );
175    }
176    else                            // allocate a new page from PPM
[7]177        {
[683]178        // get KCM order
179        uint32_t order = kcm->order;
[7]180
[683]181        // get one kcm_page from  PPM
182        page_t * page = ppm_alloc_pages( order + 6 - CONFIG_PPM_PAGE_ORDER );
183
[635]184            if( page == NULL )
185            {
[1]186
[683]187#if DEBUG_KCM_ERROR
188printk("\n[ERROR] in %s : failed to allocate page in cluster %x\n",
189__FUNCTION__ , local_cxy );
190#endif
[635]191                    return NULL;
192        }
[1]193
[635]194            // get page base address
195            xptr_t base_xp = ppm_page2base( XPTR( local_cxy , page ) );
[1]196
[683]197        // get local pointer on kcm_page
[635]198            kcm_page = GET_PTR( base_xp );
[18]199
[635]200            // initialize kcm_page descriptor
201            kcm_page->status = 0;
202            kcm_page->count  = 0;
203            kcm_page->kcm    = kcm;
204            kcm_page->page   = page;
[1]205
[635]206            // introduce new page in KCM active_list
207            list_add_first( &kcm->active_root , &kcm_page->list );
208            kcm->active_pages_nr ++;
[1]209        }
210
[50]211        return kcm_page;
[1]212
[635]213}  // end kcm_get_page()
214
[7]215//////////////////////////////
216void kcm_init( kcm_t    * kcm,
[635]217                   uint32_t   order)
[1]218{
219
[683]220// check argument
221assert( __FUNCTION__, (order < CONFIG_PPM_PAGE_ORDER),
222"order argument %d too large", order );
[619]223
[683]224assert( __FUNCTION__, (order >= CONFIG_CACHE_LINE_ORDER),
225"order argument %d too small", order );
[672]226
[20]227        // initialize lock
[635]228        remote_busylock_init( XPTR( local_cxy , &kcm->lock ) , LOCK_KCM_STATE );
[1]229
[20]230        // initialize KCM page lists
[635]231        kcm->full_pages_nr   = 0;
[1]232        kcm->active_pages_nr = 0;
[635]233        list_root_init( &kcm->full_root );
[1]234        list_root_init( &kcm->active_root );
235
[683]236        // initialize order
237        kcm->order = order;
[635]238 
[619]239#if DEBUG_KCM
[683]240if( (DEBUG_KCM_ORDER == order) && (DEBUG_KCM_CXY == local_cxy) )
241printk("\n[%s] cxy %x / order %d\n",
242__FUNCTION__, local_cxy, order );
[619]243#endif
244
[635]245}  // end kcm_init()
[1]246
247///////////////////////////////
248void kcm_destroy( kcm_t * kcm )
249{
[50]250        kcm_page_t   * kcm_page;
[18]251
[635]252    // build extended pointer on  KCM lock
253    xptr_t lock_xp = XPTR( local_cxy , &kcm->lock );
254
[20]255        // get KCM lock
[635]256        remote_busylock_acquire( lock_xp );
[1]257
[635]258        // release all full pages
259        while( list_is_empty( &kcm->full_root ) == false )
[1]260        {
[635]261                kcm_page = LIST_FIRST( &kcm->full_root , kcm_page_t , list );
262                list_unlink( &kcm_page->list );
[50]263                ppm_free_pages( kcm_page->page );
[1]264        }
265
[635]266    // release all empty pages
267    while( list_is_empty( &kcm->active_root ) == false )
[1]268        {
[635]269                kcm_page = LIST_FIRST( &kcm->active_root , kcm_page_t , list );
270                list_unlink( &kcm_page->list );
[50]271                ppm_free_pages( kcm_page->page );
[1]272        }
273
[635]274        // release KCM lock
275        remote_busylock_release( lock_xp );
276
[657]277}  // end kcm_destroy()
278
[635]279//////////////////////////////////
280void * kcm_alloc( uint32_t order )
281{
[683]282    kcm_t      * kcm;
[635]283        kcm_page_t * kcm_page;
[683]284        void       * block;
[635]285
[683]286// check argument
287assert( __FUNCTION__, (order < CONFIG_PPM_PAGE_ORDER),
288"order argument %d too large", order );
[635]289
[683]290#if DEBUG_KCM
291uint32_t cycle = (uint32_t)hal_get_cycles();
292#endif
[635]293
[683]294    // smallest block size is a cache line
295    if (order < CONFIG_CACHE_LINE_ORDER) order = CONFIG_CACHE_LINE_ORDER;
296
[635]297    // get local pointer on relevant KCM allocator
[683]298    kcm = &LOCAL_CLUSTER->kcm[order - CONFIG_CACHE_LINE_ORDER];
[635]299
300    // build extended pointer on local KCM lock
[683]301    xptr_t lock_xp = XPTR( local_cxy , &kcm->lock );
[635]302
303        // get KCM lock
304        remote_busylock_acquire( lock_xp );
305
306    // get a non-full kcm_page
[683]307    kcm_page = kcm_get_page( kcm );
[635]308
309    if( kcm_page == NULL )
[1]310        {
[635]311                remote_busylock_release( lock_xp );
312                return NULL;
[1]313        }
314
[683]315#if DEBUG_KCM
316if( (DEBUG_KCM_ORDER == order) && (DEBUG_KCM_CXY == local_cxy) && (DEBUG_KCM < cycle) )
317printk("\n[%s] enter / order %d / kcm[%x,%x] / nb_full %d / nb_active %d\n"
318"    page %x / status [%x,%x] / count %d\n",
319__FUNCTION__, order, local_cxy, kcm, kcm->full_pages_nr, kcm->active_pages_nr,
320kcm_page, (uint32_t)(kcm_page->status>>32), (uint32_t)(kcm_page->status), kcm_page->count );
321#endif
[1]322
[683]323        // allocate a block from selected active page
324        block = kcm_get_block( kcm , kcm_page );
[635]325
326#if DEBUG_KCM
[683]327if( (DEBUG_KCM_ORDER == order) && (DEBUG_KCM_CXY == local_cxy) && (DEBUG_KCM < cycle) )
328printk("\n[%s] exit  / order %d / kcm[%x,%x] / nb_full %d / nb_active %d\n"
329"    page %x / status [%x,%x] / count %d\n",
330__FUNCTION__, order, local_cxy, kcm, kcm->full_pages_nr, kcm->active_pages_nr,
331kcm_page, (uint32_t)(kcm_page->status>>32), (uint32_t)(kcm_page->status), kcm_page->count );
[635]332#endif
333
[683]334        // release lock
335        remote_busylock_release( lock_xp );
[635]336
[683]337        return block;
338
[635]339}  // end kcm_alloc()
340
[683]341///////////////////////////////
342void kcm_free( void    * block,
343               uint32_t  order )
[1]344{
[683]345    kcm_t      * kcm;
[50]346        kcm_page_t * kcm_page;
[1]347
[635]348// check argument
[683]349assert( __FUNCTION__, (block != NULL), 
350"block pointer cannot be NULL" );
[635]351
352#if DEBUG_KCM
[683]353uint32_t cycle = (uint32_t)hal_get_cycles();
[635]354#endif
355
[683]356    // smallest block size is a cache line
357    if (order < CONFIG_CACHE_LINE_ORDER) order = CONFIG_CACHE_LINE_ORDER;
358
359    // get local pointer on relevant KCM allocator
360    kcm = &LOCAL_CLUSTER->kcm[order - CONFIG_CACHE_LINE_ORDER];
361
362    // get local pointer on KCM page
363    intptr_t kcm_page_mask = (1 << (order + 6)) - 1; 
364        kcm_page = (kcm_page_t *)((intptr_t)block & ~kcm_page_mask);
365
[635]366    // build extended pointer on local KCM lock
[683]367    xptr_t lock_xp = XPTR( local_cxy , &kcm->lock );
[635]368
[20]369        // get lock
[635]370        remote_busylock_acquire( lock_xp );
[18]371
[683]372#if DEBUG_KCM
373if( (DEBUG_KCM_ORDER == order) && (DEBUG_KCM_CXY == local_cxy) && (DEBUG_KCM < cycle) )
374printk("\n[%s] exit  / order %d / kcm[%x,%x] / nb_full %d / nb_active %d\n"
375"    page %x / status [%x,%x] / count %d\n",
376__FUNCTION__, order, local_cxy, kcm, kcm->full_pages_nr, kcm->active_pages_nr,
377kcm_page, (uint32_t)(kcm_page->status>>32), (uint32_t)(kcm_page->status), kcm_page->count );
378#endif
[635]379
[683]380        // release the block to the relevant page
381        kcm_put_block( kcm , kcm_page , block );
[657]382
383#if DEBUG_KCM
[683]384if( (DEBUG_KCM_ORDER == order) && (DEBUG_KCM_CXY == local_cxy) && (DEBUG_KCM < cycle) )
385printk("\n[%s] exit  / order %d / kcm[%x,%x] / nb_full %d / nb_active %d\n"
386"    page %x / status [%x,%x] / count %d\n",
387__FUNCTION__, order, local_cxy, kcm, kcm->full_pages_nr, kcm->active_pages_nr,
388kcm_page, (uint32_t)(kcm_page->status>>32), (uint32_t)(kcm_page->status), kcm_page->count );
[657]389#endif
[635]390
[683]391        // release lock
392        remote_busylock_release( lock_xp );
393
[657]394}  // end kcm_free()
395
[672]396
[635]397/////////////////////////////////////////////////////////////////////////////////////
398//        Remote access functions
399/////////////////////////////////////////////////////////////////////////////////////
400
401/////////////////////////////////////////////////////////////////////////////////////
[683]402// This static function is called by the kcm_remote_alloc() function.
403// It can be called by any thread running in any cluster.
[657]404// It returns a local pointer on a block allocated from an active kcm_page.
405// It makes a panic if no block available in the selected kcm_page.
[635]406// It changes the page status as required.
407/////////////////////////////////////////////////////////////////////////////////////
[657]408// @ kcm_cxy  : remote KCM cluster identifier.
[635]409// @ kcm_ptr  : local pointer on remote KCM allocator.
[657]410// @ kcm_page : local pointer on remote active kcm_page to use.
[635]411// @ return a local pointer on the allocated block.
412/////////////////////////////////////////////////////////////////////////////////////
413static void * __attribute__((noinline)) kcm_remote_get_block( cxy_t        kcm_cxy,
414                                                              kcm_t      * kcm_ptr,
415                                                              kcm_page_t * kcm_page )
416{
417    uint32_t order  = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->order ) );
418    uint32_t count  = hal_remote_l32( XPTR( kcm_cxy , &kcm_page->count ) );
419    uint64_t status = hal_remote_l64( XPTR( kcm_cxy , &kcm_page->status ) );
420
[683]421// check kcm_page not full
422assert( __FUNCTION__, (count < 63) , 
423"kcm_page should not be full / cxy %x / order %d / count %d", kcm_cxy, order, count );
[635]424
425    uint32_t index  = 1;
426    uint64_t mask   = (uint64_t)0x2;
427   
428        // allocate first free block in kcm_page, update status,
429    // and count , compute index of allocated block in kcm_page
[683]430    while( index <= 63 )
[635]431    {
[657]432        if( (status & mask) == 0 )   // block found
[635]433        {
434            hal_remote_s64( XPTR( kcm_cxy , &kcm_page->status ) , status | mask );
[657]435            hal_remote_s32( XPTR( kcm_cxy , &kcm_page->count  ) , count + 1 );
[635]436            break;     
437        }
438       
439        index++;
440        mask <<= 1;
441    }
442
[683]443        // swich the page to full if last block
444        if( (count + 1) == 63 )
[20]445        {
[635]446                list_remote_unlink( kcm_cxy , &kcm_page->list );
447                hal_remote_atomic_add( XPTR( kcm_cxy , &kcm_ptr->active_pages_nr ) , -1 );
[7]448
[635]449                list_remote_add_first( kcm_cxy , &kcm_ptr->full_root , &kcm_page->list );
450                hal_remote_atomic_add( XPTR( kcm_cxy , &kcm_ptr->full_pages_nr ) , 1 );
451        }
[50]452
[635]453        // compute return pointer
[683]454        void * ptr = (void *)((intptr_t)kcm_page + (index << order));
[635]455
456        return ptr;
457
458}  // end kcm_remote_get_block()
459
460/////////////////////////////////////////////////////////////////////////////////////
[683]461// This static function is called by the kcm_remote_free() function.
462// It can be called by any thread running in any cluster.
[635]463// It releases a previously allocated block to the relevant kcm_page.
464// It changes the kcm_page status as required.
465/////////////////////////////////////////////////////////////////////////////////////
466// @ kcm_cxy   : remote KCM cluster identifier
467// @ kcm_ptr   : local pointer on remote KCM.
468// @ kcm_page  : local pointer on kcm_page.
469// @ block_ptr : pointer on block to be released.
470/////////////////////////////////////////////////////////////////////////////////////
471static void __attribute__((noinline)) kcm_remote_put_block ( cxy_t        kcm_cxy,
472                                                             kcm_t      * kcm_ptr,
473                                                             kcm_page_t * kcm_page,
474                                                             void       * block_ptr )
475{
476    uint32_t order  = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->order ) );
477    uint32_t count  = hal_remote_l32( XPTR( kcm_cxy , &kcm_page->count ) );
478    uint64_t status = hal_remote_l64( XPTR( kcm_cxy , &kcm_page->status ) );
479   
[683]480        // compute block index from block pointer and kcm_page pointer
481        uint32_t index = ((intptr_t)block_ptr - (intptr_t)kcm_page) >> order;
[635]482
483    // compute mask in bit vector
[672]484    uint64_t mask = ((uint64_t)0x1) << index;
[635]485
[672]486    if( (status & mask) == 0 )
487    {
488        printk("\n[WARNING] in %s : block[%x,%x] not allocated / kcm %x / kcm_page %x\n",
489        __FUNCTION__, kcm_cxy, block_ptr, kcm_ptr, kcm_page );
490        kcm_remote_display( kcm_cxy , kcm_ptr );
491        return;
492    }
[635]493
494    // update status & count in kcm_page
495        hal_remote_s64( XPTR( kcm_cxy , &kcm_page->status ) , status & ~mask );
496        hal_remote_s32( XPTR( kcm_cxy , &kcm_page->count  ) , count - 1 );
497
[683]498        // switch the page to active if page was full
499        if( count == 63 )
[635]500        {
501                list_remote_unlink( kcm_cxy , &kcm_page->list );
502                hal_remote_atomic_add( XPTR( kcm_cxy , &kcm_ptr->full_pages_nr ) , -1 );
503
504                list_remote_add_last( kcm_cxy , &kcm_ptr->active_root, &kcm_page->list );
505                hal_remote_atomic_add( XPTR( kcm_cxy , &kcm_ptr->active_pages_nr ) , 1 );
[20]506        }
[635]507
508}  // end kcm_remote_put_block()
509
510/////////////////////////////////////////////////////////////////////////////////////
[683]511// This static function can be called by any thread running in any cluster.
[635]512// It gets one non-full KCM page from the remote KCM.
513// It allocates a page from remote PPM to populate the freelist, and initialises
514// the kcm_page descriptor when required.
515/////////////////////////////////////////////////////////////////////////////////////
516static kcm_page_t * __attribute__((noinline)) kcm_remote_get_page( cxy_t    kcm_cxy,
517                                                                   kcm_t  * kcm_ptr )
518{
519    kcm_page_t * kcm_page;    // local pointer on remote KCM page
520
521    uint32_t active_pages_nr = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->active_pages_nr ) );
522
523    if( active_pages_nr > 0 )       // return first active page
524    {
525        kcm_page = LIST_REMOTE_FIRST( kcm_cxy , &kcm_ptr->active_root , kcm_page_t , list );
526    }
527    else                            // allocate a new page from PPM
[20]528        {
[683]529        // get KCM order
530        uint32_t order = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->order ));
[635]531
[683]532        // get one kcm_page from PPM
533        xptr_t page_xp = ppm_remote_alloc_pages( kcm_cxy,
534                                                 order + 6 - CONFIG_PPM_PAGE_ORDER );
[656]535            if( page_xp == XPTR_NULL )
[635]536            {
537
[683]538#if DEBUG_KCM_ERROR
539printk("\n[ERROR] in %s : failed to allocate page in cluster %x\n",
540__FUNCTION__ , kcm_cxy );
541#endif
[635]542                    return NULL;
543        }
544
[656]545            // get extended pointer on allocated buffer
546            xptr_t base_xp = ppm_page2base( page_xp );
[635]547
548        // get local pointer on kcm_page
549            kcm_page = GET_PTR( base_xp );
550
551            // initialize kcm_page descriptor
552            hal_remote_s32( XPTR( kcm_cxy , &kcm_page->count )  , 0 );
553            hal_remote_s64( XPTR( kcm_cxy , &kcm_page->status ) , 0 );
554            hal_remote_spt( XPTR( kcm_cxy , &kcm_page->kcm )    , kcm_ptr );
[656]555            hal_remote_spt( XPTR( kcm_cxy , &kcm_page->page )   , GET_PTR( page_xp ) );
[635]556
557            // introduce new page in remote KCM active_list
558            list_remote_add_first( kcm_cxy , &kcm_ptr->active_root , &kcm_page->list );
559            hal_remote_atomic_add( XPTR( kcm_cxy , &kcm_ptr->active_pages_nr ) , 1 );
[20]560        }
[1]561
[635]562        return kcm_page;
563
564}  // end kcm_remote_get_page()
565
[672]566//////////////////////////////////////////
[635]567void * kcm_remote_alloc( cxy_t    kcm_cxy,
568                         uint32_t order )
569{
570    kcm_t      * kcm_ptr;
571    kcm_page_t * kcm_page;
572    void       * block_ptr;
573
[683]574// check kcm_cxy argument
575assert( __FUNCTION__, cluster_is_active( kcm_cxy ),
576"cluster %x not active", kcm_cxy );
[635]577
[683]578// check order argument
579assert( __FUNCTION__, (order < CONFIG_PPM_PAGE_ORDER) ,
580"order argument %d too large", order );
[635]581
[683]582    // smallest size is a cache line
583    if( order < CONFIG_CACHE_LINE_ORDER ) order = CONFIG_CACHE_LINE_ORDER;
584
585    // get local pointer on relevant KCM allocator (same in all clusters)
[635]586    kcm_ptr = &LOCAL_CLUSTER->kcm[order - 6];
587
588    // build extended pointer on remote KCM lock
589    xptr_t lock_xp = XPTR( kcm_cxy , &kcm_ptr->lock );
590
591        // get lock
592        remote_busylock_acquire( lock_xp );
593
594    // get a non-full kcm_page
595    kcm_page = kcm_remote_get_page( kcm_cxy , kcm_ptr );
596
597    if( kcm_page == NULL )
598        {
599                remote_busylock_release( lock_xp );
600                return NULL;
601        }
602
[683]603#if DEBUG_KCM
604uint32_t cycle     = (uint32_t)hal_get_cycles();
605uint32_t nb_full   = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->full_pages_nr ));
606uint32_t nb_active = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->active_pages_nr ));
607uint64_t status    = hal_remote_l64( XPTR( kcm_cxy , &kcm_page->status ));
608uint32_t count     = hal_remote_l32( XPTR( kcm_cxy , &kcm_page->count ));
609#endif
610
611
612#if DEBUG_KCM
613if( (DEBUG_KCM_ORDER == order) && (DEBUG_KCM_CXY == local_cxy) && (DEBUG_KCM < cycle) )
614printk("\n[%s] enter / order %d / kcm[%x,%x] / nb_full %d / nb_active %d\n"
615"    page %x / status [%x,%x] / count %d\n",
616__FUNCTION__, order, kcm_cxy, kcm_ptr, nb_full, nb_active,
617kcm_page, (uint32_t)(status>>32), (uint32_t)(status), kcm_page->count );
618#endif
619
[20]620        // get a block from selected active page
[635]621        block_ptr = kcm_remote_get_block( kcm_cxy , kcm_ptr , kcm_page );
[7]622
[683]623#if DEBUG_KCM
624if( (DEBUG_KCM_ORDER == order) && (DEBUG_KCM_CXY == local_cxy) && (DEBUG_KCM < cycle) )
625printk("\n[%s] exit  / order %d / kcm[%x,%x] / nb_full %d / nb_active %d\n"
626"    page %x / status [%x,%x] / count %d\n",
627__FUNCTION__, order, kcm_cxy, kcm_ptr, nb_full, nb_active,
628kcm_page, (uint32_t)(status>>32), (uint32_t)(status), kcm_page->count );
629#endif
630
[20]631        // release lock
[635]632        remote_busylock_release( lock_xp );
[1]633
[635]634        return block_ptr;
635
636}  // end kcm_remote_alloc()
637
[683]638////////////////////////////////////////
639void kcm_remote_free( cxy_t     kcm_cxy,
640                      void    * block_ptr,
641                      uint32_t  order )
[1]642{
[635]643        kcm_t      * kcm_ptr;
[50]644        kcm_page_t * kcm_page;
[18]645
[683]646// check kcm_cxy argument
647assert( __FUNCTION__, cluster_is_active( kcm_cxy ),
648"cluster %x not active", kcm_cxy );
[18]649
[683]650// check block_ptr argument
651assert( __FUNCTION__, (block_ptr != NULL),
652"block pointer cannot be NULL" );
[1]653
[683]654// check order argument
655assert( __FUNCTION__, (order < CONFIG_PPM_PAGE_ORDER) ,
656"order argument %d too large", order );
[635]657
[683]658    // smallest block size is a cache line
659    if (order < CONFIG_CACHE_LINE_ORDER) order = CONFIG_CACHE_LINE_ORDER;
660
661    // get local pointer on relevant KCM allocator (same in all clusters)
662    kcm_ptr = &LOCAL_CLUSTER->kcm[order - CONFIG_CACHE_LINE_ORDER];
663
664    // get local pointer on KCM page
665    intptr_t kcm_page_mask = (1 << (order + 6)) - 1; 
666        kcm_page = (kcm_page_t *)((intptr_t)block_ptr & ~kcm_page_mask);
667
668#if DEBUG_KCM
669uint32_t cycle     = (uint32_t)hal_get_cycles();
670uint32_t nb_full   = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->full_pages_nr ));
671uint32_t nb_active = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->active_pages_nr ));
672uint64_t status    = hal_remote_l64( XPTR( kcm_cxy , &kcm_page->status ));
673uint32_t count     = hal_remote_l32( XPTR( kcm_cxy , &kcm_page->count ));
674#endif
675
[635]676    // build extended pointer on remote KCM lock
677    xptr_t lock_xp = XPTR( kcm_cxy , &kcm_ptr->lock );
678
[20]679        // get lock
[635]680        remote_busylock_acquire( lock_xp );
[1]681
[683]682#if DEBUG_KCM
683if( (DEBUG_KCM_ORDER == order) && (DEBUG_KCM_CXY == local_cxy) && (DEBUG_KCM < cycle) )
684printk("\n[%s] enter / order %d / kcm[%x,%x] / nb_full %d / nb_active %d\n"
685"    page %x / status [%x,%x] / count %d\n",
686__FUNCTION__, order, kcm_cxy, kcm_ptr, nb_full, nb_active,
687kcm_page, (uint32_t)(status>>32), (uint32_t)(status), kcm_page->count );
688#endif
689
690        // release the block to the relevant page
[635]691        kcm_remote_put_block( kcm_cxy , kcm_ptr , kcm_page , block_ptr );
[1]692
[683]693#if DEBUG_KCM
694if( (DEBUG_KCM_ORDER == order) && (DEBUG_KCM_CXY == local_cxy) && (DEBUG_KCM < cycle) )
695printk("\n[%s] exit  / order %d / kcm[%x,%x] / nb_full %d / nb_active %d\n"
696"    page %x / status [%x,%x] / count %d\n",
697__FUNCTION__, order, kcm_cxy, kcm_ptr, nb_full, nb_active,
698kcm_page, (uint32_t)(status>>32), (uint32_t)(status), kcm_page->count );
699#endif
700
[20]701        // release lock
[635]702        remote_busylock_release( lock_xp );
[1]703
[635]704}  // end kcm_remote_free
705
706/////////////////////////////////////////
707void kcm_remote_display( cxy_t   kcm_cxy,
708                         kcm_t * kcm_ptr )
[1]709{
[657]710    list_entry_t * iter;
711    kcm_page_t   * kcm_page;
712    uint64_t       status;
713    uint32_t       count;
714
[683]715    // get pointers on TXT0 chdev
716    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
717    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
718    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
719
720    // get extended pointer on remote TXT0 chdev lock
721    xptr_t    txt0_lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
722
723    // get TXT0 lock
724    remote_busylock_acquire( txt0_lock_xp );
725
[635]726    uint32_t order           = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->order) );
727    uint32_t full_pages_nr   = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->full_pages_nr ) );
728    uint32_t active_pages_nr = hal_remote_l32( XPTR( kcm_cxy , &kcm_ptr->active_pages_nr ) );
729
[683]730        nolock_printk("*** KCM : cxy %x / order %d / full_pages_nr %d / active_pages_nr %d\n",
[635]731        kcm_cxy, order, full_pages_nr, active_pages_nr );
[657]732
733    if( active_pages_nr )
734    {
735        LIST_REMOTE_FOREACH( kcm_cxy , &kcm_ptr->active_root , iter )
736        {
737            kcm_page = LIST_ELEMENT( iter , kcm_page_t , list );
738            status   = hal_remote_l64( XPTR( kcm_cxy , &kcm_page->status ) );
739            count    = hal_remote_l32( XPTR( kcm_cxy , &kcm_page->count ) );
740
[683]741            nolock_printk("- active page %x / status (%x,%x) / count %d\n",
742            kcm_page, (uint32_t)( status<< 32 ), (uint32_t)( status ), count );
[657]743        }
744    }
745
746    if( full_pages_nr )
747    {
748        LIST_REMOTE_FOREACH( kcm_cxy , &kcm_ptr->full_root , iter )
749        {
750            kcm_page = LIST_ELEMENT( iter , kcm_page_t , list );
751            status   = hal_remote_l64( XPTR( kcm_cxy , &kcm_page->status ) );
752            count    = hal_remote_l32( XPTR( kcm_cxy , &kcm_page->count ) );
753
[683]754            nolock_printk("- full page %x / status (%x,%x) / count %d\n",
755            kcm_page, (uint32_t)( status<< 32 ), (uint32_t)( status ), count );
[657]756        }
757    }
[683]758
759    // release TXT0 lock
760    remote_busylock_release( txt0_lock_xp );
761
[657]762}  // end kcm remote_display()
Note: See TracBrowser for help on using the repository browser.