source: trunk/kernel/kern/cluster.c @ 438

Last change on this file since 438 was 438, checked in by alain, 6 years ago

Fix a bug in scheduler related to RPC blocking.

File size: 17.2 KB
Line 
1/*
2 * cluster.c - Cluster-Manager related operations
3 *
4 * Author  Ghassan Almaless (2008,2009,2010,2011,2012)
5 *         Mohamed Lamine Karaoui (2015)
6 *         Alain Greiner (2016,2017,2018)
7 *
8 * Copyright (c) UPMC Sorbonne Universites
9 *
10 * This file is part of ALMOS-MKH..
11 *
12 * ALMOS-MKH. is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; version 2.0 of the License.
15 *
16 * ALMOS-MKH. is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#include <kernel_config.h>
27#include <hal_types.h>
28#include <hal_atomic.h>
29#include <hal_special.h>
30#include <hal_ppm.h>
31#include <remote_fifo.h>
32#include <printk.h>
33#include <errno.h>
34#include <spinlock.h>
35#include <core.h>
36#include <scheduler.h>
37#include <list.h>
38#include <cluster.h>
39#include <boot_info.h>
40#include <bits.h>
41#include <ppm.h>
42#include <thread.h>
43#include <kmem.h>
44#include <process.h>
45#include <dqdt.h>
46
47/////////////////////////////////////////////////////////////////////////////////////
48// Extern global variables
49/////////////////////////////////////////////////////////////////////////////////////
50
51extern process_t process_zero;     // allocated in kernel_init.c file
52
53
54/////////////////////////////////////////////////
55error_t cluster_init( struct boot_info_s * info )
56{
57    error_t         error;
58    lpid_t          lpid;     // local process_index
59    lid_t           lid;      // local core index
60    uint32_t        i;        // index in loop on external peripherals
61    boot_device_t * dev;      // pointer on external peripheral
62    uint32_t        func;     // external peripheral functionnal type
63
64        cluster_t * cluster = LOCAL_CLUSTER;
65
66    // initialize cluster global parameters
67        cluster->paddr_width     = info->paddr_width;
68        cluster->x_width         = info->x_width;
69        cluster->y_width         = info->y_width;
70        cluster->x_size          = info->x_size;
71        cluster->y_size          = info->y_size;
72        cluster->io_cxy          = info->io_cxy;
73
74    // initialize external peripherals channels
75    for( i = 0 ; i < info->ext_dev_nr ; i++ )
76    {
77        dev  = &info->ext_dev[i];
78        func = FUNC_FROM_TYPE( dev->type );   
79        if( func == DEV_FUNC_TXT ) cluster->nb_txt_channels = dev->channels;
80        if( func == DEV_FUNC_NIC ) cluster->nb_nic_channels = dev->channels;
81        if( func == DEV_FUNC_IOC ) cluster->nb_ioc_channels = dev->channels;
82        if( func == DEV_FUNC_FBF ) cluster->nb_fbf_channels = dev->channels;
83    }
84
85    // initialize cluster local parameters
86        cluster->cores_nr        = info->cores_nr;
87
88    // initialize the lock protecting the embedded kcm allocator
89        spinlock_init( &cluster->kcm_lock );
90
91#if DEBUG_CLUSTER_INIT
92uint32_t cycle = (uint32_t)hal_get_cycles();
93if( DEBUG_CLUSTER_INIT < cycle )
94printk("\n[DBG] %s : thread %x enters for cluster %x / cycle %d\n",
95__FUNCTION__ , CURRENT_THREAD , local_cxy , cycle );
96#endif
97
98    // initialises DQDT
99    cluster->dqdt_root_level = dqdt_init( info->x_size,
100                                          info->y_size,
101                                          info->y_width ) - 1;
102
103    // initialises embedded PPM
104        error = hal_ppm_init( info );
105
106    if( error )
107    {
108        printk("\n[ERROR] in %s : cannot initialize PPM in cluster %x\n",
109               __FUNCTION__ , local_cxy );
110        return ENOMEM;
111    }
112
113#if( DEBUG_CLUSTER_INIT & 1 )
114cycle = (uint32_t)hal_get_cycles();
115if( DEBUG_CLUSTER_INIT < cycle )
116printk("\n[DBG] %s : PPM initialized in cluster %x / cycle %d\n",
117__FUNCTION__ , local_cxy , cycle );
118#endif
119
120    // initialises embedded KHM
121        khm_init( &cluster->khm );
122
123#if( DEBUG_CLUSTER_INIT & 1 )
124uint32_t cycle = (uint32_t)hal_get_cycles();
125if( DEBUG_CLUSTER_INIT < cycle )
126printk("\n[DBG] %s : KHM initialized in cluster %x at cycle %d\n",
127__FUNCTION__ , local_cxy , hal_get_cycles() );
128#endif
129
130    // initialises embedded KCM
131        kcm_init( &cluster->kcm , KMEM_KCM );
132
133#if( DEBUG_CLUSTER_INIT & 1 )
134uint32_t cycle = (uint32_t)hal_get_cycles();
135if( DEBUG_CLUSTER_INIT < cycle )
136printk("\n[DBG] %s : KCM initialized in cluster %x at cycle %d\n",
137__FUNCTION__ , local_cxy , hal_get_cycles() );
138#endif
139
140    // initialises all cores descriptors
141        for( lid = 0 ; lid < cluster->cores_nr; lid++ )
142        {
143                core_init( &cluster->core_tbl[lid],    // target core descriptor
144                       lid,                        // local core index
145                       info->core[lid].gid );      // gid from boot_info_t
146        }
147
148#if( DEBUG_CLUSTER_INIT & 1 )
149cycle = (uint32_t)hal_get_cycles();
150if( DEBUG_CLUSTER_INIT < cycle )
151printk("\n[DBG] %s : cores initialized in cluster %x / cycle %d\n",
152__FUNCTION__ , local_cxy , cycle );
153#endif
154
155    // initialises RPC fifo
156        local_fifo_init( &cluster->rpc_fifo );
157    cluster->rpc_threads = 0;
158
159#if( DEBUG_CLUSTER_INIT & 1 )
160cycle = (uint32_t)hal_get_cycles();
161if( DEBUG_CLUSTER_INIT < cycle )
162printk("\n[DBG] %s : RPC fifo inialized in cluster %x at cycle %d\n",
163__FUNCTION__ , local_cxy , hal_get_cycles() );
164#endif
165
166    // initialise pref_tbl[] in process manager
167        spinlock_init( &cluster->pmgr.pref_lock );
168    cluster->pmgr.pref_nr = 0;
169    cluster->pmgr.pref_tbl[0] = XPTR( local_cxy , &process_zero );
170    for( lpid = 1 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ )
171    {
172        cluster->pmgr.pref_tbl[lpid] = XPTR_NULL;
173    }
174
175    // initialise local_list in process manager
176        remote_spinlock_init( XPTR( local_cxy , &cluster->pmgr.local_lock ) );
177    xlist_root_init( XPTR( local_cxy , &cluster->pmgr.local_root ) );
178    cluster->pmgr.local_nr = 0;
179
180    // initialise copies_lists in process manager
181    for( lpid = 0 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ )
182    {
183            remote_spinlock_init( XPTR( local_cxy , &cluster->pmgr.copies_lock[lpid] ) );
184        cluster->pmgr.copies_nr[lpid] = 0;
185        xlist_root_init( XPTR( local_cxy , &cluster->pmgr.copies_root[lpid] ) );
186    }
187
188#if DEBUG_CLUSTER_INIT
189cycle = (uint32_t)hal_get_cycles();
190if( DEBUG_CLUSTER_INIT < cycle )
191printk("\n[DBG] %s , thread %x exit for cluster %x / cycle %d\n",
192__FUNCTION__ , CURRENT_THREAD , local_cxy , cycle );
193#endif
194
195    hal_fence();
196
197        return 0;
198} // end cluster_init()
199
200////////////////////////////////////////
201bool_t cluster_is_undefined( cxy_t cxy )
202{
203    cluster_t * cluster = LOCAL_CLUSTER;
204
205    uint32_t y_width = cluster->y_width;
206
207    uint32_t x = cxy >> y_width;
208    uint32_t y = cxy & ((1<<y_width)-1);
209
210    if( x >= cluster->x_size ) return true;
211    if( y >= cluster->y_size ) return true;
212
213    return false;
214}
215
216////////////////////////////////////////////////////////////////////////////////////
217//  Cores related functions
218////////////////////////////////////////////////////////////////////////////////////
219
220/////////////////////////////////
221lid_t cluster_select_local_core()
222{
223    uint32_t min = 100;
224    lid_t    sel = 0;
225    lid_t    lid;
226
227    cluster_t * cluster = LOCAL_CLUSTER;
228
229    for( lid = 0 ; lid < cluster->cores_nr ; lid++ )
230    {
231        if( cluster->core_tbl[lid].usage < min )
232        {
233            min = cluster->core_tbl[lid].usage;
234            sel = lid;
235        }
236    }
237    return sel;
238}
239
240////////////////////////////////////////////////////////////////////////////////////
241//  Process related functions
242////////////////////////////////////////////////////////////////////////////////////
243
244
245//////////////////////////////////////////////////////
246xptr_t cluster_get_owner_process_from_pid( pid_t pid )
247{
248    xptr_t      root_xp;       // xptr on root of list of processes in owner cluster
249    xptr_t      lock_xp;       // xptr on lock protecting this list
250    xptr_t      iter_xp;       // iterator
251    xptr_t      current_xp;    // xptr on current process descriptor
252    process_t * current_ptr;   // local pointer on current process
253    pid_t       current_pid;   // current process identifier
254    bool_t      found;
255
256    cluster_t * cluster = LOCAL_CLUSTER;
257
258    // get owner cluster and lpid
259    cxy_t  owner_cxy = CXY_FROM_PID( pid );
260
261    // get lock & root of list of process in owner cluster
262    root_xp = XPTR( owner_cxy , &cluster->pmgr.local_root );
263    lock_xp = XPTR( owner_cxy , &cluster->pmgr.local_lock );
264
265    // take the lock protecting the list of processes
266    remote_spinlock_lock( lock_xp );
267
268    // scan list of processes in owner cluster
269    found = false;
270    XLIST_FOREACH( root_xp , iter_xp )
271    {
272        current_xp  = XLIST_ELEMENT( iter_xp , process_t , local_list );
273        current_ptr = GET_PTR( current_xp );
274        current_pid = hal_remote_lw( XPTR( owner_cxy , &current_ptr->pid ) );
275
276        if( current_pid == pid )
277        {
278            found = true;
279            break;
280        }
281    }
282
283    // release the lock protecting the list of processes
284    remote_spinlock_unlock( lock_xp );
285
286    // return extended pointer on process descriptor in owner cluster
287    if( found ) return current_xp;
288    else        return XPTR_NULL;
289
290}  // end cluster_get_owner_process_from_pid()
291
292//////////////////////////////////////////////////////////
293xptr_t cluster_get_reference_process_from_pid( pid_t pid )
294{
295    xptr_t ref_xp;   // extended pointer on reference process descriptor
296
297    cluster_t * cluster = LOCAL_CLUSTER;
298
299    // get owner cluster and lpid
300    cxy_t  owner_cxy = CXY_FROM_PID( pid );
301    lpid_t lpid      = LPID_FROM_PID( pid );
302
303    // Check valid PID
304    if( lpid >= CONFIG_MAX_PROCESS_PER_CLUSTER )  return XPTR_NULL;
305
306    if( local_cxy == owner_cxy )   // local cluster is owner cluster
307    {
308        ref_xp = cluster->pmgr.pref_tbl[lpid];
309    }
310    else                              // use a remote_lwd to access owner cluster
311    {
312        ref_xp = (xptr_t)hal_remote_lwd( XPTR( owner_cxy , &cluster->pmgr.pref_tbl[lpid] ) );
313    }
314
315    return ref_xp;
316}
317
318///////////////////////////////////////////////
319error_t cluster_pid_alloc( process_t * process,
320                           pid_t     * pid )
321{
322    lpid_t      lpid;
323    bool_t      found;
324
325    pmgr_t    * pm         = &LOCAL_CLUSTER->pmgr;
326
327    // get the process manager lock
328    spinlock_lock( &pm->pref_lock );
329
330    // search an empty slot
331    found = false;
332    for( lpid = 0 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ )
333    {
334        if( pm->pref_tbl[lpid] == XPTR_NULL )
335        {
336            found = true;
337            break;
338        }
339    }
340
341    if( found )
342    {
343        // register process in pref_tbl[]
344        pm->pref_tbl[lpid] = XPTR( local_cxy , process );
345        pm->pref_nr++;
346
347        // returns pid
348        *pid = PID( local_cxy , lpid );
349
350        // release the processs_manager lock
351        spinlock_unlock( &pm->pref_lock );
352
353        return 0;
354    }
355    else
356    {
357        // release the processs_manager lock
358        spinlock_unlock( &pm->pref_lock );
359
360        return -1;
361    }
362
363} // end cluster_pid_alloc()
364
365/////////////////////////////////////
366void cluster_pid_release( pid_t pid )
367{
368    cxy_t  owner_cxy  = CXY_FROM_PID( pid );
369    lpid_t lpid       = LPID_FROM_PID( pid );
370
371    pmgr_t  * pm = &LOCAL_CLUSTER->pmgr;
372
373    // check pid argument
374    assert( (lpid < CONFIG_MAX_PROCESS_PER_CLUSTER) && (owner_cxy == local_cxy) ,
375    __FUNCTION__ , "illegal PID" );
376
377    // get the process manager lock
378    spinlock_lock( &pm->pref_lock );
379
380    // remove process from pref_tbl[]
381    pm->pref_tbl[lpid] = XPTR_NULL;
382    pm->pref_nr--;
383
384    // release the processs_manager lock
385    spinlock_unlock( &pm->pref_lock );
386
387} // end cluster_pid_release()
388
389///////////////////////////////////////////////////////////
390process_t * cluster_get_local_process_from_pid( pid_t pid )
391{
392    xptr_t         process_xp;
393    process_t    * process_ptr;
394    xptr_t         root_xp;
395    xptr_t         iter_xp;
396    bool_t         found;
397
398    found   = false;
399    root_xp = XPTR( local_cxy , &LOCAL_CLUSTER->pmgr.local_root );
400
401    XLIST_FOREACH( root_xp , iter_xp )
402    {
403        process_xp  = XLIST_ELEMENT( iter_xp , process_t , local_list );
404        process_ptr = (process_t *)GET_PTR( process_xp );
405        if( process_ptr->pid == pid )
406        {
407            found = true;
408            break;
409        }
410    }
411
412    if (found ) return process_ptr;
413    else        return NULL;
414
415}  // end cluster_get_local_process_from_pid()
416
417//////////////////////////////////////////////////////
418void cluster_process_local_link( process_t * process )
419{
420    uint32_t irq_state;
421    pmgr_t * pm = &LOCAL_CLUSTER->pmgr;
422
423    // get lock protecting the process manager local list
424    remote_spinlock_lock_busy( XPTR( local_cxy , &pm->local_lock ) , & irq_state );
425
426    xlist_add_last( XPTR( local_cxy , &pm->local_root ),
427                    XPTR( local_cxy , &process->local_list ) );
428    pm->local_nr++;
429
430    // release lock protecting the process manager local list
431    remote_spinlock_unlock_busy( XPTR( local_cxy , &pm->local_lock ) , irq_state );
432}
433
434////////////////////////////////////////////////////////
435void cluster_process_local_unlink( process_t * process )
436{
437    uint32_t irq_state;
438    pmgr_t * pm = &LOCAL_CLUSTER->pmgr;
439
440    // get lock protecting the process manager local list
441    remote_spinlock_lock_busy( XPTR( local_cxy , &pm->local_lock ) , &irq_state );
442
443    xlist_unlink( XPTR( local_cxy , &process->local_list ) );
444    pm->local_nr--;
445
446    // release lock protecting the process manager local list
447    remote_spinlock_unlock_busy( XPTR( local_cxy , &pm->local_lock ) , irq_state );
448}
449
450///////////////////////////////////////////////////////
451void cluster_process_copies_link( process_t * process )
452{
453    reg_t    irq_state;
454    pmgr_t * pm = &LOCAL_CLUSTER->pmgr;
455
456#if DEBUG_CLUSTER_PROCESS_COPIES
457uint32_t cycle = (uint32_t)hal_get_cycles();
458if( DEBUG_CLUSTER_PROCESS_COPIES < cycle )
459printk("\n[DBG] %s enters / cluster %x / process %x / cycle %d\n",
460__FUNCTION__ , local_cxy , process , cycle );
461#endif
462
463    // get owner cluster identifier CXY and process LPID
464    pid_t    pid        = process->pid;
465    cxy_t    owner_cxy  = CXY_FROM_PID( pid );
466    lpid_t   lpid       = LPID_FROM_PID( pid );
467
468    // get extended pointer on lock protecting copies_list[lpid]
469    xptr_t copies_lock  = XPTR( owner_cxy , &pm->copies_lock[lpid] );
470
471    // get extended pointer on the copies_list[lpid] root
472    xptr_t copies_root  = XPTR( owner_cxy , &pm->copies_root[lpid] );
473
474    // get extended pointer on the local copies_list entry
475    xptr_t copies_entry = XPTR( local_cxy , &process->copies_list );
476
477    // get lock protecting copies_list[lpid]
478    remote_spinlock_lock_busy( copies_lock , &irq_state );
479
480    // add copy to copies_list
481    xlist_add_first( copies_root , copies_entry );
482    hal_remote_atomic_add( XPTR( owner_cxy , &pm->copies_nr[lpid] ) , 1 );
483
484    // release lock protecting copies_list[lpid]
485    remote_spinlock_unlock_busy( copies_lock , irq_state );
486
487#if DEBUG_CLUSTER_PROCESS_COPIES
488cycle = (uint32_t)hal_get_cycles();
489if( DEBUG_CLUSTER_PROCESS_COPIES < cycle )
490printk("\n[DBG] %s exit / cluster %x / process %x / cycle %d\n",
491__FUNCTION__ , local_cxy , process , cycle );
492#endif
493
494}  // end cluster_process_copies_link()
495
496/////////////////////////////////////////////////////////
497void cluster_process_copies_unlink( process_t * process )
498{
499    uint32_t irq_state;
500    pmgr_t * pm = &LOCAL_CLUSTER->pmgr;
501
502#if DEBUG_CLUSTER_PROCESS_COPIES
503uint32_t cycle = (uint32_t)hal_get_cycles();
504if( DEBUG_CLUSTER_PROCESS_COPIES < cycle )
505printk("\n[DBG] %s enters / cluster %x / process %x / cycle %d\n",
506__FUNCTION__ , local_cxy , process , cycle );
507#endif
508
509    // get owner cluster identifier CXY and process LPID
510    pid_t    pid        = process->pid;
511    cxy_t    owner_cxy  = CXY_FROM_PID( pid );
512    lpid_t   lpid       = LPID_FROM_PID( pid );
513
514    // get extended pointer on lock protecting copies_list[lpid]
515    xptr_t copies_lock  = XPTR( owner_cxy , &pm->copies_lock[lpid] );
516
517    // get extended pointer on the local copies_list entry
518    xptr_t copies_entry = XPTR( local_cxy , &process->copies_list );
519
520    // get lock protecting copies_list[lpid]
521    remote_spinlock_lock_busy( copies_lock , &irq_state );
522
523    // remove copy from copies_list
524    xlist_unlink( copies_entry );
525    hal_remote_atomic_add( XPTR( owner_cxy , &pm->copies_nr[lpid] ) , -1 );
526
527    // release lock protecting copies_list[lpid]
528    remote_spinlock_unlock_busy( copies_lock , irq_state );
529
530#if DEBUG_CLUSTER_PROCESS_COPIES
531cycle = (uint32_t)hal_get_cycles();
532if( DEBUG_CLUSTER_PROCESS_COPIES < cycle )
533printk("\n[DBG] %s exit / cluster %x / process %x / cycle %d\n",
534__FUNCTION__ , local_cxy , process , cycle );
535#endif
536
537}  // end cluster_process_copies_unlink()
538
539///////////////////////////////////////////
540void cluster_processes_display( cxy_t cxy )
541{
542    xptr_t        root_xp;
543    xptr_t        iter_xp;
544    xptr_t        process_xp;     
545
546    // get extended pointer on root of process in cluster cxy
547    root_xp = XPTR( cxy , &LOCAL_CLUSTER->pmgr.local_root );
548
549    // skip one line
550    printk("\n***** processes in cluster %x / cycle %d\n", cxy , (uint32_t)hal_get_cycles() );
551
552    // loop on all reference processes in cluster cxy
553    XLIST_FOREACH( root_xp , iter_xp )
554    {
555        process_xp = XLIST_ELEMENT( iter_xp , process_t , local_list );
556        process_display( process_xp );
557    }
558}  // end cluster_processes_display()
559
560
Note: See TracBrowser for help on using the repository browser.