cvmx-app-hotplug.c revision 215990
1/***********************license start*************** 2 * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights 3 * reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 18 * * Neither the name of Cavium Networks nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 23 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38 ***********************license end**************************************/ 39 40/** 41 * @file 42 * 43 * Provides APIs for applications to register for hotplug. It also provides 44 * APIs for requesting shutdown of a running target application. 45 * 46 * <hr>$Revision: $<hr> 47 */ 48 49#include "cvmx-app-hotplug.h" 50#include "cvmx-spinlock.h" 51 52//#define DEBUG 1 53 54#ifndef CVMX_BUILD_FOR_LINUX_USER 55 56static CVMX_SHARED cvmx_spinlock_t cvmx_app_hotplug_sync_lock = { CVMX_SPINLOCK_UNLOCKED_VAL }; 57static CVMX_SHARED cvmx_spinlock_t cvmx_app_hotplug_lock = { CVMX_SPINLOCK_UNLOCKED_VAL }; 58static CVMX_SHARED cvmx_app_hotplug_info_t *cvmx_app_hotplug_info_ptr = NULL; 59 60static void __cvmx_app_hotplug_shutdown(int irq_number, uint64_t registers[32], void *user_arg); 61static void __cvmx_app_hotplug_sync(void); 62static void __cvmx_app_hotplug_reset(void); 63 64/** 65 * This routine registers an application for hotplug. It installs a handler for 66 * any incoming shutdown request. It also registers a callback routine from the 67 * application. This callback is invoked when the application receives a 68 * shutdown notification. 69 * 70 * This routine only needs to be called once per application. 71 * 72 * @param fn Callback routine from the application. 73 * @param arg Argument to the application callback routine. 74 * @return Return 0 on success, -1 on failure 75 * 76 */ 77int cvmx_app_hotplug_register(void(*fn)(void*), void* arg) 78{ 79 /* Find the list of applications launched by bootoct utility. */ 80 81 if (!(cvmx_app_hotplug_info_ptr = cvmx_app_hotplug_get_info(cvmx_sysinfo_get()->core_mask))) 82 { 83 /* Application not launched by bootoct? */ 84 printf("ERROR: cmvx_app_hotplug_register() failed\n"); 85 return -1; 86 } 87 88 /* Register the callback */ 89 cvmx_app_hotplug_info_ptr->data = CAST64(arg); 90 cvmx_app_hotplug_info_ptr->shutdown_callback = CAST64(fn); 91 92#ifdef DEBUG 93 cvmx_dprintf("cvmx_app_hotplug_register(): coremask 0x%x valid %d\n", 94 cvmx_app_hotplug_info_ptr->coremask, cvmx_app_hotplug_info_ptr->valid); 95#endif 96 97 cvmx_interrupt_register(CVMX_IRQ_MBOX0, __cvmx_app_hotplug_shutdown, NULL); 98 99 return 0; 100} 101 102/** 103 * Activate the current application core for receiving hotplug shutdown requests. 104 * 105 * This routine makes sure that each core belonging to the application is enabled 106 * to receive the shutdown notification and also provides a barrier sync to make 107 * sure that all cores are ready. 108 */ 109int cvmx_app_hotplug_activate(void) 110{ 111 /* Make sure all application cores are activating */ 112 __cvmx_app_hotplug_sync(); 113 114 cvmx_spinlock_lock(&cvmx_app_hotplug_lock); 115 116 if (!cvmx_app_hotplug_info_ptr) 117 { 118 cvmx_spinlock_unlock(&cvmx_app_hotplug_lock); 119 printf("ERROR: This application is not registered for hotplug\n"); 120 return -1; 121 } 122 123 /* Enable the interrupt before we mark the core as activated */ 124 cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0); 125 126 cvmx_app_hotplug_info_ptr->hotplug_activated_coremask |= (1<<cvmx_get_core_num()); 127 128#ifdef DEBUG 129 cvmx_dprintf("cvmx_app_hotplug_activate(): coremask 0x%x valid %d sizeof %d\n", 130 cvmx_app_hotplug_info_ptr->coremask, cvmx_app_hotplug_info_ptr->valid, 131 sizeof(*cvmx_app_hotplug_info_ptr)); 132#endif 133 134 cvmx_spinlock_unlock(&cvmx_app_hotplug_lock); 135 136 return 0; 137} 138 139/** 140 * This routine is only required if cvmx_app_hotplug_shutdown_request() was called 141 * with wait=0. This routine waits for the application shutdown to complete. 142 * 143 * @param coremask Coremask the application is running on. 144 * @return 0 on success, -1 on error 145 * 146 */ 147int cvmx_app_hotplug_shutdown_complete(uint32_t coremask) 148{ 149 cvmx_app_hotplug_info_t *hotplug_info_ptr; 150 151 if (!(hotplug_info_ptr = cvmx_app_hotplug_get_info(coremask))) 152 { 153 printf("\nERROR: Failed to get hotplug info for coremask: 0x%x\n", (unsigned int)coremask); 154 return -1; 155 } 156 157 while(!hotplug_info_ptr->shutdown_done); 158 159 /* Clean up the hotplug info region for this app */ 160 bzero(hotplug_info_ptr, sizeof(*hotplug_info_ptr)); 161 162 return 0; 163} 164 165/** 166 * Disable recognition of any incoming shutdown request. 167 */ 168 169void cvmx_app_hotplug_shutdown_disable(void) 170{ 171 cvmx_interrupt_mask_irq(CVMX_IRQ_MBOX0); 172} 173 174/** 175 * Re-enable recognition of incoming shutdown requests. 176 */ 177 178void cvmx_app_hotplug_shutdown_enable(void) 179{ 180 cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0); 181} 182 183/* 184 * ISR for the incoming shutdown request interrupt. 185 */ 186static void __cvmx_app_hotplug_shutdown(int irq_number, uint64_t registers[32], void *user_arg) 187{ 188 cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get(); 189 uint32_t flags; 190 191 cvmx_interrupt_mask_irq(CVMX_IRQ_MBOX0); 192 193 /* Clear the interrupt */ 194 cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 1); 195 196 /* Make sure the write above completes */ 197 cvmx_read_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num())); 198 199 if (!cvmx_app_hotplug_info_ptr) 200 { 201 printf("ERROR: Application is not registered for hotplug!\n"); 202 return; 203 } 204 205 if (cvmx_app_hotplug_info_ptr->hotplug_activated_coremask != sys_info_ptr->core_mask) 206 { 207 printf("ERROR: Shutdown requested when not all app cores have activated hotplug\n" 208 "Application coremask: 0x%x Hotplug coremask: 0x%x\n", (unsigned int)sys_info_ptr->core_mask, 209 (unsigned int)cvmx_app_hotplug_info_ptr->hotplug_activated_coremask); 210 return; 211 } 212 213 /* Call the application's own callback function */ 214 ((void(*)(void*))(long)cvmx_app_hotplug_info_ptr->shutdown_callback)(CASTPTR(void *, cvmx_app_hotplug_info_ptr->data)); 215 216 __cvmx_app_hotplug_sync(); 217 218 if (cvmx_coremask_first_core(sys_info_ptr->core_mask)) 219 { 220 bzero(cvmx_app_hotplug_info_ptr, sizeof(*cvmx_app_hotplug_info_ptr)); 221#ifdef DEBUG 222 cvmx_dprintf("__cvmx_app_hotplug_shutdown(): setting shutdown done! \n"); 223#endif 224 cvmx_app_hotplug_info_ptr->shutdown_done = 1; 225 } 226 227 flags = cvmx_interrupt_disable_save(); 228 229 __cvmx_app_hotplug_sync(); 230 231 /* Reset the core */ 232 __cvmx_app_hotplug_reset(); 233} 234 235/* 236 * Reset the core. We just jump back to the reset vector for now. 237 */ 238void __cvmx_app_hotplug_reset(void) 239{ 240 /* Code from SecondaryCoreLoop from bootloader, sleep until we recieve 241 a NMI. */ 242 __asm__ volatile ( 243 ".set noreorder \n" 244 "\tsync \n" 245 "\tnop \n" 246 "1:\twait \n" 247 "\tb 1b \n" 248 "\tnop \n" 249 ".set reorder \n" 250 :: 251 ); 252} 253 254/* 255 * We need a separate sync operation from cvmx_coremask_barrier_sync() to 256 * avoid a deadlock on state.lock, since the application itself maybe doing a 257 * cvmx_coremask_barrier_sync(). 258 */ 259static void __cvmx_app_hotplug_sync(void) 260{ 261 static CVMX_SHARED volatile uint32_t sync_coremask = 0; 262 cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get(); 263 264 cvmx_spinlock_lock(&cvmx_app_hotplug_sync_lock); 265 266 sync_coremask |= cvmx_coremask_core(cvmx_get_core_num()); 267 268 cvmx_spinlock_unlock(&cvmx_app_hotplug_sync_lock); 269 270 while (sync_coremask != sys_info_ptr->core_mask); 271} 272 273#endif /* CVMX_BUILD_FOR_LINUX_USER */ 274 275/** 276 * Return the hotplug info structure (cvmx_app_hotplug_info_t) pointer for the 277 * application running on the given coremask. 278 * 279 * @param coremask Coremask of application. 280 * @return Returns hotplug info struct on success, NULL on failure 281 * 282 */ 283cvmx_app_hotplug_info_t* cvmx_app_hotplug_get_info(uint32_t coremask) 284{ 285 const struct cvmx_bootmem_named_block_desc *block_desc; 286 cvmx_app_hotplug_info_t *hip; 287 cvmx_app_hotplug_global_t *hgp; 288 int i; 289 290 block_desc = cvmx_bootmem_find_named_block(CVMX_APP_HOTPLUG_INFO_REGION_NAME); 291 292 if (!block_desc) 293 { 294 printf("ERROR: Hotplug info region is not setup\n"); 295 return NULL; 296 } 297 else 298 299#ifdef CVMX_BUILD_FOR_LINUX_USER 300 { 301 size_t pg_sz = sysconf(_SC_PAGESIZE), size; 302 off_t offset; 303 char *vaddr; 304 int fd; 305 306 if ((fd = open("/dev/mem", O_RDWR)) == -1) { 307 perror("open"); 308 return NULL; 309 } 310 311 /* 312 * We need to mmap() this memory, since this was allocated from the 313 * kernel bootup code and does not reside in the RESERVE32 region. 314 */ 315 size = CVMX_APP_HOTPLUG_INFO_REGION_SIZE + pg_sz-1; 316 offset = block_desc->base_addr & ~(pg_sz-1); 317 if ((vaddr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) 318 { 319 perror("mmap"); 320 return NULL; 321 } 322 323 hgp = (cvmx_app_hotplug_global_t *)(vaddr + ( block_desc->base_addr & (pg_sz-1))); 324 } 325#else 326 hgp = cvmx_phys_to_ptr(block_desc->base_addr); 327#endif 328 329 hip = hgp->hotplug_info_array; 330 331#ifdef DEBUG 332 cvmx_dprintf("cvmx_app_hotplug_get_info(): hotplug_info phy addr 0x%llx ptr %p\n", 333 block_desc->base_addr, hgp); 334#endif 335 336 /* Look for the current app's info */ 337 338 for (i=0; i<CVMX_APP_HOTPLUG_MAX_APPS; i++) 339 { 340 if (hip[i].coremask == coremask) 341 { 342#ifdef DEBUG 343 cvmx_dprintf("cvmx_app_hotplug_get_info(): coremask match %d -- coremask 0x%x valid %d\n", 344 i, hip[i].coremask, hip[i].valid); 345#endif 346 347 return &hip[i]; 348 } 349 } 350 351 return NULL; 352} 353 354/** 355 * This routine sends a shutdown request to a running target application. 356 * 357 * @param coremask Coremask the application is running on. 358 * @param wait 1 - Wait for shutdown completion 359 * 0 - Do not wait 360 * @return 0 on success, -1 on error 361 * 362 */ 363 364int cvmx_app_hotplug_shutdown_request(uint32_t coremask, int wait) 365{ 366 int i; 367 cvmx_app_hotplug_info_t *hotplug_info_ptr; 368 369 if (!(hotplug_info_ptr = cvmx_app_hotplug_get_info(coremask))) 370 { 371 printf("\nERROR: Failed to get hotplug info for coremask: 0x%x\n", (unsigned int)coremask); 372 return -1; 373 } 374 375 if (!hotplug_info_ptr->shutdown_callback) 376 { 377 printf("\nERROR: Target application has not registered for hotplug!\n"); 378 return -1; 379 } 380 381 if (hotplug_info_ptr->hotplug_activated_coremask != coremask) 382 { 383 printf("\nERROR: Not all application cores have activated hotplug\n"); 384 return -1; 385 } 386 387 /* Send IPIs to all application cores to request shutdown */ 388 for (i=0; i<CVMX_MAX_CORES; i++) { 389 if (coremask & (1<<i)) 390 cvmx_write_csr(CVMX_CIU_MBOX_SETX(i), 1); 391 } 392 393 if (wait) 394 { 395 while (!hotplug_info_ptr->shutdown_done); 396 397 /* Clean up the hotplug info region for this application */ 398 bzero(hotplug_info_ptr, sizeof(*hotplug_info_ptr)); 399 } 400 401 return 0; 402} 403