source: trunk/kernel/mm/ppm.c

Last change on this file was 683, checked in by alain, 3 years ago

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

File size: 25.9 KB
RevLine 
[1]1/*
[636]2 * ppm.c -  Physical Pages Manager implementation
[1]3 *
4 * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
[657]5 *          Alain Greiner    (2016,2017,2018,2019,2020)
[1]6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH.is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH.is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
[14]25#include <kernel_config.h>
[457]26#include <hal_kernel_types.h>
[1]27#include <hal_special.h>
28#include <printk.h>
29#include <list.h>
30#include <bits.h>
31#include <page.h>
[585]32#include <dqdt.h>
[567]33#include <busylock.h>
34#include <queuelock.h>
[1]35#include <thread.h>
36#include <cluster.h>
37#include <kmem.h>
38#include <process.h>
[567]39#include <mapper.h>
[1]40#include <ppm.h>
[606]41#include <vfs.h>
[1]42
[567]43////////////////////////////////////////////////////////////////////////////////////////
[634]44//         global variables
45////////////////////////////////////////////////////////////////////////////////////////
46
47extern chdev_directory_t    chdev_dir;          // allocated in kernel_init.c
48
49////////////////////////////////////////////////////////////////////////////////////////
[567]50//     functions to  translate [ page <-> base <-> ppn ]
51////////////////////////////////////////////////////////////////////////////////////////
52
[50]53/////////////////////////////////////////////
[315]54inline xptr_t ppm_page2base( xptr_t page_xp )
[1]55{
[315]56        ppm_t  * ppm      = &LOCAL_CLUSTER->ppm;
[1]57
[315]58    cxy_t    page_cxy = GET_CXY( page_xp );
[437]59    page_t * page_ptr = GET_PTR( page_xp );
[315]60
[406]61   void   * base_ptr = ppm->vaddr_base + 
[683]62                       ((page_ptr - ppm->pages_tbl)<<CONFIG_PPM_PAGE_ORDER);
[406]63
[315]64        return XPTR( page_cxy , base_ptr );
65
66} // end ppm_page2base()
67
68/////////////////////////////////////////////
69inline xptr_t ppm_base2page( xptr_t base_xp )
[1]70{
[315]71        ppm_t  * ppm = &LOCAL_CLUSTER->ppm;
[1]72
[315]73    cxy_t    base_cxy = GET_CXY( base_xp );
[437]74    void   * base_ptr = GET_PTR( base_xp );
[315]75
76        page_t * page_ptr = ppm->pages_tbl + 
[683]77                        ((base_ptr - ppm->vaddr_base)>>CONFIG_PPM_PAGE_ORDER);
[315]78
79        return XPTR( base_cxy , page_ptr );
80
81}  // end ppm_base2page()
82
83
84
[50]85///////////////////////////////////////////
[315]86inline ppn_t ppm_page2ppn( xptr_t page_xp )
87{
88        ppm_t  * ppm      = &LOCAL_CLUSTER->ppm;
89
90    cxy_t    page_cxy = GET_CXY( page_xp );
[437]91    page_t * page_ptr = GET_PTR( page_xp );
[315]92
[683]93    paddr_t  paddr    = PADDR( page_cxy , (page_ptr - ppm->pages_tbl)<<CONFIG_PPM_PAGE_ORDER );
[315]94
[683]95    return (ppn_t)(paddr >> CONFIG_PPM_PAGE_ORDER);
[315]96
97}  // end hal_page2ppn()
98
99///////////////////////////////////////
100inline xptr_t ppm_ppn2page( ppn_t ppn )
101{
[437]102        ppm_t   * ppm  = &LOCAL_CLUSTER->ppm;
[315]103
[683]104    paddr_t  paddr = ((paddr_t)ppn) << CONFIG_PPM_PAGE_ORDER;
[315]105
[437]106    cxy_t    cxy   = CXY_FROM_PADDR( paddr );
107    lpa_t    lpa   = LPA_FROM_PADDR( paddr );
[315]108
[683]109    return XPTR( cxy , &ppm->pages_tbl[lpa>>CONFIG_PPM_PAGE_ORDER] );
[315]110
111}  // end hal_ppn2page
112
113
114
115///////////////////////////////////////
116inline xptr_t ppm_ppn2base( ppn_t ppn )
117{
[437]118        ppm_t  * ppm   = &LOCAL_CLUSTER->ppm;
[315]119   
[683]120    paddr_t  paddr = ((paddr_t)ppn) << CONFIG_PPM_PAGE_ORDER;
[315]121
[437]122    cxy_t    cxy   = CXY_FROM_PADDR( paddr );
123    lpa_t    lpa   = LPA_FROM_PADDR( paddr );
[315]124
[437]125        return XPTR( cxy , (void *)ppm->vaddr_base + lpa );
[315]126
127}  // end ppm_ppn2base()
128
129///////////////////////////////////////////
130inline ppn_t ppm_base2ppn( xptr_t base_xp )
131{
132        ppm_t  * ppm      = &LOCAL_CLUSTER->ppm;
133
134    cxy_t    base_cxy = GET_CXY( base_xp );
[437]135    void   * base_ptr = GET_PTR( base_xp );
[315]136
137    paddr_t  paddr    = PADDR( base_cxy , (base_ptr - ppm->vaddr_base) );
138
[683]139    return (ppn_t)(paddr >> CONFIG_PPM_PAGE_ORDER);
[315]140
141}  // end ppm_base2ppn()
142
143
[567]144////////////////////////////////////////////////////////////////////////////////////////
145//     functions to  allocate / release  physical pages
146////////////////////////////////////////////////////////////////////////////////////////
[315]147
148///////////////////////////////////////////
[50]149void ppm_free_pages_nolock( page_t * page )
[1]150{
[636]151        page_t   * buddy;               // searched buddy page descriptor
152        uint32_t   buddy_index;         // buddy page index in page_tbl[]
[656]153        page_t   * current_ptr;         // current (merged) page descriptor
[636]154        uint32_t   current_index;       // current (merged) page index in page_tbl[]
155        uint32_t   current_order;       // current (merged) page order
[7]156
[160]157        ppm_t    * ppm         = &LOCAL_CLUSTER->ppm;
158        page_t   * pages_tbl   = ppm->pages_tbl;
[1]159
[672]160assert( __FUNCTION__, !page_is_flag( page , PG_FREE ) ,
[683]161"page already released : ppn = %x" , ppm_page2ppn( XPTR( local_cxy , page ) ) );
[177]162
[672]163assert( __FUNCTION__, !page_is_flag( page , PG_RESERVED ) ,
[683]164"reserved page : ppn = %x" , ppm_page2ppn( XPTR( local_cxy , page ) ) );
[407]165
[636]166        // set FREE flag in released page descriptor
[1]167        page_set_flag( page , PG_FREE );
168
[636]169    // initialise loop variables
[656]170    current_ptr   = page;
[636]171    current_order = page->order;
172        current_index = page - ppm->pages_tbl;
173
[160]174        // search the buddy page descriptor
[636]175        // - merge with current page if buddy found
176        // - exit to release the current page when buddy not found
177    while( current_order < CONFIG_PPM_MAX_ORDER )
178    {
179        // compute buddy page index and page descriptor
[7]180                buddy_index = current_index ^ (1 << current_order);
181                buddy       = pages_tbl + buddy_index;
[636]182       
183        // exit loop if buddy not found in current free list
184                if( !page_is_flag( buddy , PG_FREE ) || (buddy->order != current_order) ) break;
[18]185
[636]186        // remove buddy page from current free_list
[7]187                list_unlink( &buddy->list );
[1]188                ppm->free_pages_nr[current_order] --;
[18]189
[636]190        // reset order field in buddy page descriptor
[7]191                buddy->order = 0;
[632]192
[656]193                // compute next values for loop variables
[7]194                current_index &= buddy_index;
[636]195        current_order++;
[656]196        current_ptr = pages_tbl + current_index; 
[636]197    }
198
199        // update order field for merged page descriptor
[656]200        current_ptr->order = current_order;
[1]201
[636]202        // insert merged page in relevant free list
[656]203        list_add_first( &ppm->free_pages_root[current_order] , &current_ptr->list );
[1]204        ppm->free_pages_nr[current_order] ++;
205
[433]206}  // end ppm_free_pages_nolock()
207
[1]208////////////////////////////////////////////
209page_t * ppm_alloc_pages( uint32_t   order )
210{
[632]211        page_t   * current_block;
[160]212        uint32_t   current_order;
[1]213        uint32_t   current_size;
[632]214        page_t   * found_block; 
[551]215
[656]216        ppm_t    * ppm = &LOCAL_CLUSTER->ppm;
217
[683]218#if DEBUG_PPM_ALLOC_PAGES || DEBUG_PPM_ERROR
219thread_t * this  = CURRENT_THREAD;
220uint32_t   cycle = (uint32_t)hal_get_cycles();
[433]221#endif
[1]222
[656]223#if DEBUG_PPM_ALLOC_PAGES
[438]224if( DEBUG_PPM_ALLOC_PAGES < cycle )
[636]225{
226    printk("\n[%s] thread[%x,%x] enter for %d page(s) in cluster %x / cycle %d\n",
227    __FUNCTION__, this->process->pid, this->trdid, 1<<order, local_cxy, cycle );
[656]228    if( DEBUG_PPM_ALLOC_PAGES & 1 ) ppm_remote_display( local_cxy );
[636]229}
[433]230#endif
231
[611]232// check order
[683]233assert( __FUNCTION__, (order < CONFIG_PPM_MAX_ORDER) ,
234"illegal order argument = %d" , order );
[1]235
[632]236    //build extended pointer on lock protecting remote PPM
237    xptr_t lock_xp = XPTR( local_cxy , &ppm->free_lock );
[1]238
[160]239        // take lock protecting free lists
[632]240        remote_busylock_acquire( lock_xp );
[1]241
[632]242        current_block = NULL;
[635]243    current_order = order;
[632]244
[635]245        // search a free block equal or larger than requested size
246        while( current_order < CONFIG_PPM_MAX_ORDER )
[1]247        {
[635]248        // get local pointer on the root of relevant free_list (same in all clusters)
249        list_entry_t * root = &ppm->free_pages_root[current_order];
250
251                if( !list_is_empty( root ) )
[1]252                {
[632]253            // get first free block in this free_list
[635]254                        current_block = LIST_FIRST( root , page_t , list );
[632]255
256            // remove this block from this free_list
257                        list_unlink( &current_block->list );
[635]258                ppm->free_pages_nr[current_order] --;
[632]259
260            // register pointer on found block
261            found_block = current_block;
262
263            // compute found block size
264                current_size = (1 << current_order);
265
266                        break; 
[1]267                }
[635]268
269        // increment loop index
270        current_order++;
[1]271        }
272
[632]273        if( current_block == NULL ) // return failure if no free block found
[1]274        {
[683]275
276#if DEBUG_PPM_ERROR
277printk("\n[ERROR] in %s thread[%x,%x] cannot allocate %d page(s) in cluster %x / cycle %d\n",
278__FUNCTION__, this->process->pid, this->trdid, 1<<order, local_cxy, cycle );
279#endif
280        // release lock protecting free lists
[632]281                remote_busylock_release( lock_xp );
[160]282                return NULL;
283        }
[18]284
[1]285
[632]286        // split the found block in smaller sub-blocks if required
[160]287        // and update the free-lists accordingly
[1]288        while( current_order > order )
289        {
[635]290        // update size and order
[1]291                current_order --;
[635]292                current_size >>= 1;
[632]293
[651]294        // update order fields in new free block
[632]295                current_block = found_block + current_size;
296                current_block->order = current_order;
[18]297
[632]298        // insert new free block in relevant free_list
299                list_add_first( &ppm->free_pages_root[current_order] , &current_block->list );
[1]300                ppm->free_pages_nr[current_order] ++;
301        }
[18]302
[632]303        // update found block page descriptor
304        page_clear_flag( found_block , PG_FREE );
305        page_refcount_up( found_block );
306        found_block->order = order;
[1]307
[160]308        // release lock protecting free lists
[632]309        remote_busylock_release( lock_xp );
[18]310
[585]311    // update DQDT
[632]312    dqdt_increment_pages( local_cxy , order );
[585]313
[656]314    hal_fence();
315
[438]316#if DEBUG_PPM_ALLOC_PAGES
317if( DEBUG_PPM_ALLOC_PAGES < cycle )
[636]318{
319    printk("\n[%s] thread[%x,%x] allocated %d page(s) in cluster %x / ppn %x / cycle %d\n",
320    __FUNCTION__, this->process->pid, this->trdid, 
321    1<<order, local_cxy, ppm_page2ppn(XPTR( local_cxy , found_block )), cycle );
[656]322    if( DEBUG_PPM_ALLOC_PAGES & 1 ) ppm_remote_display( local_cxy );
[636]323}
[433]324#endif
[7]325
[632]326        return found_block;
[1]327
[433]328}  // end ppm_alloc_pages()
[1]329
330////////////////////////////////////
331void ppm_free_pages( page_t * page )
332{
333        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
[18]334
[438]335#if DEBUG_PPM_FREE_PAGES
[632]336thread_t * this  = CURRENT_THREAD;
337uint32_t   cycle = (uint32_t)hal_get_cycles();
[433]338#endif
339
[656]340#if DEBUG_PPM_FREE_PAGES
[438]341if( DEBUG_PPM_FREE_PAGES < cycle )
[636]342{
343    printk("\n[%s] thread[%x,%x] enter for %d page(s) in cluster %x / ppn %x / cycle %d\n",
344    __FUNCTION__, this->process->pid, this->trdid, 
345    1<<page->order, local_cxy, ppm_page2ppn(XPTR(local_cxy , page)), cycle );
[656]346    if( DEBUG_PPM_FREE_PAGES & 1 ) ppm_remote_display( local_cxy );
347}
[433]348#endif
349
[632]350    //build extended pointer on lock protecting free_lists
351    xptr_t lock_xp = XPTR( local_cxy , &ppm->free_lock );
352
[160]353        // get lock protecting free_pages[] array
[632]354        remote_busylock_acquire( lock_xp );
[1]355
[18]356        ppm_free_pages_nolock( page );
[1]357
[632]358        // release lock protecting free_lists
359        remote_busylock_release( lock_xp );
[433]360
[585]361    // update DQDT
[632]362    dqdt_decrement_pages( local_cxy , page->order );
[585]363
[656]364    hal_fence();
365
[438]366#if DEBUG_PPM_FREE_PAGES
367if( DEBUG_PPM_FREE_PAGES < cycle )
[636]368{
369    printk("\n[%s] thread[%x,%x] released %d page(s) in cluster %x / ppn %x / cycle %d\n",
370    __FUNCTION__, this->process->pid, this->trdid, 
371    1<<page->order, local_cxy, ppm_page2ppn(XPTR(local_cxy , page)) , cycle );
[656]372    if( DEBUG_PPM_FREE_PAGES & 1 ) ppm_remote_display( local_cxy );
[636]373}
[433]374#endif
375
[567]376}  // end ppm_free_pages()
[1]377
[636]378
[632]379/////////////////////////////////////////////
[656]380xptr_t ppm_remote_alloc_pages( cxy_t     cxy,
[632]381                               uint32_t  order )
[1]382{
[632]383        uint32_t   current_order;
384        uint32_t   current_size;
385    page_t   * current_block;   
386    page_t   * found_block;
387
[656]388// check order
[683]389assert( __FUNCTION__, (order < CONFIG_PPM_MAX_ORDER) ,
390"illegal order argument = %d" , order );
[656]391
392    // get local pointer on PPM (same in all clusters)
393        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
394
[683]395#if DEBUG_PPM_ALLOC_PAGES || DEBUG_PPM_ERROR
396thread_t * this  = CURRENT_THREAD;
[632]397uint32_t   cycle = (uint32_t)hal_get_cycles();
398#endif
399
[683]400#if DEBUG_PPM_ALLOC_PAGES
401if( DEBUG_PPM_ALLOC_PAGES < cycle )
[636]402{
[656]403    printk("\n[%s] thread[%x,%x] enter for %d page(s) in cluster %x / cycle %d\n",
[636]404    __FUNCTION__, this->process->pid, this->trdid, 1<<order, cxy, cycle );
[683]405    if( DEBUG_PPM_ALLOC_PAGES & 1 ) ppm_remote_display( cxy );
[636]406}
[632]407#endif
408
409    //build extended pointer on lock protecting remote PPM
410    xptr_t lock_xp = XPTR( cxy , &ppm->free_lock );
411
412        // take lock protecting free lists in remote cluster
413        remote_busylock_acquire( lock_xp );
414
415    current_block = NULL;   
[635]416    current_order = order;
[632]417
[635]418    // search a free block equal or larger than requested size
419    while( current_order < CONFIG_PPM_MAX_ORDER )
420    {
421        // get local pointer on the root of relevant free_list (same in all clusters)
[632]422        list_entry_t * root = &ppm->free_pages_root[current_order];
423
[635]424                if( !list_remote_is_empty( cxy , root ) )  // list non empty => success
[632]425                {
426            // get local pointer on first free page descriptor in remote cluster
427                        current_block = LIST_REMOTE_FIRST( cxy, root , page_t , list );
428
429            // remove first free page from the free-list in remote cluster
430                        list_remote_unlink( cxy , &current_block->list );
[635]431                hal_remote_atomic_add( XPTR( cxy , &ppm->free_pages_nr[current_order] ), -1 );
[632]432
433            // register found block
434            found_block = current_block;
435
436            // compute found block size
437                current_size = (1 << current_order);
438
439                        break;
440                }
[635]441
442        // increment loop index
443        current_order++;
[632]444        }
445
446        if( current_block == NULL ) // return failure
447        {
[683]448
449#if DEBUG_PPM_ERROR
450 printk("\n[ERROR] in %s : thread[%x,%x] cannot allocate %d page(s) in cluster %x / cycle %d\n",
451__FUNCTION__, this->process->pid, this->trdid, 1<<order, cxy, cycle );
452#endif
[632]453                // release lock protecting free lists
454                remote_busylock_release( lock_xp );
455                return XPTR_NULL;
456        }
457
458        // split the found block in smaller sub-blocks if required
459        // and update the free-lists accordingly in remote cluster
460        while( current_order > order )
461        {
[635]462        // update order and size
[632]463                current_order --;
464                current_size >>= 1;
465
466        // update new free block order field in remote cluster
[635]467                current_block = found_block + current_size;
[632]468                hal_remote_s32( XPTR( cxy , &current_block->order ) , current_order );
469
470        // get local pointer on the root of the relevant free_list in remote cluster 
471        list_entry_t * root = &ppm->free_pages_root[current_order];
472
473        // insert new free block in this free_list
474                list_remote_add_first( cxy , root, &current_block->list );
475
476        // update free-list number of items in remote cluster
477        hal_remote_atomic_add( XPTR(cxy , &ppm->free_pages_nr[current_order]), 1 );
478        }
479
[634]480        // update refcount, flags and order fields in found block
[632]481        page_remote_clear_flag( XPTR( cxy , found_block ), PG_FREE );
482        page_remote_refcount_up( XPTR( cxy , found_block ) );
483        hal_remote_s32( XPTR( cxy , &found_block->order ) , order );
484   
485        // release lock protecting free lists in remote cluster
486        remote_busylock_release( lock_xp );
487
488    // update DQDT page counter in remote cluster
489    dqdt_increment_pages( cxy , order );
490
[656]491    hal_fence();
492
[683]493#if DEBUG_PPM_ALLOC_PAGES
494if( DEBUG_PPM_ALLOC_PAGES < cycle )
[636]495{
496    printk("\n[%s] thread[%x,%x] allocated %d page(s) in cluster %x / ppn %x / cycle %d\n",
497    __FUNCTION__, this->process->pid, this->trdid, 
498    1<<order, cxy, ppm_page2ppn(XPTR( cxy , found_block )), cycle );
[683]499    if( DEBUG_PPM_ALLOC_PAGES & 1 ) ppm_remote_display( cxy );
[636]500}
[632]501#endif
502
[656]503        return XPTR( cxy , found_block );
[632]504
505}  // end ppm_remote_alloc_pages()
506
[636]507///////////////////////////////////////////////
508void ppm_remote_free_pages( cxy_t     page_cxy,
509                            page_t  * page_ptr )
[632]510{
511    xptr_t     page_xp;          // extended pointer on released page descriptor
[636]512        page_t   * buddy_ptr;        // searched buddy page descriptor
513    uint32_t   buddy_order;      // searched buddy page order
514        uint32_t   buddy_index;      // buddy page index in page_tbl[]
515        page_t   * current_ptr;      // current (merged) page descriptor
516        uint32_t   current_index;    // current (merged) page index in page_tbl[]
517        uint32_t   current_order;    // current (merged) page order
[632]518
[656]519    // get local pointer on PPM (same in all clusters)
520        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
521
522    // get page ppn and order
523    uint32_t   order = hal_remote_l32( XPTR( page_cxy , &page_ptr->order ) );
524
[683]525#if DEBUG_PPM_FREE_PAGES
[632]526thread_t * this  = CURRENT_THREAD;
527uint32_t   cycle = (uint32_t)hal_get_cycles();
[656]528ppn_t      ppn   = ppm_page2ppn( XPTR( page_cxy , page_ptr ) );
[632]529#endif
530
[683]531#if DEBUG_PPM_FREE_PAGES
532if( DEBUG_PPM_FREE_PAGES < cycle )
[636]533{
534    printk("\n[%s] thread[%x,%x] enter for %d page(s) in cluster %x / ppn %x / cycle %d\n",
[656]535    __FUNCTION__, this->process->pid, this->trdid, 1<<order, page_cxy, ppn, cycle );
[683]536    if( DEBUG_PPM_FREE_PAGES & 1 ) ppm_remote_display( page_cxy );
[636]537}
[632]538#endif
539
540    // build extended pointer on released page descriptor
[636]541    page_xp = XPTR( page_cxy , page_ptr );
[632]542   
543    // build extended pointer on lock protecting remote PPM
[636]544    xptr_t lock_xp = XPTR( page_cxy , &ppm->free_lock );
[632]545
546    // get local pointer on remote PPM page_tbl[] array
[636]547        page_t * pages_tbl = hal_remote_lpt( XPTR( page_cxy , &ppm->pages_tbl ) );
[632]548
549        // get lock protecting free_pages in remote cluster
550        remote_busylock_acquire( lock_xp );
551
[672]552assert( __FUNCTION__, !page_remote_is_flag( page_xp , PG_FREE ) ,
[683]553"page already released : ppn = %x" , ppm_page2ppn(XPTR( page_cxy , page_ptr ) ) );
[632]554
[672]555assert( __FUNCTION__, !page_remote_is_flag( page_xp , PG_RESERVED ) ,
[683]556"reserved page : ppn = %x" , ppm_page2ppn(XPTR( page_cxy , page_ptr ) ) );
[632]557
[636]558        // set the FREE flag in released page descriptor
[632]559        page_remote_set_flag( page_xp , PG_FREE );
560
[636]561    // initialise loop variables
562    current_ptr   = page_ptr;
[656]563    current_order = order;
[636]564        current_index = page_ptr - ppm->pages_tbl;
565
[632]566        // search the buddy page descriptor
[636]567        // - merge with current page descriptor if buddy found
568        // - exit to release the current page descriptor if buddy not found
569    while( current_order < CONFIG_PPM_MAX_ORDER )
570    {
571        // compute buddy page index and local pointer on page descriptor
[632]572                buddy_index = current_index ^ (1 << current_order);
573                buddy_ptr   = pages_tbl + buddy_index;
[637]574
575        // get buddy order
576        buddy_order = hal_remote_l32( XPTR( page_cxy , &buddy_ptr->order ) );
[636]577       
578        // exit loop if buddy not found
579                if( !page_remote_is_flag( XPTR( page_cxy , buddy_ptr ) , PG_FREE ) || 
[632]580            (buddy_order != current_order) ) break;
581
[636]582        // remove buddy page from its free list in remote cluster
583                list_remote_unlink( page_cxy , &buddy_ptr->list );
584        hal_remote_atomic_add( XPTR( page_cxy , &ppm->free_pages_nr[current_order] ) , -1 );
[632]585
[636]586        // reset order field in buddy page descriptor
587        hal_remote_s32( XPTR( page_cxy , &buddy_ptr->order ) , 0 );
[632]588
[656]589                // compute next values for loop variables
[632]590                current_index &= buddy_index;
[636]591        current_order++;
592        current_ptr = pages_tbl + current_index; 
593
594    }  // end loop on order
595
596        // update current (merged) page descriptor order field
597    hal_remote_s32( XPTR( page_cxy , &current_ptr->order ) , current_order );
[632]598
[636]599        // insert current (merged) page into relevant free list
[656]600        list_remote_add_first( page_cxy, &ppm->free_pages_root[current_order], &current_ptr->list );
[636]601    hal_remote_atomic_add( XPTR( page_cxy , &ppm->free_pages_nr[current_order] ) , 1 );
[632]602
603        // release lock protecting free_pages[] array
604        remote_busylock_release( lock_xp );
605
606    // update DQDT
[636]607    dqdt_decrement_pages( page_cxy , page_ptr->order );
[632]608
[656]609    hal_fence();
610
[683]611#if DEBUG_PPM_FREE_PAGES
612if( DEBUG_PPM_FREE_PAGES < cycle )
[636]613{
614    printk("\n[%s] thread[%x,%x] released %d page(s) in cluster %x / ppn %x / cycle %d\n",
[656]615    __FUNCTION__, this->process->pid, this->trdid, 1<<order, page_cxy, ppn, cycle );
[683]616    if( DEBUG_PPM_FREE_PAGES & 1 ) ppm_remote_display( page_cxy );
[636]617}
[632]618#endif
619
620}  // end ppm_remote_free_pages()
621
622////////////////////////////////////
623void ppm_remote_display( cxy_t cxy )
624{
[1]625        uint32_t       order;
626        list_entry_t * iter;
[634]627    xptr_t         page_xp;
[1]628
[433]629    ppm_t * ppm = &LOCAL_CLUSTER->ppm;
630
[636]631    // get remote PPM general parameters
632    uint32_t   pages_nr   = hal_remote_l32( XPTR( cxy , &ppm->pages_nr ) );
633    void     * vaddr_base = hal_remote_lpt( XPTR( cxy , &ppm->vaddr_base ) ); 
634    void     * pages_tbl  = hal_remote_lpt( XPTR( cxy , &ppm->pages_tbl ) ); 
635
[632]636    // build extended pointer on lock protecting remote PPM
[634]637    xptr_t ppm_lock_xp = XPTR( cxy , &ppm->free_lock );
[1]638
[634]639    // get pointers on TXT0 chdev
640    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
641    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
642    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
[632]643
[634]644    // build extended pointer on remote TXT0 lock
645    xptr_t  txt_lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
[18]646
[634]647        // get PPM lock
648        remote_busylock_acquire( ppm_lock_xp );
649
650    // get TXT0 lock
651    remote_busylock_acquire( txt_lock_xp );
652
[636]653        nolock_printk("\n***** PPM in cluster %x / %d pages / page_tbl %x / vaddr_base %x\n",
654    local_cxy, pages_nr, pages_tbl, vaddr_base );
[634]655
[1]656        for( order = 0 ; order < CONFIG_PPM_MAX_ORDER ; order++ )
657        {
[632]658        // get number of free pages for free_list[order] in remote cluster
659        uint32_t n = hal_remote_l32( XPTR( cxy , &ppm->free_pages_nr[order] ) );
[18]660
[656]661        // display forward free_list[order]
662                nolock_printk("- forward  : order = %d / n = %d : ", order , n );
[632]663                LIST_REMOTE_FOREACH( cxy , &ppm->free_pages_root[order] , iter )
[1]664                {
[634]665            page_xp = XPTR( cxy , LIST_ELEMENT( iter , page_t , list ) );
666                        nolock_printk("%x," , ppm_page2ppn( page_xp ) );
[1]667                }
[634]668                nolock_printk("\n");
[656]669
670        // display backward free_list[order]
671                nolock_printk("- backward : order = %d / n = %d : ", order , n );
672                LIST_REMOTE_FOREACH_BACKWARD( cxy , &ppm->free_pages_root[order] , iter )
673                {
674            page_xp = XPTR( cxy , LIST_ELEMENT( iter , page_t , list ) );
675                        nolock_printk("%x," , ppm_page2ppn( page_xp ) );
676                }
677                nolock_printk("\n");
[1]678        }
679
[634]680        // release TXT0 lock
681        remote_busylock_release( txt_lock_xp );
682
683        // release PPM lock
684        remote_busylock_release( ppm_lock_xp );
[160]685}
[1]686
[632]687////////////////////////////////
688error_t ppm_assert_order( void )
[1]689{
690        uint32_t       order;
691        list_entry_t * iter;
692        page_t       * page;
[18]693
[632]694    ppm_t * ppm = &LOCAL_CLUSTER->ppm;
695
[407]696        for( order=0 ; order < CONFIG_PPM_MAX_ORDER ; order++ )
[1]697        {
698                if( list_is_empty( &ppm->free_pages_root[order] ) ) continue;
[18]699
[1]700                LIST_FOREACH( &ppm->free_pages_root[order] , iter )
701                {
702                        page = LIST_ELEMENT( iter , page_t , list );
[160]703                        if( page->order != order )  return -1;
[1]704                }
705        }
706
[160]707        return 0;
708}
[53]709
[567]710
711//////////////////////////////////////////////////////////////////////////////////////
712//     functions to handle  dirty physical pages
713//////////////////////////////////////////////////////////////////////////////////////
714
[606]715//////////////////////////////////////////
716bool_t ppm_page_do_dirty( xptr_t page_xp )
[567]717{
718        bool_t done = false;
719
[606]720    // get page cluster and local pointer
721    page_t * page_ptr = GET_PTR( page_xp );
722    cxy_t    page_cxy = GET_CXY( page_xp );
723
724    // get local pointer on PPM (same in all clusters)
[567]725        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
726
[606]727    // build extended pointers on page lock, page flags, and PPM dirty list lock
728    xptr_t page_lock_xp  = XPTR( page_cxy , &page_ptr->lock  );   
729    xptr_t page_flags_xp = XPTR( page_cxy , &page_ptr->flags );
730    xptr_t dirty_lock_xp = XPTR( page_cxy , &ppm->dirty_lock );
731           
732        // lock the remote PPM dirty_list
733        remote_queuelock_acquire( dirty_lock_xp );
[567]734
[606]735    // lock the remote page
736    remote_busylock_acquire( page_lock_xp );
737
738    // get remote page flags
739    uint32_t flags = hal_remote_l32( page_flags_xp );
740
741        if( (flags & PG_DIRTY) == 0 )
[567]742        {
743                // set dirty flag in page descriptor
[606]744        hal_remote_s32( page_flags_xp , flags | PG_DIRTY );
[567]745
[632]746                // insert the page in the remote dirty list
747        list_remote_add_first( page_cxy , &ppm->dirty_root , &page_ptr->list );
[606]748
[567]749                done = true;
750        }
751
[606]752    // unlock the remote page
753    remote_busylock_release( page_lock_xp );
[567]754
[606]755        // unlock the remote PPM dirty_list
756        remote_queuelock_release( dirty_lock_xp );
757
[567]758        return done;
759
[606]760} // end ppm_page_do_dirty()
761
762////////////////////////////////////////////
763bool_t ppm_page_undo_dirty( xptr_t page_xp )
[567]764{
765        bool_t done = false;
766
[606]767    // get page cluster and local pointer
768    page_t * page_ptr = GET_PTR( page_xp );
769    cxy_t    page_cxy = GET_CXY( page_xp );
770
771    // get local pointer on PPM (same in all clusters)
[567]772        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
773
[606]774    // build extended pointers on page lock, page flags, and PPM dirty list lock
775    xptr_t page_lock_xp  = XPTR( page_cxy , &page_ptr->lock  );
776    xptr_t page_flags_xp = XPTR( page_cxy , &page_ptr->flags );
777    xptr_t dirty_lock_xp = XPTR( page_cxy , &ppm->dirty_lock );
778           
779        // lock the remote PPM dirty_list
780        remote_queuelock_acquire( XPTR( page_cxy , &ppm->dirty_lock ) );
[567]781
[606]782    // lock the remote page
783    remote_busylock_acquire( page_lock_xp );
784
785    // get remote page flags
786    uint32_t flags = hal_remote_l32( page_flags_xp );
787
788        if( (flags & PG_DIRTY) )  // page is dirty
[567]789        {
[606]790                // reset dirty flag in page descriptor
791        hal_remote_s32( page_flags_xp , flags & (~PG_DIRTY) );
[567]792
[632]793        // remove the page from remote dirty list
794        list_remote_unlink( page_cxy , &page_ptr->list );
[606]795
[567]796                done = true;
797        }
798
[606]799    // unlock the remote page
800    remote_busylock_release( page_lock_xp );
[567]801
[606]802        // unlock the remote PPM dirty_list
803        remote_queuelock_release( dirty_lock_xp );
804
[567]805        return done;
806
[606]807}  // end ppm_page_undo_dirty()
808
809/////////////////////////////////
810void ppm_sync_dirty_pages( void )
[567]811{
[606]812        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
[567]813
[606]814    // get local pointer on PPM dirty_root
815    list_entry_t * dirty_root = &ppm->dirty_root;
816
817    // build extended pointer on PPM dirty_lock
818    xptr_t dirty_lock_xp = XPTR( local_cxy , &ppm->dirty_lock );
819
[567]820        // get the PPM dirty_list lock
[606]821        remote_queuelock_acquire( dirty_lock_xp );
[567]822
823        while( !list_is_empty( &ppm->dirty_root ) )
824        {
[606]825                page_t * page = LIST_FIRST( dirty_root ,  page_t , list );
826        xptr_t   page_xp = XPTR( local_cxy , page );
[567]827
[606]828        // build extended pointer on page lock
829        xptr_t page_lock_xp = XPTR( local_cxy , &page->lock );
830
[567]831                // get the page lock
[606]832                remote_busylock_acquire( page_lock_xp );
[567]833
834                // sync the page
[606]835                vfs_fs_move_page( page_xp , false );  // from mapper to device
[567]836
837                // release the page lock
[606]838                remote_busylock_release( page_lock_xp );
[567]839        }
840
841        // release the PPM dirty_list lock
[606]842        remote_queuelock_release( dirty_lock_xp );
[567]843
[606]844}  // end ppm_sync_dirty_pages()
845
Note: See TracBrowser for help on using the repository browser.