/* * cluster.c - Cluster-Manager related operations * * Author Ghassan Almaless (2008,2009,2010,2011,2012) * Mohamed Lamine Karaoui (2015) * Alain Greiner (2016,2017,2018) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH.. * * ALMOS-MKH. is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH. is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH.; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ///////////////////////////////////////////////////////////////////////////////////// // Extern global variables ///////////////////////////////////////////////////////////////////////////////////// extern process_t process_zero; // allocated in kernel_init.c file extern chdev_directory_t chdev_dir; // allocated in kernel_init.c file ///////////////////////////////////////////////n error_t cluster_init( struct boot_info_s * info ) { error_t error; lpid_t lpid; // local process_index lid_t lid; // local core index uint32_t i; // index in loop on external peripherals boot_device_t * dev; // pointer on external peripheral uint32_t func; // external peripheral functionnal type cluster_t * cluster = LOCAL_CLUSTER; // initialize cluster global parameters cluster->paddr_width = info->paddr_width; cluster->x_width = info->x_width; cluster->y_width = info->y_width; cluster->x_size = info->x_size; cluster->y_size = info->y_size; cluster->x_max = info->x_max; // [FIXME] cluster->y_max = info->y_max; // [FIXME] cluster->io_cxy = info->io_cxy; // initialize external peripherals channels for( i = 0 ; i < info->ext_dev_nr ; i++ ) { dev = &info->ext_dev[i]; func = FUNC_FROM_TYPE( dev->type ); if( func == DEV_FUNC_TXT ) cluster->nb_txt_channels = dev->channels; if( func == DEV_FUNC_NIC ) cluster->nb_nic_channels = dev->channels; if( func == DEV_FUNC_IOC ) cluster->nb_ioc_channels = dev->channels; if( func == DEV_FUNC_FBF ) cluster->nb_fbf_channels = dev->channels; } // initialize cluster local parameters cluster->cores_nr = info->cores_nr; // initialize the lock protecting the embedded kcm allocator spinlock_init( &cluster->kcm_lock ); #if DEBUG_CLUSTER_INIT uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_INIT < cycle ) printk("\n[DBG] %s : thread %x enters for cluster %x / cycle %d\n", __FUNCTION__ , CURRENT_THREAD , local_cxy , cycle ); #endif // initialises DQDT cluster->dqdt_root_level = dqdt_init( info->x_max, // [FIXME] info->y_max, // [FIXME] info->y_width ) - 1; // initialises embedded PPM error = hal_ppm_init( info ); if( error ) { printk("\n[ERROR] in %s : cannot initialize PPM in cluster %x\n", __FUNCTION__ , local_cxy ); return ENOMEM; } #if( DEBUG_CLUSTER_INIT & 1 ) cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_INIT < cycle ) printk("\n[DBG] %s : PPM initialized in cluster %x / cycle %d\n", __FUNCTION__ , local_cxy , cycle ); #endif // initialises embedded KHM khm_init( &cluster->khm ); #if( DEBUG_CLUSTER_INIT & 1 ) cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_INIT < cycle ) printk("\n[DBG] %s : KHM initialized in cluster %x at cycle %d\n", __FUNCTION__ , local_cxy , hal_get_cycles() ); #endif // initialises embedded KCM kcm_init( &cluster->kcm , KMEM_KCM ); #if( DEBUG_CLUSTER_INIT & 1 ) cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_INIT < cycle ) printk("\n[DBG] %s : KCM initialized in cluster %x at cycle %d\n", __FUNCTION__ , local_cxy , hal_get_cycles() ); #endif // initialises all cores descriptors for( lid = 0 ; lid < cluster->cores_nr; lid++ ) { core_init( &cluster->core_tbl[lid], // target core descriptor lid, // local core index info->core[lid].gid ); // gid from boot_info_t } #if( DEBUG_CLUSTER_INIT & 1 ) cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_INIT < cycle ) printk("\n[DBG] %s : cores initialized in cluster %x / cycle %d\n", __FUNCTION__ , local_cxy , cycle ); #endif // initialises RPC FIFOs for( lid = 0 ; lid < cluster->cores_nr; lid++ ) { local_fifo_init( &cluster->rpc_fifo[lid] ); cluster->rpc_threads[lid] = 0; } #if( DEBUG_CLUSTER_INIT & 1 ) cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_INIT < cycle ) printk("\n[DBG] %s : RPC fifo inialized in cluster %x at cycle %d\n", __FUNCTION__ , local_cxy , hal_get_cycles() ); #endif // initialise pref_tbl[] in process manager spinlock_init( &cluster->pmgr.pref_lock ); cluster->pmgr.pref_nr = 0; cluster->pmgr.pref_tbl[0] = XPTR( local_cxy , &process_zero ); for( lpid = 1 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ ) { cluster->pmgr.pref_tbl[lpid] = XPTR_NULL; } // initialise local_list in process manager remote_spinlock_init( XPTR( local_cxy , &cluster->pmgr.local_lock ) ); xlist_root_init( XPTR( local_cxy , &cluster->pmgr.local_root ) ); cluster->pmgr.local_nr = 0; // initialise copies_lists in process manager for( lpid = 0 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ ) { remote_spinlock_init( XPTR( local_cxy , &cluster->pmgr.copies_lock[lpid] ) ); cluster->pmgr.copies_nr[lpid] = 0; xlist_root_init( XPTR( local_cxy , &cluster->pmgr.copies_root[lpid] ) ); } #if DEBUG_CLUSTER_INIT cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_INIT < cycle ) printk("\n[DBG] %s , thread %x exit for cluster %x / cycle %d\n", __FUNCTION__ , CURRENT_THREAD , local_cxy , cycle ); #endif hal_fence(); return 0; } // end cluster_init() //////////////////////////////////////// bool_t cluster_is_undefined( cxy_t cxy ) { cluster_t * cluster = LOCAL_CLUSTER; uint32_t y_width = cluster->y_width; uint32_t x = cxy >> y_width; uint32_t y = cxy & ((1<= cluster->x_size ) return true; if( y >= cluster->y_size ) return true; return false; } //////////////////////////////////////////////////////////////////////////////////// // Cores related functions //////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////// lid_t cluster_select_local_core( void ) { uint32_t min = 1000; lid_t sel = 0; uint32_t nthreads; lid_t lid; scheduler_t * sched; cluster_t * cluster = LOCAL_CLUSTER; for( lid = 0 ; lid < cluster->cores_nr ; lid++ ) { sched = &cluster->core_tbl[lid].scheduler; nthreads = sched->u_threads_nr + sched->k_threads_nr; if( nthreads < min ) { min = nthreads; sel = lid; } } return sel; } //////////////////////////////////////////////////////////////////////////////////// // Process related functions //////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////// xptr_t cluster_get_process_from_pid_in_cxy( cxy_t cxy, pid_t pid ) { xptr_t root_xp; // xptr on root of list of processes in owner cluster xptr_t lock_xp; // xptr on lock protecting this list xptr_t iter_xp; // iterator xptr_t current_xp; // xptr on current process descriptor bool_t found; cluster_t * cluster = LOCAL_CLUSTER; // get owner cluster and lpid cxy_t owner_cxy = CXY_FROM_PID( pid ); lpid_t lpid = LPID_FROM_PID( pid ); // get lock & root of list of copies from owner cluster root_xp = XPTR( owner_cxy , &cluster->pmgr.copies_root[lpid] ); lock_xp = XPTR( owner_cxy , &cluster->pmgr.copies_lock[lpid] ); // take the lock protecting the list of processes remote_spinlock_lock( lock_xp ); // scan list of processes found = false; XLIST_FOREACH( root_xp , iter_xp ) { current_xp = XLIST_ELEMENT( iter_xp , process_t , copies_list ); if( GET_CXY( current_xp ) == cxy ) { found = true; break; } } // release the lock protecting the list of processes remote_spinlock_unlock( lock_xp ); // return extended pointer on process descriptor in owner cluster if( found ) return current_xp; else return XPTR_NULL; } // end cluster_get_process_from_pid_in_cxy() ////////////////////////////////////////////////////// xptr_t cluster_get_owner_process_from_pid( pid_t pid ) { xptr_t root_xp; // xptr on root of list of processes in owner cluster xptr_t lock_xp; // xptr on lock protecting this list xptr_t iter_xp; // iterator xptr_t current_xp; // xptr on current process descriptor process_t * current_ptr; // local pointer on current process pid_t current_pid; // current process identifier bool_t found; cluster_t * cluster = LOCAL_CLUSTER; // get owner cluster and lpid cxy_t owner_cxy = CXY_FROM_PID( pid ); // get lock & root of list of process in owner cluster root_xp = XPTR( owner_cxy , &cluster->pmgr.local_root ); lock_xp = XPTR( owner_cxy , &cluster->pmgr.local_lock ); // take the lock protecting the list of processes remote_spinlock_lock( lock_xp ); // scan list of processes in owner cluster found = false; XLIST_FOREACH( root_xp , iter_xp ) { current_xp = XLIST_ELEMENT( iter_xp , process_t , local_list ); current_ptr = GET_PTR( current_xp ); current_pid = hal_remote_lw( XPTR( owner_cxy , ¤t_ptr->pid ) ); if( current_pid == pid ) { found = true; break; } } // release the lock protecting the list of processes remote_spinlock_unlock( lock_xp ); // return extended pointer on process descriptor in owner cluster if( found ) return current_xp; else return XPTR_NULL; } // end cluster_get_owner_process_from_pid() ////////////////////////////////////////////////////////// xptr_t cluster_get_reference_process_from_pid( pid_t pid ) { xptr_t ref_xp; // extended pointer on reference process descriptor cluster_t * cluster = LOCAL_CLUSTER; // get owner cluster and lpid cxy_t owner_cxy = CXY_FROM_PID( pid ); lpid_t lpid = LPID_FROM_PID( pid ); // Check valid PID if( lpid >= CONFIG_MAX_PROCESS_PER_CLUSTER ) return XPTR_NULL; if( local_cxy == owner_cxy ) // local cluster is owner cluster { ref_xp = cluster->pmgr.pref_tbl[lpid]; } else // use a remote_lwd to access owner cluster { ref_xp = (xptr_t)hal_remote_lwd( XPTR( owner_cxy , &cluster->pmgr.pref_tbl[lpid] ) ); } return ref_xp; } /////////////////////////////////////////////// error_t cluster_pid_alloc( process_t * process, pid_t * pid ) { lpid_t lpid; bool_t found; #if DEBUG_CLUSTER_PID_ALLOC uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_PID_ALLOC < cycle ) printk("\n[DBG] %s : thread %x enters in cluster %x / cycle %d\n", __FUNCTION__ , CURRENT_THREAD , local_cxy , cycle ); #endif pmgr_t * pm = &LOCAL_CLUSTER->pmgr; // get the process manager lock spinlock_lock( &pm->pref_lock ); // search an empty slot found = false; for( lpid = 0 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ ) { if( pm->pref_tbl[lpid] == XPTR_NULL ) { found = true; break; } } if( found ) { // register process in pref_tbl[] pm->pref_tbl[lpid] = XPTR( local_cxy , process ); pm->pref_nr++; // returns pid *pid = PID( local_cxy , lpid ); // release the processs_manager lock spinlock_unlock( &pm->pref_lock ); return 0; } else { // release the processs_manager lock spinlock_unlock( &pm->pref_lock ); return -1; } #if DEBUG_CLUSTER_PID_ALLOC cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_PID_ALLOC < cycle ) printk("\n[DBG] %s : thread %x exit in cluster %x / pid %x / cycle %d\n", __FUNCTION__ , CURRENT_THREAD , local_cxy , *pid , cycle ); #endif } // end cluster_pid_alloc() ///////////////////////////////////// void cluster_pid_release( pid_t pid ) { #if DEBUG_CLUSTER_PID_RELEASE uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_PID_RELEASE < cycle ) printk("\n[DBG] %s : thread %x enters in cluster %x / pid %x / cycle %d\n", __FUNCTION__ , CURRENT_THREAD , local_cxy , pid , cycle ); #endif cxy_t owner_cxy = CXY_FROM_PID( pid ); lpid_t lpid = LPID_FROM_PID( pid ); pmgr_t * pm = &LOCAL_CLUSTER->pmgr; // check lpid assert( (lpid < CONFIG_MAX_PROCESS_PER_CLUSTER), "illegal LPID = %d" , lpid ); // check owner cluster assert( (owner_cxy == local_cxy) , "local_cluster %x != owner_cluster %x" , local_cxy , owner_cxy ); // get the process manager lock spinlock_lock( &pm->pref_lock ); // remove process from pref_tbl[] pm->pref_tbl[lpid] = XPTR_NULL; pm->pref_nr--; // release the processs_manager lock spinlock_unlock( &pm->pref_lock ); #if DEBUG_CLUSTER_PID_RELEASE cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_PID_RELEASE < cycle ) printk("\n[DBG] %s : thread %x exit in cluster %x / cycle %d\n", __FUNCTION__ , CURRENT_THREAD , local_cxy , cycle ); #endif } // end cluster_pid_release() /////////////////////////////////////////////////////////// process_t * cluster_get_local_process_from_pid( pid_t pid ) { xptr_t process_xp; process_t * process_ptr; xptr_t root_xp; xptr_t iter_xp; bool_t found; found = false; root_xp = XPTR( local_cxy , &LOCAL_CLUSTER->pmgr.local_root ); XLIST_FOREACH( root_xp , iter_xp ) { process_xp = XLIST_ELEMENT( iter_xp , process_t , local_list ); process_ptr = (process_t *)GET_PTR( process_xp ); if( process_ptr->pid == pid ) { found = true; break; } } if (found ) return process_ptr; else return NULL; } // end cluster_get_local_process_from_pid() ////////////////////////////////////////////////////// void cluster_process_local_link( process_t * process ) { reg_t save_sr; pmgr_t * pm = &LOCAL_CLUSTER->pmgr; // get extended pointers on local process list root & lock xptr_t root_xp = XPTR( local_cxy , &pm->local_root ); xptr_t lock_xp = XPTR( local_cxy , &pm->local_lock ); // get lock protecting the process manager local list remote_spinlock_lock_busy( lock_xp , &save_sr ); // register process in local list xlist_add_last( root_xp , XPTR( local_cxy , &process->local_list ) ); pm->local_nr++; // release lock protecting the process manager local list remote_spinlock_unlock_busy( lock_xp , save_sr ); } //////////////////////////////////////////////////////// void cluster_process_local_unlink( process_t * process ) { reg_t save_sr; pmgr_t * pm = &LOCAL_CLUSTER->pmgr; // get extended pointers on local process list lock xptr_t lock_xp = XPTR( local_cxy , &pm->local_lock ); // get lock protecting the process manager local list remote_spinlock_lock_busy( lock_xp , &save_sr ); // remove process from local list xlist_unlink( XPTR( local_cxy , &process->local_list ) ); pm->local_nr--; // release lock protecting the process manager local list remote_spinlock_unlock_busy( lock_xp , save_sr ); } /////////////////////////////////////////////////////// void cluster_process_copies_link( process_t * process ) { reg_t irq_state; pmgr_t * pm = &LOCAL_CLUSTER->pmgr; #if DEBUG_CLUSTER_PROCESS_COPIES uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_PROCESS_COPIES < cycle ) printk("\n[DBG] %s enters / cluster %x / process %x / cycle %d\n", __FUNCTION__ , local_cxy , process , cycle ); #endif // get owner cluster identifier CXY and process LPID pid_t pid = process->pid; cxy_t owner_cxy = CXY_FROM_PID( pid ); lpid_t lpid = LPID_FROM_PID( pid ); // get extended pointer on lock protecting copies_list[lpid] xptr_t copies_lock = XPTR( owner_cxy , &pm->copies_lock[lpid] ); // get extended pointer on the copies_list[lpid] root xptr_t copies_root = XPTR( owner_cxy , &pm->copies_root[lpid] ); // get extended pointer on the local copies_list entry xptr_t copies_entry = XPTR( local_cxy , &process->copies_list ); // get lock protecting copies_list[lpid] remote_spinlock_lock_busy( copies_lock , &irq_state ); // add copy to copies_list xlist_add_first( copies_root , copies_entry ); hal_remote_atomic_add( XPTR( owner_cxy , &pm->copies_nr[lpid] ) , 1 ); // release lock protecting copies_list[lpid] remote_spinlock_unlock_busy( copies_lock , irq_state ); #if DEBUG_CLUSTER_PROCESS_COPIES cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_PROCESS_COPIES < cycle ) printk("\n[DBG] %s exit / cluster %x / process %x / cycle %d\n", __FUNCTION__ , local_cxy , process , cycle ); #endif } // end cluster_process_copies_link() ///////////////////////////////////////////////////////// void cluster_process_copies_unlink( process_t * process ) { uint32_t irq_state; pmgr_t * pm = &LOCAL_CLUSTER->pmgr; #if DEBUG_CLUSTER_PROCESS_COPIES uint32_t cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_PROCESS_COPIES < cycle ) printk("\n[DBG] %s enters / cluster %x / process %x / cycle %d\n", __FUNCTION__ , local_cxy , process , cycle ); #endif // get owner cluster identifier CXY and process LPID pid_t pid = process->pid; cxy_t owner_cxy = CXY_FROM_PID( pid ); lpid_t lpid = LPID_FROM_PID( pid ); // get extended pointer on lock protecting copies_list[lpid] xptr_t copies_lock = XPTR( owner_cxy , &pm->copies_lock[lpid] ); // get extended pointer on the local copies_list entry xptr_t copies_entry = XPTR( local_cxy , &process->copies_list ); // get lock protecting copies_list[lpid] remote_spinlock_lock_busy( copies_lock , &irq_state ); // remove copy from copies_list xlist_unlink( copies_entry ); hal_remote_atomic_add( XPTR( owner_cxy , &pm->copies_nr[lpid] ) , -1 ); // release lock protecting copies_list[lpid] remote_spinlock_unlock_busy( copies_lock , irq_state ); #if DEBUG_CLUSTER_PROCESS_COPIES cycle = (uint32_t)hal_get_cycles(); if( DEBUG_CLUSTER_PROCESS_COPIES < cycle ) printk("\n[DBG] %s exit / cluster %x / process %x / cycle %d\n", __FUNCTION__ , local_cxy , process , cycle ); #endif } // end cluster_process_copies_unlink() /////////////////////////////////////////// void cluster_processes_display( cxy_t cxy ) { xptr_t root_xp; xptr_t lock_xp; xptr_t iter_xp; xptr_t process_xp; cxy_t txt0_cxy; chdev_t * txt0_ptr; xptr_t txt0_xp; xptr_t txt0_lock_xp; reg_t txt0_save_sr; // save SR to take TXT0 lock in busy mode assert( (cluster_is_undefined( cxy ) == false), "illegal cluster index" ); // get extended pointer on root and lock for local process list in cluster root_xp = XPTR( cxy , &LOCAL_CLUSTER->pmgr.local_root ); lock_xp = XPTR( cxy , &LOCAL_CLUSTER->pmgr.local_lock ); // get pointers on TXT0 chdev txt0_xp = chdev_dir.txt_tx[0]; txt0_cxy = GET_CXY( txt0_xp ); txt0_ptr = GET_PTR( txt0_xp ); // get extended pointer on TXT0 lock txt0_lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock ); // get lock on local process list remote_spinlock_lock( lock_xp ); // get TXT0 lock in busy waiting mode remote_spinlock_lock_busy( txt0_lock_xp , &txt0_save_sr ); // display header nolock_printk("\n***** processes in cluster %x / cycle %d\n", cxy , (uint32_t)hal_get_cycles() ); // loop on all processes in cluster cxy XLIST_FOREACH( root_xp , iter_xp ) { process_xp = XLIST_ELEMENT( iter_xp , process_t , local_list ); process_display( process_xp ); } // release TXT0 lock in busy waiting mode remote_spinlock_unlock_busy( txt0_lock_xp , txt0_save_sr ); // release lock on local process list remote_spinlock_unlock( lock_xp ); } // end cluster_processes_display()