source: trunk/kernel/mm/kcm.c @ 26

Last change on this file since 26 was 20, checked in by max@…, 8 years ago

cosmetic and improve a few comments

File size: 9.3 KB
RevLine 
[1]1/*
2 * kcm.c - Per cluster & per type Kernel Cache Manager access functions
[18]3 *
[1]4 * Author  Ghassan Almaless (2008,2009,2010,2011,2012)
5 *         Alain Greiner    (2016)
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>
[1]26#include <hal_types.h>
27#include <hal_special.h>
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
38//////////////////////////////////////////////////////////////////////////////////////
[7]39// This static function returns pointer on an allocated block from an active page.
[1]40// It returns NULL if no block available in selected page.
41// It changes the page status if required.
42//////////////////////////////////////////////////////////////////////////////////////
[7]43// @ kcm   : pointer on kcm allocator.
44// @ ptr   : pointer on active kcm page to use.
45/////////////////////////////////////////////////////////////////////////////////////
46static void * kcm_get_block( kcm_t      * kcm,
47                             kcm_page_t * page )
[1]48{
[20]49        assert( page->active , __FUNCTION__ , "kcm page should be active" );
[1]50
[20]51        // get first block available
[18]52        int32_t index = bitmap_ffs( page->bitmap , kcm->blocks_nr );
[1]53
[20]54        assert( (index != -1) , __FUNCTION__ , "kcm page should not be full" );
[18]55
[20]56        // allocate block
[1]57        bitmap_clear( page->bitmap , index );
[7]58
[20]59        // increase page refcount
[1]60        page->refcount ++;
61
[20]62        // change the page to busy no more free block in page
63        if( page->refcount >= kcm->blocks_nr )
64        {
65                page->active = 0;
[1]66                list_unlink( &page->list);
67                kcm->active_pages_nr --;
68
69                list_add_first( &kcm->busy_root , &page->list);
70                kcm->busy_pages_nr ++;
[20]71                page->busy   = 1;
72        }
[1]73
[7]74        return (page->base + index * kcm->block_size );
[1]75
[7]76}  // kcm_get_block()
77
[1]78/////////////////////////////////////////////////////////////////////////////////////
79// This static function releases a previously allocated block.
80// It changes the page status if required.
81/////////////////////////////////////////////////////////////////////////////////////
[7]82// @ kcm   : pointer on kcm allocator.
83// @ ptr   : pointer on block to be released.
84/////////////////////////////////////////////////////////////////////////////////////
85static void kcm_put_block ( kcm_t * kcm,
86                            void  * ptr )
[1]87{
88        kcm_page_t * page;
[20]89        uint32_t     index;
[18]90
[1]91        page = (kcm_page_t*)((intptr_t)ptr & CONFIG_PPM_PAGE_MASK);
[7]92        index = ((uint8_t*)ptr - page->base) / kcm->block_size;
[18]93
[1]94        bitmap_set( page->bitmap , index );
95        page->refcount --;
[18]96
[20]97        // change the page to active if it was busy
[1]98        if( page->busy )
99        {
100                page->busy = 0;
101                list_unlink( &page->list );
102                kcm->busy_pages_nr --;
103
104                list_add_last( &kcm->active_root, &page->list );
105                kcm->active_pages_nr ++;
[20]106                page->active = 1;
[1]107        }
108
[20]109        // change the page to free if last block in active page
[1]110        if( (page->active) && (page->refcount == 0) )
111        {
[20]112                page->active = 0;
[1]113                list_unlink( &page->list);
114                kcm->active_pages_nr --;
115
116                list_add_first( &kcm->free_root , &page->list);
117                kcm->free_pages_nr ++;
118        }
[7]119}  // kcm_put_block()
[1]120
121/////////////////////////////////////////////////////////////////////////////////////
[7]122// This static function allocates one page from PPM. It initializes
[18]123// the KCM-page descriptor, and introduces the new page into freelist.
[1]124/////////////////////////////////////////////////////////////////////////////////////
125static error_t freelist_populate( kcm_t * kcm )
126{
127        page_t     * page;
128        kcm_page_t * ptr;
[20]129        kmem_req_t   req;
[1]130
[20]131        // get one page from local PPM
132        req.type  = KMEM_PAGE;
133        req.size  = 0;
134        req.flags = AF_KERNEL;
135        page = kmem_alloc( &req );
[18]136
[7]137        if( page == NULL )
138        {
[18]139                printk("\n[ERROR] in %s : failed to allocate page in cluster %d\n",
[20]140                       __FUNCTION__ , local_cxy );
141                return ENOMEM;
[7]142        }
143
[20]144        // get page base address
[1]145        ptr = ppm_page2base( page );
146
[20]147        // initialize KCM-page descriptor
[1]148        bitmap_set_range( ptr->bitmap , 0 , kcm->blocks_nr );
149
150        ptr->busy          = 0;
151        ptr->active        = 0;
152        ptr->refcount      = 0;
[7]153        ptr->base          = (uint8_t*)ptr + kcm->block_size;
[1]154        ptr->kcm           = kcm;
155        ptr->page          = page;
156
[20]157        // introduce new page in free-list
[1]158        list_add_first( &kcm->free_root , &ptr->list );
159        kcm->free_pages_nr ++;
[18]160
[1]161        return 0;
162
[7]163}  // freelist_populate()
164
[1]165/////////////////////////////////////////////////////////////////////////////////////
[20]166// This private function gets one KCM page from the KCM freelist.
[1]167// It populates the freelist if required.
168/////////////////////////////////////////////////////////////////////////////////////
169static kcm_page_t * freelist_get( kcm_t * kcm )
170{
[7]171        error_t      error;
[1]172        kcm_page_t * page;
173
[20]174        // get a new page from PPM if freelist empty
[1]175        if( kcm->free_pages_nr == 0 )
176        {
[20]177                error = freelist_populate( kcm );
178                if( error ) return NULL;
[1]179        }
180
[20]181        // get first KCM page from freelist and change its status to active
[1]182        page = LIST_FIRST( &kcm->free_root, kcm_page_t , list );
183        list_unlink( &page->list );
184        kcm->free_pages_nr --;
185
186        return page;
187
[7]188} // freelist_get()
[1]189
[7]190
191//////////////////////////////
192void kcm_init( kcm_t    * kcm,
193                   uint32_t   type )
[1]194{
195        uint32_t     blocks_nr;
196        uint32_t     block_size;
197        uint32_t     remaining;
198
[20]199        // initialize lock
[1]200        spinlock_init( &kcm->lock );
201
[20]202        // initialize KCM type
[1]203        kcm->type = type;
204
[20]205        // initialize KCM page lists
[1]206        kcm->free_pages_nr   = 0;
207        kcm->busy_pages_nr   = 0;
208        kcm->active_pages_nr = 0;
209        list_root_init( &kcm->free_root );
210        list_root_init( &kcm->busy_root );
211        list_root_init( &kcm->active_root );
212
[20]213        // initialize block size and number of blocks per page
[7]214        block_size      = ARROUND_UP( kmem_type_size( type ) , 64 );
[1]215        blocks_nr       = CONFIG_PPM_PAGE_SIZE / block_size;
216        remaining       = CONFIG_PPM_PAGE_SIZE % block_size;
217        blocks_nr       = (remaining >= sizeof(kcm_page_t)) ? blocks_nr : blocks_nr - 1;
218
219        kcm->blocks_nr  = blocks_nr;
220        kcm->block_size = block_size;
[18]221
[20]222        kcm_dmsg("\n[INFO] %s : KCM %s initialised / block_size = %d / blocks_nr = %d\n",
223                 __FUNCTION__ , kmem_type_str( type ) , block_size , blocks_nr );
[1]224
[7]225}  // kcm_init()
[1]226
227///////////////////////////////
228void kcm_destroy( kcm_t * kcm )
229{
230        kcm_page_t   * page;
231        list_entry_t * iter;
[18]232
[20]233        // get KCM lock
[1]234        spinlock_lock( &kcm->lock );
235
[20]236        // release all free pages
[1]237        LIST_FOREACH( &kcm->free_root , iter )
238        {
239                page = (kcm_page_t *)LIST_ELEMENT( iter , kcm_page_t , list );
240                list_unlink( iter );
241                kcm->free_pages_nr --;
242                ppm_free_pages( page->page );
243        }
244
[20]245        // release all active pages
[1]246        LIST_FOREACH( &kcm->active_root , iter )
247        {
248                page = (kcm_page_t *)LIST_ELEMENT( iter , kcm_page_t , list );
249                list_unlink( iter );
250                kcm->free_pages_nr --;
251                ppm_free_pages( page->page );
252        }
253
[20]254        // release all busy pages
[1]255        LIST_FOREACH( &kcm->busy_root , iter )
256        {
257                page = (kcm_page_t *)LIST_ELEMENT( iter , kcm_page_t , list );
258                list_unlink( iter );
259                kcm->free_pages_nr --;
260                ppm_free_pages( page->page );
261        }
262
[20]263        // release KCM lock
264        spinlock_unlock( &kcm->lock );
[1]265
[7]266}  // kcm_destroy()
[1]267
268///////////////////////////////
269void * kcm_alloc( kcm_t * kcm )
270{
271        kcm_page_t * page;
272        void       * ptr = NULL;   // pointer on block
273
[20]274        // get lock
[1]275        spinlock_lock( &kcm->lock );
[18]276
[20]277        // get an active page
278        if( list_is_empty( &kcm->active_root ) )  // no active page => get one
279        {
280                kcm_dmsg("\n[INFO] %s : enters for type %s but no active page => get one\n",
281                         __FUNCTION__ , kmem_type_str( kcm->type ) );
[7]282
[20]283                // get a page from free list
[7]284                page = freelist_get( kcm );
[20]285                if( page == NULL ) return NULL;
[7]286
[20]287                // insert page in active list
288                list_add_first( &kcm->active_root , &page->list );
289                kcm->active_pages_nr ++;
290                page->active = 1;
291        }
292        else                     // get first page from active list
293        {
294                kcm_dmsg("\n[INFO] %s : enters for type %s with an active page\n",
295                         __FUNCTION__ , kmem_type_str( kcm->type ) );
[7]296
[20]297                // get page pointer from active list
[7]298                page = (kcm_page_t *)LIST_FIRST( &kcm->active_root , kcm_page_t , list );
[20]299        }
[1]300
[20]301        // get a block from selected active page
302        // cannot fail, as an active page cannot be full...
303        ptr  = kcm_get_block( kcm , page );
[7]304
[20]305        // release lock
[1]306        spinlock_unlock(&kcm->lock);
307
[20]308        kcm_dmsg("\n[INFO] %s : allocated one block of type %s / ptr = %x\n",
309                 __FUNCTION__ , kmem_type_str( kcm->type ) , (uint32_t)ptr );
[7]310
[1]311        return ptr;
312
[7]313}  // kcm_alloc()
314
[1]315///////////////////////////
316void kcm_free( void * ptr )
317{
318        kcm_page_t * page;
319        kcm_t      * kcm;
[18]320
[1]321        if( ptr == NULL ) return;
[18]322
[1]323        page = (kcm_page_t *)((intptr_t)ptr & CONFIG_PPM_PAGE_MASK);
324        kcm  = page->kcm;
325
[20]326        // get lock
[1]327        spinlock_lock( &kcm->lock );
328
[20]329        // release block
[7]330        kcm_put_block( kcm , ptr );
[1]331
[20]332        // release lock
[1]333        spinlock_unlock( &kcm->lock );
334}
335
336////////////////////////////
337void kcm_print (kcm_t * kcm)
338{
[7]339        printk("*** KCM type = %s / free_pages = %d / busy_pages = %d / active_pages = %d\n",
[20]340               kmem_type_str( kcm->type ) ,
341               kcm->free_pages_nr ,
342               kcm->busy_pages_nr ,
343               kcm->active_pages_nr );
[1]344}
Note: See TracBrowser for help on using the repository browser.