1215976Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3215976Sjmallett * reserved. 4215976Sjmallett * 5215976Sjmallett * 6215976Sjmallett * Redistribution and use in source and binary forms, with or without 7215976Sjmallett * modification, are permitted provided that the following conditions are 8215976Sjmallett * met: 9215976Sjmallett * 10215976Sjmallett * * Redistributions of source code must retain the above copyright 11215976Sjmallett * notice, this list of conditions and the following disclaimer. 12215976Sjmallett * 13215976Sjmallett * * Redistributions in binary form must reproduce the above 14215976Sjmallett * copyright notice, this list of conditions and the following 15215976Sjmallett * disclaimer in the documentation and/or other materials provided 16215976Sjmallett * with the distribution. 17215976Sjmallett 18232812Sjmallett * * Neither the name of Cavium Inc. nor the names of 19215976Sjmallett * its contributors may be used to endorse or promote products 20215976Sjmallett * derived from this software without specific prior written 21215976Sjmallett * permission. 22215976Sjmallett 23215976Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215976Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215976Sjmallett * regulations, and may be subject to export or import regulations in other 26215976Sjmallett * countries. 27215976Sjmallett 28215976Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30215976Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215976Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215976Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215976Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215976Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215976Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215976Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215976Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38215976Sjmallett ***********************license end**************************************/ 39215976Sjmallett 40215976Sjmallett/** 41215976Sjmallett * @file 42215976Sjmallett * 43215976Sjmallett * Provides APIs for applications to register for hotplug. It also provides 44215976Sjmallett * APIs for requesting shutdown of a running target application. 45215976Sjmallett * 46215976Sjmallett * <hr>$Revision: $<hr> 47215976Sjmallett */ 48215976Sjmallett 49215976Sjmallett#include "cvmx-app-hotplug.h" 50215976Sjmallett#include "cvmx-spinlock.h" 51232812Sjmallett#include "cvmx-debug.h" 52215976Sjmallett 53215976Sjmallett//#define DEBUG 1 54215976Sjmallett 55232812Sjmallettstatic cvmx_app_hotplug_global_t *hotplug_global_ptr = 0; 56232812Sjmallett 57215976Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_USER 58215976Sjmallett 59215976Sjmallettstatic CVMX_SHARED cvmx_spinlock_t cvmx_app_hotplug_sync_lock = { CVMX_SPINLOCK_UNLOCKED_VAL }; 60215976Sjmallettstatic CVMX_SHARED cvmx_spinlock_t cvmx_app_hotplug_lock = { CVMX_SPINLOCK_UNLOCKED_VAL }; 61215976Sjmallettstatic CVMX_SHARED cvmx_app_hotplug_info_t *cvmx_app_hotplug_info_ptr = NULL; 62215976Sjmallett 63215976Sjmallettstatic void __cvmx_app_hotplug_shutdown(int irq_number, uint64_t registers[32], void *user_arg); 64215976Sjmallettstatic void __cvmx_app_hotplug_sync(void); 65215976Sjmallettstatic void __cvmx_app_hotplug_reset(void); 66215976Sjmallett 67232812Sjmallett/* Declaring this array here is a compile time check to ensure that the 68232812Sjmallett size of cvmx_app_hotplug_info_t is 1024. If the size is not 1024 69232812Sjmallett the size of the array will be -1 and this results in a compilation 70232812Sjmallett error */ 71232812Sjmallettchar __hotplug_info_check[(sizeof(cvmx_app_hotplug_info_t) == 1024) ? 1 : -1]; 72215976Sjmallett/** 73215976Sjmallett * This routine registers an application for hotplug. It installs a handler for 74215976Sjmallett * any incoming shutdown request. It also registers a callback routine from the 75215976Sjmallett * application. This callback is invoked when the application receives a 76215976Sjmallett * shutdown notification. 77215976Sjmallett * 78215976Sjmallett * This routine only needs to be called once per application. 79215976Sjmallett * 80215976Sjmallett * @param fn Callback routine from the application. 81215976Sjmallett * @param arg Argument to the application callback routine. 82215976Sjmallett * @return Return 0 on success, -1 on failure 83215976Sjmallett * 84215976Sjmallett */ 85215976Sjmallettint cvmx_app_hotplug_register(void(*fn)(void*), void* arg) 86215976Sjmallett{ 87215976Sjmallett /* Find the list of applications launched by bootoct utility. */ 88215976Sjmallett 89215976Sjmallett if (!(cvmx_app_hotplug_info_ptr = cvmx_app_hotplug_get_info(cvmx_sysinfo_get()->core_mask))) 90215976Sjmallett { 91215976Sjmallett /* Application not launched by bootoct? */ 92215976Sjmallett printf("ERROR: cmvx_app_hotplug_register() failed\n"); 93215976Sjmallett return -1; 94215976Sjmallett } 95215976Sjmallett 96215976Sjmallett /* Register the callback */ 97215976Sjmallett cvmx_app_hotplug_info_ptr->data = CAST64(arg); 98215976Sjmallett cvmx_app_hotplug_info_ptr->shutdown_callback = CAST64(fn); 99215976Sjmallett 100215976Sjmallett#ifdef DEBUG 101232812Sjmallett printf("cvmx_app_hotplug_register(): coremask 0x%x valid %d\n", 102215976Sjmallett cvmx_app_hotplug_info_ptr->coremask, cvmx_app_hotplug_info_ptr->valid); 103215976Sjmallett#endif 104215976Sjmallett 105215976Sjmallett cvmx_interrupt_register(CVMX_IRQ_MBOX0, __cvmx_app_hotplug_shutdown, NULL); 106215976Sjmallett 107215976Sjmallett return 0; 108215976Sjmallett} 109215976Sjmallett 110215976Sjmallett/** 111232812Sjmallett * This routine deprecates the the cvmx_app_hotplug_register method. This 112232812Sjmallett * registers application for hotplug and the application will have CPU 113232812Sjmallett * hotplug callbacks. Various callbacks are specified in cb. 114232812Sjmallett * cvmx_app_hotplug_callbacks_t documents the callbacks 115215976Sjmallett * 116232812Sjmallett * This routine only needs to be called once per application. 117232812Sjmallett * 118232812Sjmallett * @param cb Callback routine from the application. 119232812Sjmallett * @param arg Argument to the application callback routins 120232812Sjmallett * @param app_shutdown When set to 1 the application will invoke core_shutdown 121232812Sjmallett on each core. When set to 0 core shutdown will be 122232812Sjmallett called invoked automatically after invoking the 123232812Sjmallett application callback. 124232812Sjmallett * @return Return index of app on success, -1 on failure 125232812Sjmallett * 126232812Sjmallett */ 127232812Sjmallettint cvmx_app_hotplug_register_cb(cvmx_app_hotplug_callbacks_t *cb, void* arg, 128232812Sjmallett int app_shutdown) 129232812Sjmallett{ 130232812Sjmallett cvmx_app_hotplug_info_t *app_info; 131232812Sjmallett 132232812Sjmallett /* Find the list of applications launched by bootoct utility. */ 133232812Sjmallett app_info = cvmx_app_hotplug_get_info(cvmx_sysinfo_get()->core_mask); 134232812Sjmallett cvmx_app_hotplug_info_ptr = app_info; 135232812Sjmallett if (!app_info) 136232812Sjmallett { 137232812Sjmallett /* Application not launched by bootoct? */ 138232812Sjmallett printf("ERROR: cmvx_app_hotplug_register() failed\n"); 139232812Sjmallett return -1; 140232812Sjmallett } 141232812Sjmallett /* Register the callback */ 142232812Sjmallett app_info->data = CAST64(arg); 143232812Sjmallett app_info->shutdown_callback = CAST64(cb->shutdown_callback); 144232812Sjmallett app_info->cores_added_callback = CAST64(cb->cores_added_callback); 145232812Sjmallett app_info->cores_removed_callback = CAST64(cb->cores_removed_callback); 146232812Sjmallett app_info->unplug_callback = CAST64(cb->unplug_core_callback); 147232812Sjmallett app_info->hotplug_start = CAST64(cb->hotplug_start); 148232812Sjmallett app_info->app_shutdown = app_shutdown; 149232812Sjmallett#ifdef DEBUG 150232812Sjmallett printf("cvmx_app_hotplug_register(): coremask 0x%x valid %d\n", 151232812Sjmallett app_info->coremask, app_info->valid); 152232812Sjmallett#endif 153232812Sjmallett 154232812Sjmallett cvmx_interrupt_register(CVMX_IRQ_MBOX0, __cvmx_app_hotplug_shutdown, NULL); 155232812Sjmallett return 0; 156232812Sjmallett 157232812Sjmallett} 158232812Sjmallett 159232812Sjmallettvoid cvmx_app_hotplug_remove_self_from_core_mask(void) 160232812Sjmallett{ 161232812Sjmallett int core = cvmx_get_core_num(); 162232812Sjmallett uint32_t core_mask = 1ull << core; 163232812Sjmallett 164232812Sjmallett cvmx_spinlock_lock(&cvmx_app_hotplug_lock); 165232812Sjmallett cvmx_app_hotplug_info_ptr->coremask = cvmx_app_hotplug_info_ptr->coremask & ~core_mask ; 166232812Sjmallett cvmx_app_hotplug_info_ptr->hotplug_activated_coremask = 167232812Sjmallett cvmx_app_hotplug_info_ptr->hotplug_activated_coremask & ~core_mask ; 168232812Sjmallett cvmx_spinlock_unlock(&cvmx_app_hotplug_lock); 169232812Sjmallett} 170232812Sjmallett 171232812Sjmallett 172232812Sjmallett 173232812Sjmallett/** 174232812Sjmallett* Returns 1 if the running core is being unplugged, else it returns 0. 175232812Sjmallett*/ 176232812Sjmallettint is_core_being_unplugged(void) 177232812Sjmallett{ 178232812Sjmallett if (cvmx_app_hotplug_info_ptr->unplug_cores & 179232812Sjmallett (1ull << cvmx_get_core_num())) 180232812Sjmallett return 1; 181232812Sjmallett return 0; 182232812Sjmallett} 183232812Sjmallett 184232812Sjmallett 185232812Sjmallett/** 186232812Sjmallett * Activate the current application core for receiving hotplug shutdown requests. 187232812Sjmallett * 188215976Sjmallett * This routine makes sure that each core belonging to the application is enabled 189215976Sjmallett * to receive the shutdown notification and also provides a barrier sync to make 190215976Sjmallett * sure that all cores are ready. 191215976Sjmallett */ 192215976Sjmallettint cvmx_app_hotplug_activate(void) 193215976Sjmallett{ 194232812Sjmallett uint64_t cnt = 0; 195232812Sjmallett uint64_t cnt_interval = 10000000; 196215976Sjmallett 197232812Sjmallett while (!cvmx_app_hotplug_info_ptr) 198232812Sjmallett { 199232812Sjmallett cnt++; 200232812Sjmallett if ((cnt % cnt_interval) == 0) 201232812Sjmallett printf("waiting for cnt=%lld\n", (unsigned long long)cnt); 202232812Sjmallett } 203232812Sjmallett 204232812Sjmallett if (cvmx_app_hotplug_info_ptr->hplugged_cores & (1ull << cvmx_get_core_num())) 205232812Sjmallett { 206232812Sjmallett#ifdef DEBUG 207232812Sjmallett printf("core=%d : is being hotplugged \n", cvmx_get_core_num()); 208232812Sjmallett#endif 209232812Sjmallett cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get(); 210232812Sjmallett sys_info_ptr->core_mask |= 1ull << cvmx_get_core_num(); 211232812Sjmallett } 212232812Sjmallett else 213232812Sjmallett { 214232812Sjmallett __cvmx_app_hotplug_sync(); 215232812Sjmallett } 216215976Sjmallett cvmx_spinlock_lock(&cvmx_app_hotplug_lock); 217215976Sjmallett if (!cvmx_app_hotplug_info_ptr) 218215976Sjmallett { 219215976Sjmallett cvmx_spinlock_unlock(&cvmx_app_hotplug_lock); 220215976Sjmallett printf("ERROR: This application is not registered for hotplug\n"); 221232812Sjmallett return -1; 222215976Sjmallett } 223215976Sjmallett /* Enable the interrupt before we mark the core as activated */ 224215976Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0); 225232812Sjmallett cvmx_app_hotplug_info_ptr->hotplug_activated_coremask |= (1ull<<cvmx_get_core_num()); 226215976Sjmallett 227215976Sjmallett#ifdef DEBUG 228232812Sjmallett printf("cvmx_app_hotplug_activate(): coremask 0x%x valid %d sizeof %d\n", 229215976Sjmallett cvmx_app_hotplug_info_ptr->coremask, cvmx_app_hotplug_info_ptr->valid, 230215976Sjmallett sizeof(*cvmx_app_hotplug_info_ptr)); 231215976Sjmallett#endif 232215976Sjmallett 233215976Sjmallett cvmx_spinlock_unlock(&cvmx_app_hotplug_lock); 234215976Sjmallett 235215976Sjmallett return 0; 236215976Sjmallett} 237215976Sjmallett 238215976Sjmallett/** 239215976Sjmallett * This routine is only required if cvmx_app_hotplug_shutdown_request() was called 240215976Sjmallett * with wait=0. This routine waits for the application shutdown to complete. 241215976Sjmallett * 242215976Sjmallett * @param coremask Coremask the application is running on. 243215976Sjmallett * @return 0 on success, -1 on error 244215976Sjmallett * 245215976Sjmallett */ 246215976Sjmallettint cvmx_app_hotplug_shutdown_complete(uint32_t coremask) 247215976Sjmallett{ 248215976Sjmallett cvmx_app_hotplug_info_t *hotplug_info_ptr; 249215976Sjmallett 250215976Sjmallett if (!(hotplug_info_ptr = cvmx_app_hotplug_get_info(coremask))) 251215976Sjmallett { 252215976Sjmallett printf("\nERROR: Failed to get hotplug info for coremask: 0x%x\n", (unsigned int)coremask); 253215976Sjmallett return -1; 254215976Sjmallett } 255215976Sjmallett 256215976Sjmallett while(!hotplug_info_ptr->shutdown_done); 257215976Sjmallett 258215976Sjmallett /* Clean up the hotplug info region for this app */ 259215976Sjmallett bzero(hotplug_info_ptr, sizeof(*hotplug_info_ptr)); 260215976Sjmallett 261215976Sjmallett return 0; 262215976Sjmallett} 263215976Sjmallett 264215976Sjmallett/** 265215976Sjmallett * Disable recognition of any incoming shutdown request. 266215976Sjmallett */ 267215976Sjmallett 268215976Sjmallettvoid cvmx_app_hotplug_shutdown_disable(void) 269215976Sjmallett{ 270215976Sjmallett cvmx_interrupt_mask_irq(CVMX_IRQ_MBOX0); 271215976Sjmallett} 272215976Sjmallett 273215976Sjmallett/** 274215976Sjmallett * Re-enable recognition of incoming shutdown requests. 275215976Sjmallett */ 276215976Sjmallett 277215976Sjmallettvoid cvmx_app_hotplug_shutdown_enable(void) 278215976Sjmallett{ 279215976Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0); 280215976Sjmallett} 281215976Sjmallett 282232812Sjmallett/** 283232812Sjmallett* Request shutdown of the currently running core. Should be 284232812Sjmallett* called by the application when it has been registered with 285232812Sjmallett* app_shutdown option set to 1. 286232812Sjmallett*/ 287232812Sjmallettvoid cvmx_app_hotplug_core_shutdown(void) 288232812Sjmallett{ 289232812Sjmallett uint32_t flags; 290232812Sjmallett if (cvmx_app_hotplug_info_ptr->shutdown_cores) 291232812Sjmallett { 292232812Sjmallett cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get(); 293232812Sjmallett __cvmx_app_hotplug_sync(); 294232812Sjmallett if (cvmx_coremask_first_core(sys_info_ptr->core_mask)) 295232812Sjmallett { 296232812Sjmallett bzero(cvmx_app_hotplug_info_ptr, 297232812Sjmallett sizeof(*cvmx_app_hotplug_info_ptr)); 298232812Sjmallett #ifdef DEBUG 299232812Sjmallett printf("__cvmx_app_hotplug_shutdown(): setting shutdown done! \n"); 300232812Sjmallett #endif 301232812Sjmallett cvmx_app_hotplug_info_ptr->shutdown_done = 1; 302232812Sjmallett } 303232812Sjmallett /* Tell the debugger that this application is finishing. */ 304232812Sjmallett cvmx_debug_finish (); 305232812Sjmallett flags = cvmx_interrupt_disable_save(); 306232812Sjmallett __cvmx_app_hotplug_sync(); 307232812Sjmallett /* Reset the core */ 308232812Sjmallett __cvmx_app_hotplug_reset(); 309232812Sjmallett } 310232812Sjmallett else 311232812Sjmallett { 312232812Sjmallett cvmx_sysinfo_remove_self_from_core_mask(); 313232812Sjmallett cvmx_app_hotplug_remove_self_from_core_mask(); 314232812Sjmallett flags = cvmx_interrupt_disable_save(); 315232812Sjmallett __cvmx_app_hotplug_reset(); 316232812Sjmallett } 317232812Sjmallett} 318232812Sjmallett 319215976Sjmallett/* 320232812Sjmallett * ISR for the incoming shutdown request interrupt. 321215976Sjmallett */ 322232812Sjmallettstatic void __cvmx_app_hotplug_shutdown(int irq_number, uint64_t registers[32], 323232812Sjmallett void *user_arg) 324215976Sjmallett{ 325215976Sjmallett cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get(); 326232812Sjmallett uint64_t mbox; 327232812Sjmallett cvmx_app_hotplug_info_t *ai = cvmx_app_hotplug_info_ptr; 328232812Sjmallett int dbg = 0; 329215976Sjmallett 330232812Sjmallett#ifdef DEBUG 331232812Sjmallett dbg = 1; 332232812Sjmallett#endif 333215976Sjmallett cvmx_interrupt_mask_irq(CVMX_IRQ_MBOX0); 334215976Sjmallett 335232812Sjmallett mbox = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num())); 336215976Sjmallett /* Clear the interrupt */ 337232812Sjmallett cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), mbox); 338215976Sjmallett 339215976Sjmallett /* Make sure the write above completes */ 340215976Sjmallett cvmx_read_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num())); 341215976Sjmallett 342232812Sjmallett 343215976Sjmallett if (!cvmx_app_hotplug_info_ptr) 344215976Sjmallett { 345215976Sjmallett printf("ERROR: Application is not registered for hotplug!\n"); 346215976Sjmallett return; 347215976Sjmallett } 348215976Sjmallett 349232812Sjmallett if (ai->hotplug_activated_coremask != sys_info_ptr->core_mask) 350215976Sjmallett { 351232812Sjmallett printf("ERROR: Shutdown requested when not all app cores have " 352232812Sjmallett "activated hotplug\n" "Application coremask: 0x%x Hotplug " 353232812Sjmallett "coremask: 0x%x\n", (unsigned int)sys_info_ptr->core_mask, 354232812Sjmallett (unsigned int)ai->hotplug_activated_coremask); 355232812Sjmallett return; 356215976Sjmallett } 357215976Sjmallett 358232812Sjmallett if (mbox & 1ull) 359232812Sjmallett { 360232812Sjmallett int core = cvmx_get_core_num(); 361232812Sjmallett if (dbg) 362232812Sjmallett printf("Shutting down application .\n"); 363232812Sjmallett /* Call the application's own callback function */ 364232812Sjmallett if (ai->shutdown_callback) 365232812Sjmallett { 366232812Sjmallett ((void(*)(void*))(long)ai->shutdown_callback)(CASTPTR(void *, ai->data)); 367232812Sjmallett } 368232812Sjmallett else 369232812Sjmallett { 370232812Sjmallett printf("ERROR : Shutdown callback has not been registered\n"); 371232812Sjmallett } 372232812Sjmallett if (!ai->app_shutdown) 373232812Sjmallett { 374232812Sjmallett if (dbg) 375232812Sjmallett printf("%s : core = %d Invoking app shutdown\n", __FUNCTION__, core); 376232812Sjmallett cvmx_app_hotplug_core_shutdown(); 377232812Sjmallett } 378232812Sjmallett } 379232812Sjmallett else if (mbox & 2ull) 380232812Sjmallett { 381232812Sjmallett int core = cvmx_get_core_num(); 382232812Sjmallett int unplug = is_core_being_unplugged(); 383232812Sjmallett if (dbg) printf("%s : core=%d Unplug event \n", __FUNCTION__, core); 384215976Sjmallett 385232812Sjmallett if (unplug) 386232812Sjmallett { 387232812Sjmallett /* Call the application's own callback function */ 388232812Sjmallett if (ai->unplug_callback) 389232812Sjmallett { 390232812Sjmallett if (dbg) printf("%s : core=%d Calling unplug callback\n", 391232812Sjmallett __FUNCTION__, core); 392232812Sjmallett ((void(*)(void*))(long)ai->unplug_callback)(CASTPTR(void *, 393232812Sjmallett ai->data)); 394232812Sjmallett } 395232812Sjmallett if (!ai->app_shutdown) 396232812Sjmallett { 397232812Sjmallett if (dbg) printf("%s : core = %d Invoking app shutdown\n", 398232812Sjmallett __FUNCTION__, core); 399232812Sjmallett cvmx_app_hotplug_core_shutdown(); 400232812Sjmallett } 401232812Sjmallett } 402232812Sjmallett else 403232812Sjmallett { 404232812Sjmallett if (ai->cores_removed_callback) 405232812Sjmallett { 406232812Sjmallett if (dbg) printf("%s : core=%d Calling cores removed callback\n", 407232812Sjmallett __FUNCTION__, core); 408232812Sjmallett ((void(*)(uint32_t, void*))(long)ai->cores_removed_callback) 409232812Sjmallett (ai->unplug_cores, CASTPTR(void *, ai->data)); 410232812Sjmallett } 411232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0); 412232812Sjmallett } 413232812Sjmallett } 414232812Sjmallett else if (mbox & 4ull) 415232812Sjmallett { 416232812Sjmallett int core = cvmx_get_core_num(); 417232812Sjmallett if (dbg) printf("%s : core=%d Add cores event \n", __FUNCTION__, core); 418215976Sjmallett 419232812Sjmallett if (ai->cores_added_callback) 420232812Sjmallett { 421232812Sjmallett if (dbg) printf("%s : core=%d Calling cores added callback\n", 422232812Sjmallett __FUNCTION__, core); 423232812Sjmallett ((void(*)(uint32_t, void*))(long)ai->cores_added_callback) 424232812Sjmallett (ai->hplugged_cores, CASTPTR(void *, ai->data)); 425232812Sjmallett } 426232812Sjmallett cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0); 427232812Sjmallett } 428232812Sjmallett else 429215976Sjmallett { 430232812Sjmallett printf("ERROR: unexpected mbox=%llx\n", (unsigned long long)mbox); 431215976Sjmallett } 432215976Sjmallett 433215976Sjmallett} 434215976Sjmallett 435215976Sjmallettvoid __cvmx_app_hotplug_reset(void) 436215976Sjmallett{ 437232812Sjmallett#define IDLE_CORE_BLOCK_NAME "idle-core-loop" 438232812Sjmallett#define HPLUG_MAKE_XKPHYS(x) ((1ULL << 63) | (x)) 439232812Sjmallett uint64_t reset_addr; 440232812Sjmallett const cvmx_bootmem_named_block_desc_t *block_desc; 441232812Sjmallett 442232812Sjmallett block_desc = cvmx_bootmem_find_named_block(IDLE_CORE_BLOCK_NAME); 443232812Sjmallett if (!block_desc) { 444232812Sjmallett cvmx_dprintf("Named block(%s) is not created\n", IDLE_CORE_BLOCK_NAME); 445232812Sjmallett /* loop here, should not happen */ 446232812Sjmallett __asm__ volatile ( 447232812Sjmallett ".set noreorder \n" 448232812Sjmallett "\tsync \n" 449232812Sjmallett "\tnop \n" 450232812Sjmallett "1:\twait \n" 451232812Sjmallett "\tb 1b \n" 452232812Sjmallett "\tnop \n" 453232812Sjmallett ".set reorder \n" 454232812Sjmallett :: 455232812Sjmallett ); 456232812Sjmallett } 457232812Sjmallett 458232812Sjmallett reset_addr = HPLUG_MAKE_XKPHYS(block_desc->base_addr); 459232812Sjmallett asm volatile (" .set push \n" 460232812Sjmallett " .set mips64 \n" 461232812Sjmallett " .set noreorder \n" 462232812Sjmallett " move $2, %[addr] \n" 463232812Sjmallett " jr $2 \n" 464232812Sjmallett " nop \n" 465232812Sjmallett " .set pop " 466232812Sjmallett :: [addr] "r"(reset_addr) 467232812Sjmallett : "$2"); 468232812Sjmallett 469232812Sjmallett /*Should never reach here*/ 470232812Sjmallett while (1) ; 471232812Sjmallett 472215976Sjmallett} 473215976Sjmallett 474215976Sjmallett/* 475215976Sjmallett * We need a separate sync operation from cvmx_coremask_barrier_sync() to 476215976Sjmallett * avoid a deadlock on state.lock, since the application itself maybe doing a 477215976Sjmallett * cvmx_coremask_barrier_sync(). 478215976Sjmallett */ 479215976Sjmallettstatic void __cvmx_app_hotplug_sync(void) 480215976Sjmallett{ 481215976Sjmallett static CVMX_SHARED volatile uint32_t sync_coremask = 0; 482215976Sjmallett cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get(); 483215976Sjmallett 484215976Sjmallett cvmx_spinlock_lock(&cvmx_app_hotplug_sync_lock); 485215976Sjmallett 486215976Sjmallett sync_coremask |= cvmx_coremask_core(cvmx_get_core_num()); 487215976Sjmallett 488215976Sjmallett cvmx_spinlock_unlock(&cvmx_app_hotplug_sync_lock); 489215976Sjmallett 490215976Sjmallett while (sync_coremask != sys_info_ptr->core_mask); 491232812Sjmallett 492232812Sjmallett cvmx_spinlock_lock(&cvmx_app_hotplug_sync_lock); 493232812Sjmallett sync_coremask = 0; 494232812Sjmallett cvmx_spinlock_unlock(&cvmx_app_hotplug_sync_lock); 495232812Sjmallett 496232812Sjmallett 497215976Sjmallett} 498215976Sjmallett 499215976Sjmallett#endif /* CVMX_BUILD_FOR_LINUX_USER */ 500215976Sjmallett 501215976Sjmallett/** 502232812Sjmallett* Returns 1 if the running core is being hotplugged, else it returns 0. 503232812Sjmallett*/ 504232812Sjmallettint is_core_being_hot_plugged(void) 505215976Sjmallett{ 506232812Sjmallett 507232812Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_USER 508232812Sjmallett if (!cvmx_app_hotplug_info_ptr) return 0; 509232812Sjmallett if (cvmx_app_hotplug_info_ptr->hplugged_cores & 510232812Sjmallett (1ull << cvmx_get_core_num())) 511232812Sjmallett return 1; 512232812Sjmallett return 0; 513232812Sjmallett#else 514232812Sjmallett return 0; 515232812Sjmallett#endif 516232812Sjmallett} 517232812Sjmallett 518232812Sjmallettstatic cvmx_app_hotplug_global_t *cvmx_app_get_hotplug_global_ptr(void) 519232812Sjmallett{ 520215976Sjmallett const struct cvmx_bootmem_named_block_desc *block_desc; 521215976Sjmallett cvmx_app_hotplug_global_t *hgp; 522215976Sjmallett 523232812Sjmallett if(hotplug_global_ptr != 0) return hotplug_global_ptr; 524232812Sjmallett 525215976Sjmallett block_desc = cvmx_bootmem_find_named_block(CVMX_APP_HOTPLUG_INFO_REGION_NAME); 526215976Sjmallett if (!block_desc) 527215976Sjmallett { 528215976Sjmallett printf("ERROR: Hotplug info region is not setup\n"); 529215976Sjmallett return NULL; 530215976Sjmallett } 531215976Sjmallett else 532215976Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_USER 533215976Sjmallett { 534215976Sjmallett size_t pg_sz = sysconf(_SC_PAGESIZE), size; 535215976Sjmallett off_t offset; 536215976Sjmallett char *vaddr; 537215976Sjmallett int fd; 538215976Sjmallett 539215976Sjmallett if ((fd = open("/dev/mem", O_RDWR)) == -1) { 540215976Sjmallett perror("open"); 541215976Sjmallett return NULL; 542215976Sjmallett } 543215976Sjmallett 544215976Sjmallett /* 545215976Sjmallett * We need to mmap() this memory, since this was allocated from the 546215976Sjmallett * kernel bootup code and does not reside in the RESERVE32 region. 547215976Sjmallett */ 548215976Sjmallett size = CVMX_APP_HOTPLUG_INFO_REGION_SIZE + pg_sz-1; 549215976Sjmallett offset = block_desc->base_addr & ~(pg_sz-1); 550232812Sjmallett if ((vaddr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset)) 551232812Sjmallett == MAP_FAILED) 552215976Sjmallett { 553215976Sjmallett perror("mmap"); 554215976Sjmallett return NULL; 555215976Sjmallett } 556215976Sjmallett 557215976Sjmallett hgp = (cvmx_app_hotplug_global_t *)(vaddr + ( block_desc->base_addr & (pg_sz-1))); 558215976Sjmallett } 559215976Sjmallett#else 560232812Sjmallett hgp = CASTPTR(void, CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, block_desc->base_addr)); 561215976Sjmallett#endif 562232812Sjmallett hotplug_global_ptr = hgp; 563232812Sjmallett return hgp; 564215976Sjmallett 565232812Sjmallett} 566215976Sjmallett 567232812Sjmallett/** 568232812Sjmallett * Return the hotplug info structure (cvmx_app_hotplug_info_t) pointer for the 569232812Sjmallett * application running on the given coremask. 570232812Sjmallett * 571232812Sjmallett * @param coremask Coremask of application. 572232812Sjmallett * @return Returns hotplug info struct on success, NULL on failure 573232812Sjmallett * 574232812Sjmallett */ 575232812Sjmallettcvmx_app_hotplug_info_t* cvmx_app_hotplug_get_info(uint32_t coremask) 576232812Sjmallett{ 577232812Sjmallett cvmx_app_hotplug_info_t *hip; 578232812Sjmallett cvmx_app_hotplug_global_t *hgp; 579232812Sjmallett int i; 580232812Sjmallett int dbg = 0; 581232812Sjmallett 582215976Sjmallett#ifdef DEBUG 583232812Sjmallett dbg = 1; 584215976Sjmallett#endif 585232812Sjmallett hgp = cvmx_app_get_hotplug_global_ptr(); 586232812Sjmallett if (!hgp) return NULL; 587232812Sjmallett hip = hgp->hotplug_info_array; 588215976Sjmallett 589215976Sjmallett /* Look for the current app's info */ 590215976Sjmallett for (i=0; i<CVMX_APP_HOTPLUG_MAX_APPS; i++) 591215976Sjmallett { 592215976Sjmallett if (hip[i].coremask == coremask) 593232812Sjmallett { 594232812Sjmallett if (dbg) 595232812Sjmallett printf("cvmx_app_hotplug_get_info(): coremask match %d -- coremask 0x%x, valid %d\n", i, (unsigned int)hip[i].coremask, (unsigned int)hip[i].valid); 596232812Sjmallett return &hip[i]; 597232812Sjmallett } 598232812Sjmallett } 599232812Sjmallett return NULL; 600232812Sjmallett} 601232812Sjmallett 602232812Sjmallett/** 603232812Sjmallett * Return the hotplug application index structure for the application running on the 604232812Sjmallett * given coremask. 605232812Sjmallett * 606232812Sjmallett * @param coremask Coremask of application. 607232812Sjmallett * @return Returns hotplug application index on success. -1 on failure 608232812Sjmallett * 609232812Sjmallett */ 610232812Sjmallettint cvmx_app_hotplug_get_index(uint32_t coremask) 611232812Sjmallett{ 612232812Sjmallett cvmx_app_hotplug_info_t *hip; 613232812Sjmallett cvmx_app_hotplug_global_t *hgp; 614232812Sjmallett int i; 615232812Sjmallett int dbg = 0; 616232812Sjmallett 617215976Sjmallett#ifdef DEBUG 618232812Sjmallett dbg = 1; 619215976Sjmallett#endif 620232812Sjmallett hgp = cvmx_app_get_hotplug_global_ptr(); 621232812Sjmallett if (!hgp) return -1; 622232812Sjmallett hip = hgp->hotplug_info_array; 623215976Sjmallett 624232812Sjmallett /* Look for the current app's info */ 625232812Sjmallett for (i=0; i<CVMX_APP_HOTPLUG_MAX_APPS; i++) 626232812Sjmallett { 627232812Sjmallett if (hip[i].coremask == coremask) 628232812Sjmallett { 629232812Sjmallett if (dbg) 630232812Sjmallett printf("cvmx_app_hotplug_get_info(): coremask match %d -- coremask 0x%x valid %d\n", i, (unsigned int)hip[i].coremask, (unsigned int)hip[i].valid); 631232812Sjmallett return i; 632232812Sjmallett } 633215976Sjmallett } 634232812Sjmallett return -1; 635232812Sjmallett} 636215976Sjmallett 637232812Sjmallettvoid print_hot_plug_info(cvmx_app_hotplug_info_t* hpinfo) 638232812Sjmallett{ 639232812Sjmallett printf("name=%s coremask=%08x hotplugged coremask=%08x valid=%d\n", hpinfo->app_name, 640232812Sjmallett (unsigned int)hpinfo->coremask, (unsigned int)hpinfo->hotplug_activated_coremask, (unsigned int)hpinfo->valid); 641232812Sjmallett} 642232812Sjmallett 643232812Sjmallett/** 644232812Sjmallett * Return the hotplug info structure (cvmx_app_hotplug_info_t) pointer for the 645232812Sjmallett * application with the specified index. 646232812Sjmallett * 647232812Sjmallett * @param index index of application. 648232812Sjmallett * @return Returns hotplug info struct on success, NULL on failure 649232812Sjmallett * 650232812Sjmallett */ 651232812Sjmallettcvmx_app_hotplug_info_t* cvmx_app_hotplug_get_info_at_index(int index) 652232812Sjmallett{ 653232812Sjmallett cvmx_app_hotplug_info_t *hip; 654232812Sjmallett cvmx_app_hotplug_global_t *hgp; 655232812Sjmallett 656232812Sjmallett hgp = cvmx_app_get_hotplug_global_ptr(); 657232812Sjmallett if (!hgp) return NULL; 658232812Sjmallett hip = hgp->hotplug_info_array; 659232812Sjmallett 660232812Sjmallett#ifdef DEBUG 661232812Sjmallett printf("cvmx_app_hotplug_get_info(): hotplug_info phy addr 0x%llx ptr %p\n", 662232812Sjmallett block_desc->base_addr, hgp); 663232812Sjmallett#endif 664232812Sjmallett if (index < CVMX_APP_HOTPLUG_MAX_APPS) 665232812Sjmallett { 666232812Sjmallett if (hip[index].valid) 667232812Sjmallett { 668232812Sjmallett //print_hot_plug_info( &hip[index] ); 669232812Sjmallett return &hip[index]; 670232812Sjmallett } 671232812Sjmallett } 672215976Sjmallett return NULL; 673215976Sjmallett} 674215976Sjmallett 675215976Sjmallett/** 676232812Sjmallett * Determines if SE application at the index specified is hotpluggable. 677232812Sjmallett * 678232812Sjmallett * @param index index of application. 679232812Sjmallett * @return Returns -1 on error. 680232812Sjmallett * 0 -> The application is not hotpluggable 681232812Sjmallett * 1 -> The application is hotpluggable 682232812Sjmallett*/ 683232812Sjmallettint is_app_hotpluggable(int index) 684232812Sjmallett{ 685232812Sjmallett cvmx_app_hotplug_info_t *ai; 686232812Sjmallett 687232812Sjmallett if (!(ai = cvmx_app_hotplug_get_info_at_index(index))) 688232812Sjmallett { 689232812Sjmallett printf("\nERROR: Failed to get hotplug info for app at index=%d\n", index); 690232812Sjmallett return -1; 691232812Sjmallett } 692232812Sjmallett if (ai->hotplug_activated_coremask) return 1; 693232812Sjmallett return 0; 694232812Sjmallett} 695232812Sjmallett 696232812Sjmallett/** 697215976Sjmallett * This routine sends a shutdown request to a running target application. 698215976Sjmallett * 699215976Sjmallett * @param coremask Coremask the application is running on. 700215976Sjmallett * @param wait 1 - Wait for shutdown completion 701215976Sjmallett * 0 - Do not wait 702215976Sjmallett * @return 0 on success, -1 on error 703215976Sjmallett * 704215976Sjmallett */ 705215976Sjmallett 706215976Sjmallettint cvmx_app_hotplug_shutdown_request(uint32_t coremask, int wait) 707215976Sjmallett{ 708215976Sjmallett int i; 709215976Sjmallett cvmx_app_hotplug_info_t *hotplug_info_ptr; 710215976Sjmallett 711215976Sjmallett if (!(hotplug_info_ptr = cvmx_app_hotplug_get_info(coremask))) 712215976Sjmallett { 713215976Sjmallett printf("\nERROR: Failed to get hotplug info for coremask: 0x%x\n", (unsigned int)coremask); 714215976Sjmallett return -1; 715215976Sjmallett } 716232812Sjmallett hotplug_info_ptr->shutdown_cores = coremask; 717215976Sjmallett if (!hotplug_info_ptr->shutdown_callback) 718215976Sjmallett { 719215976Sjmallett printf("\nERROR: Target application has not registered for hotplug!\n"); 720215976Sjmallett return -1; 721215976Sjmallett } 722215976Sjmallett 723215976Sjmallett if (hotplug_info_ptr->hotplug_activated_coremask != coremask) 724215976Sjmallett { 725215976Sjmallett printf("\nERROR: Not all application cores have activated hotplug\n"); 726215976Sjmallett return -1; 727215976Sjmallett } 728215976Sjmallett 729215976Sjmallett /* Send IPIs to all application cores to request shutdown */ 730215976Sjmallett for (i=0; i<CVMX_MAX_CORES; i++) { 731232812Sjmallett if (coremask & (1ull<<i)) 732232812Sjmallett cvmx_write_csr(CVMX_CIU_MBOX_SETX(i), 1); 733215976Sjmallett } 734215976Sjmallett 735215976Sjmallett if (wait) 736215976Sjmallett { 737215976Sjmallett while (!hotplug_info_ptr->shutdown_done); 738215976Sjmallett 739215976Sjmallett /* Clean up the hotplug info region for this application */ 740215976Sjmallett bzero(hotplug_info_ptr, sizeof(*hotplug_info_ptr)); 741215976Sjmallett } 742215976Sjmallett 743215976Sjmallett return 0; 744215976Sjmallett} 745232812Sjmallett 746232812Sjmallett 747232812Sjmallett 748232812Sjmallett/** 749232812Sjmallett * This routine invokes the invoked the cores_added callbacks. 750232812Sjmallett */ 751232812Sjmallettint cvmx_app_hotplug_call_add_cores_callback(int index) 752232812Sjmallett{ 753232812Sjmallett cvmx_app_hotplug_info_t *ai; 754232812Sjmallett int i; 755232812Sjmallett if (!(ai = cvmx_app_hotplug_get_info_at_index(index))) 756232812Sjmallett { 757232812Sjmallett printf("\nERROR: Failed to get hotplug info for app at index=%d\n", index); 758232812Sjmallett return -1; 759232812Sjmallett } 760232812Sjmallett /* Send IPIs to all application cores to request add_cores callback*/ 761232812Sjmallett for (i=0; i<CVMX_MAX_CORES; i++) { 762232812Sjmallett if (ai->coremask & (1ull<<i)) 763232812Sjmallett cvmx_write_csr(CVMX_CIU_MBOX_SETX(i), 4); 764232812Sjmallett } 765232812Sjmallett return 0; 766232812Sjmallett} 767232812Sjmallett 768232812Sjmallett/** 769232812Sjmallett * This routine sends a request to a running target application 770232812Sjmallett * to unplug a specified set cores 771232812Sjmallett * @param index is the index of the target application 772232812Sjmallett * @param coremask Coremask of the cores to be unplugged from the app. 773232812Sjmallett * @param wait 1 - Wait for shutdown completion 774232812Sjmallett * 0 - Do not wait 775232812Sjmallett * @return 0 on success, -1 on error 776232812Sjmallett * 777232812Sjmallett */ 778232812Sjmallettint cvmx_app_hotplug_unplug_cores(int index, uint32_t coremask, int wait) 779232812Sjmallett{ 780232812Sjmallett cvmx_app_hotplug_info_t *ai; 781232812Sjmallett int i; 782232812Sjmallett 783232812Sjmallett if (!(ai = cvmx_app_hotplug_get_info_at_index(index))) 784232812Sjmallett { 785232812Sjmallett printf("\nERROR: Failed to get hotplug info for app at index=%d\n", index); 786232812Sjmallett return -1; 787232812Sjmallett } 788232812Sjmallett ai->unplug_cores = coremask; 789232812Sjmallett#if 0 790232812Sjmallett if (!ai->shutdown_callback) 791232812Sjmallett { 792232812Sjmallett printf("\nERROR: Target application has not registered for hotplug!\n"); 793232812Sjmallett return -1; 794232812Sjmallett } 795232812Sjmallett#endif 796232812Sjmallett if ( (ai->coremask | coremask ) != ai->coremask) 797232812Sjmallett { 798232812Sjmallett printf("\nERROR: Not all cores requested are a part of the app " 799232812Sjmallett "r=%08x:%08x\n", (unsigned int)coremask, (unsigned int)ai->coremask); 800232812Sjmallett return -1; 801232812Sjmallett } 802232812Sjmallett if (ai->coremask == coremask) 803232812Sjmallett { 804232812Sjmallett printf("\nERROR: Trying to remove all cores in app. " 805232812Sjmallett "r=%08x:%08x\n", (unsigned int)coremask, (unsigned int)ai->coremask); 806232812Sjmallett return -1; 807232812Sjmallett } 808232812Sjmallett /* Send IPIs to all application cores to request unplug/remove_cores 809232812Sjmallett callback */ 810232812Sjmallett for (i=0; i<CVMX_MAX_CORES; i++) { 811232812Sjmallett if (ai->coremask & (1ull<<i)) 812232812Sjmallett cvmx_write_csr(CVMX_CIU_MBOX_SETX(i), 2); 813232812Sjmallett } 814232812Sjmallett 815232812Sjmallett#if 0 816232812Sjmallett if (wait) 817232812Sjmallett { 818232812Sjmallett while (!ai->shutdown_done); 819232812Sjmallett 820232812Sjmallett /* Clean up the hotplug info region for this application */ 821232812Sjmallett bzero(ai, sizeof(*ai)); 822232812Sjmallett } 823232812Sjmallett#endif 824232812Sjmallett return 0; 825232812Sjmallett} 826232812Sjmallett 827232812Sjmallett/** 828232812Sjmallett * Returns 1 if any app is currently being currently booted , hotplugged or 829232812Sjmallett * shutdown. Only one app can be under a boot, hotplug or shutdown condition. 830232812Sjmallett * Before booting an app this methods should be used to check whether boot or 831232812Sjmallett * shutdown activity is in progress and proceed with the boot or shutdown only 832232812Sjmallett * when there is no other activity. 833232812Sjmallett * 834232812Sjmallett */ 835232812Sjmallettint is_app_under_boot_or_shutdown(void) 836232812Sjmallett{ 837232812Sjmallett int ret=0; 838232812Sjmallett cvmx_app_hotplug_global_t *hgp; 839232812Sjmallett 840232812Sjmallett hgp = cvmx_app_get_hotplug_global_ptr(); 841232812Sjmallett cvmx_spinlock_lock(&hgp->hotplug_global_lock); 842232812Sjmallett if (hgp->app_under_boot || hgp->app_under_shutdown) ret=1; 843232812Sjmallett cvmx_spinlock_unlock(&hgp->hotplug_global_lock); 844232812Sjmallett return ret; 845232812Sjmallett 846232812Sjmallett} 847232812Sjmallett 848232812Sjmallett/** 849232812Sjmallett * Sets or clear the app_under_boot value. This when set signifies that an app 850232812Sjmallett * is being currently booted or hotplugged with a new core. 851232812Sjmallett * 852232812Sjmallett * 853232812Sjmallett * @param val sets the app_under_boot to the specified value. This should be 854232812Sjmallett * set to 1 while app any is being booted and cleared after the 855232812Sjmallett * application has booted up. 856232812Sjmallett * 857232812Sjmallett */ 858232812Sjmallettvoid set_app_unber_boot(int val) 859232812Sjmallett{ 860232812Sjmallett cvmx_app_hotplug_global_t *hgp; 861232812Sjmallett 862232812Sjmallett hgp = cvmx_app_get_hotplug_global_ptr(); 863232812Sjmallett cvmx_spinlock_lock(&hgp->hotplug_global_lock); 864232812Sjmallett hgp->app_under_boot = val; 865232812Sjmallett cvmx_spinlock_unlock(&hgp->hotplug_global_lock); 866232812Sjmallett} 867232812Sjmallett 868232812Sjmallett/** 869232812Sjmallett * Sets or clear the app_under_shutdown value. This when set signifies that an 870232812Sjmallett * app is being currently shutdown or some cores of an app are being shutdown. 871232812Sjmallett * 872232812Sjmallett * @param val sets the app_under_shutdown to the specified value. This 873232812Sjmallett * should be set to 1 while any app is being shutdown and cleared 874232812Sjmallett * after the shutdown of the app is complete. 875232812Sjmallett * 876232812Sjmallett */ 877232812Sjmallettvoid set_app_under_shutdown(int val) 878232812Sjmallett{ 879232812Sjmallett cvmx_app_hotplug_global_t *hgp; 880232812Sjmallett 881232812Sjmallett hgp = cvmx_app_get_hotplug_global_ptr(); 882232812Sjmallett cvmx_spinlock_lock(&hgp->hotplug_global_lock); 883232812Sjmallett hgp->app_under_shutdown = val; 884232812Sjmallett cvmx_spinlock_unlock(&hgp->hotplug_global_lock); 885232812Sjmallett} 886