dc4ee6ca91
make use of it where possible. This primarily brings in support for newer hardware, and FreeBSD is not yet able to support the abundance of IRQs on new hardware and many features in the Ethernet driver. Because of the changes to IRQs in the Simple Executive, we have to maintain our own list of Octeon IRQs now, which probably can be pared-down and be specific to the CIU interrupt unit soon, and when other interrupt mechanisms are added they can maintain their own definitions. Remove unmasking of interrupts from within the UART device now that the function used is no longer present in the Simple Executive. The unmasking seems to have been gratuitous as this is more properly handled by the buses above the UART device, and seems to work on that basis.
886 lines
28 KiB
C
886 lines
28 KiB
C
/***********************license start***************
|
|
* Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights
|
|
* reserved.
|
|
*
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
|
|
* * Neither the name of Cavium Inc. nor the names of
|
|
* its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written
|
|
* permission.
|
|
|
|
* This Software, including technical data, may be subject to U.S. export control
|
|
* laws, including the U.S. Export Administration Act and its associated
|
|
* regulations, and may be subject to export or import regulations in other
|
|
* countries.
|
|
|
|
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
|
|
* AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
|
|
* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
|
|
* THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
|
|
* DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
|
|
* SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
|
|
* MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
|
|
* VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
|
|
* CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR
|
|
* PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
|
|
***********************license end**************************************/
|
|
|
|
/**
|
|
* @file
|
|
*
|
|
* Provides APIs for applications to register for hotplug. It also provides
|
|
* APIs for requesting shutdown of a running target application.
|
|
*
|
|
* <hr>$Revision: $<hr>
|
|
*/
|
|
|
|
#include "cvmx-app-hotplug.h"
|
|
#include "cvmx-spinlock.h"
|
|
#include "cvmx-debug.h"
|
|
|
|
//#define DEBUG 1
|
|
|
|
static cvmx_app_hotplug_global_t *hotplug_global_ptr = 0;
|
|
|
|
#ifndef CVMX_BUILD_FOR_LINUX_USER
|
|
|
|
static CVMX_SHARED cvmx_spinlock_t cvmx_app_hotplug_sync_lock = { CVMX_SPINLOCK_UNLOCKED_VAL };
|
|
static CVMX_SHARED cvmx_spinlock_t cvmx_app_hotplug_lock = { CVMX_SPINLOCK_UNLOCKED_VAL };
|
|
static CVMX_SHARED cvmx_app_hotplug_info_t *cvmx_app_hotplug_info_ptr = NULL;
|
|
|
|
static void __cvmx_app_hotplug_shutdown(int irq_number, uint64_t registers[32], void *user_arg);
|
|
static void __cvmx_app_hotplug_sync(void);
|
|
static void __cvmx_app_hotplug_reset(void);
|
|
|
|
/* Declaring this array here is a compile time check to ensure that the
|
|
size of cvmx_app_hotplug_info_t is 1024. If the size is not 1024
|
|
the size of the array will be -1 and this results in a compilation
|
|
error */
|
|
char __hotplug_info_check[(sizeof(cvmx_app_hotplug_info_t) == 1024) ? 1 : -1];
|
|
/**
|
|
* This routine registers an application for hotplug. It installs a handler for
|
|
* any incoming shutdown request. It also registers a callback routine from the
|
|
* application. This callback is invoked when the application receives a
|
|
* shutdown notification.
|
|
*
|
|
* This routine only needs to be called once per application.
|
|
*
|
|
* @param fn Callback routine from the application.
|
|
* @param arg Argument to the application callback routine.
|
|
* @return Return 0 on success, -1 on failure
|
|
*
|
|
*/
|
|
int cvmx_app_hotplug_register(void(*fn)(void*), void* arg)
|
|
{
|
|
/* Find the list of applications launched by bootoct utility. */
|
|
|
|
if (!(cvmx_app_hotplug_info_ptr = cvmx_app_hotplug_get_info(cvmx_sysinfo_get()->core_mask)))
|
|
{
|
|
/* Application not launched by bootoct? */
|
|
printf("ERROR: cmvx_app_hotplug_register() failed\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Register the callback */
|
|
cvmx_app_hotplug_info_ptr->data = CAST64(arg);
|
|
cvmx_app_hotplug_info_ptr->shutdown_callback = CAST64(fn);
|
|
|
|
#ifdef DEBUG
|
|
printf("cvmx_app_hotplug_register(): coremask 0x%x valid %d\n",
|
|
cvmx_app_hotplug_info_ptr->coremask, cvmx_app_hotplug_info_ptr->valid);
|
|
#endif
|
|
|
|
cvmx_interrupt_register(CVMX_IRQ_MBOX0, __cvmx_app_hotplug_shutdown, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* This routine deprecates the the cvmx_app_hotplug_register method. This
|
|
* registers application for hotplug and the application will have CPU
|
|
* hotplug callbacks. Various callbacks are specified in cb.
|
|
* cvmx_app_hotplug_callbacks_t documents the callbacks
|
|
*
|
|
* This routine only needs to be called once per application.
|
|
*
|
|
* @param cb Callback routine from the application.
|
|
* @param arg Argument to the application callback routins
|
|
* @param app_shutdown When set to 1 the application will invoke core_shutdown
|
|
on each core. When set to 0 core shutdown will be
|
|
called invoked automatically after invoking the
|
|
application callback.
|
|
* @return Return index of app on success, -1 on failure
|
|
*
|
|
*/
|
|
int cvmx_app_hotplug_register_cb(cvmx_app_hotplug_callbacks_t *cb, void* arg,
|
|
int app_shutdown)
|
|
{
|
|
cvmx_app_hotplug_info_t *app_info;
|
|
|
|
/* Find the list of applications launched by bootoct utility. */
|
|
app_info = cvmx_app_hotplug_get_info(cvmx_sysinfo_get()->core_mask);
|
|
cvmx_app_hotplug_info_ptr = app_info;
|
|
if (!app_info)
|
|
{
|
|
/* Application not launched by bootoct? */
|
|
printf("ERROR: cmvx_app_hotplug_register() failed\n");
|
|
return -1;
|
|
}
|
|
/* Register the callback */
|
|
app_info->data = CAST64(arg);
|
|
app_info->shutdown_callback = CAST64(cb->shutdown_callback);
|
|
app_info->cores_added_callback = CAST64(cb->cores_added_callback);
|
|
app_info->cores_removed_callback = CAST64(cb->cores_removed_callback);
|
|
app_info->unplug_callback = CAST64(cb->unplug_core_callback);
|
|
app_info->hotplug_start = CAST64(cb->hotplug_start);
|
|
app_info->app_shutdown = app_shutdown;
|
|
#ifdef DEBUG
|
|
printf("cvmx_app_hotplug_register(): coremask 0x%x valid %d\n",
|
|
app_info->coremask, app_info->valid);
|
|
#endif
|
|
|
|
cvmx_interrupt_register(CVMX_IRQ_MBOX0, __cvmx_app_hotplug_shutdown, NULL);
|
|
return 0;
|
|
|
|
}
|
|
|
|
void cvmx_app_hotplug_remove_self_from_core_mask(void)
|
|
{
|
|
int core = cvmx_get_core_num();
|
|
uint32_t core_mask = 1ull << core;
|
|
|
|
cvmx_spinlock_lock(&cvmx_app_hotplug_lock);
|
|
cvmx_app_hotplug_info_ptr->coremask = cvmx_app_hotplug_info_ptr->coremask & ~core_mask ;
|
|
cvmx_app_hotplug_info_ptr->hotplug_activated_coremask =
|
|
cvmx_app_hotplug_info_ptr->hotplug_activated_coremask & ~core_mask ;
|
|
cvmx_spinlock_unlock(&cvmx_app_hotplug_lock);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Returns 1 if the running core is being unplugged, else it returns 0.
|
|
*/
|
|
int is_core_being_unplugged(void)
|
|
{
|
|
if (cvmx_app_hotplug_info_ptr->unplug_cores &
|
|
(1ull << cvmx_get_core_num()))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Activate the current application core for receiving hotplug shutdown requests.
|
|
*
|
|
* This routine makes sure that each core belonging to the application is enabled
|
|
* to receive the shutdown notification and also provides a barrier sync to make
|
|
* sure that all cores are ready.
|
|
*/
|
|
int cvmx_app_hotplug_activate(void)
|
|
{
|
|
uint64_t cnt = 0;
|
|
uint64_t cnt_interval = 10000000;
|
|
|
|
while (!cvmx_app_hotplug_info_ptr)
|
|
{
|
|
cnt++;
|
|
if ((cnt % cnt_interval) == 0)
|
|
printf("waiting for cnt=%lld\n", (unsigned long long)cnt);
|
|
}
|
|
|
|
if (cvmx_app_hotplug_info_ptr->hplugged_cores & (1ull << cvmx_get_core_num()))
|
|
{
|
|
#ifdef DEBUG
|
|
printf("core=%d : is being hotplugged \n", cvmx_get_core_num());
|
|
#endif
|
|
cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get();
|
|
sys_info_ptr->core_mask |= 1ull << cvmx_get_core_num();
|
|
}
|
|
else
|
|
{
|
|
__cvmx_app_hotplug_sync();
|
|
}
|
|
cvmx_spinlock_lock(&cvmx_app_hotplug_lock);
|
|
if (!cvmx_app_hotplug_info_ptr)
|
|
{
|
|
cvmx_spinlock_unlock(&cvmx_app_hotplug_lock);
|
|
printf("ERROR: This application is not registered for hotplug\n");
|
|
return -1;
|
|
}
|
|
/* Enable the interrupt before we mark the core as activated */
|
|
cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0);
|
|
cvmx_app_hotplug_info_ptr->hotplug_activated_coremask |= (1ull<<cvmx_get_core_num());
|
|
|
|
#ifdef DEBUG
|
|
printf("cvmx_app_hotplug_activate(): coremask 0x%x valid %d sizeof %d\n",
|
|
cvmx_app_hotplug_info_ptr->coremask, cvmx_app_hotplug_info_ptr->valid,
|
|
sizeof(*cvmx_app_hotplug_info_ptr));
|
|
#endif
|
|
|
|
cvmx_spinlock_unlock(&cvmx_app_hotplug_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* This routine is only required if cvmx_app_hotplug_shutdown_request() was called
|
|
* with wait=0. This routine waits for the application shutdown to complete.
|
|
*
|
|
* @param coremask Coremask the application is running on.
|
|
* @return 0 on success, -1 on error
|
|
*
|
|
*/
|
|
int cvmx_app_hotplug_shutdown_complete(uint32_t coremask)
|
|
{
|
|
cvmx_app_hotplug_info_t *hotplug_info_ptr;
|
|
|
|
if (!(hotplug_info_ptr = cvmx_app_hotplug_get_info(coremask)))
|
|
{
|
|
printf("\nERROR: Failed to get hotplug info for coremask: 0x%x\n", (unsigned int)coremask);
|
|
return -1;
|
|
}
|
|
|
|
while(!hotplug_info_ptr->shutdown_done);
|
|
|
|
/* Clean up the hotplug info region for this app */
|
|
bzero(hotplug_info_ptr, sizeof(*hotplug_info_ptr));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Disable recognition of any incoming shutdown request.
|
|
*/
|
|
|
|
void cvmx_app_hotplug_shutdown_disable(void)
|
|
{
|
|
cvmx_interrupt_mask_irq(CVMX_IRQ_MBOX0);
|
|
}
|
|
|
|
/**
|
|
* Re-enable recognition of incoming shutdown requests.
|
|
*/
|
|
|
|
void cvmx_app_hotplug_shutdown_enable(void)
|
|
{
|
|
cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0);
|
|
}
|
|
|
|
/**
|
|
* Request shutdown of the currently running core. Should be
|
|
* called by the application when it has been registered with
|
|
* app_shutdown option set to 1.
|
|
*/
|
|
void cvmx_app_hotplug_core_shutdown(void)
|
|
{
|
|
uint32_t flags;
|
|
if (cvmx_app_hotplug_info_ptr->shutdown_cores)
|
|
{
|
|
cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get();
|
|
__cvmx_app_hotplug_sync();
|
|
if (cvmx_coremask_first_core(sys_info_ptr->core_mask))
|
|
{
|
|
bzero(cvmx_app_hotplug_info_ptr,
|
|
sizeof(*cvmx_app_hotplug_info_ptr));
|
|
#ifdef DEBUG
|
|
printf("__cvmx_app_hotplug_shutdown(): setting shutdown done! \n");
|
|
#endif
|
|
cvmx_app_hotplug_info_ptr->shutdown_done = 1;
|
|
}
|
|
/* Tell the debugger that this application is finishing. */
|
|
cvmx_debug_finish ();
|
|
flags = cvmx_interrupt_disable_save();
|
|
__cvmx_app_hotplug_sync();
|
|
/* Reset the core */
|
|
__cvmx_app_hotplug_reset();
|
|
}
|
|
else
|
|
{
|
|
cvmx_sysinfo_remove_self_from_core_mask();
|
|
cvmx_app_hotplug_remove_self_from_core_mask();
|
|
flags = cvmx_interrupt_disable_save();
|
|
__cvmx_app_hotplug_reset();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ISR for the incoming shutdown request interrupt.
|
|
*/
|
|
static void __cvmx_app_hotplug_shutdown(int irq_number, uint64_t registers[32],
|
|
void *user_arg)
|
|
{
|
|
cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get();
|
|
uint64_t mbox;
|
|
cvmx_app_hotplug_info_t *ai = cvmx_app_hotplug_info_ptr;
|
|
int dbg = 0;
|
|
|
|
#ifdef DEBUG
|
|
dbg = 1;
|
|
#endif
|
|
cvmx_interrupt_mask_irq(CVMX_IRQ_MBOX0);
|
|
|
|
mbox = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()));
|
|
/* Clear the interrupt */
|
|
cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), mbox);
|
|
|
|
/* Make sure the write above completes */
|
|
cvmx_read_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()));
|
|
|
|
|
|
if (!cvmx_app_hotplug_info_ptr)
|
|
{
|
|
printf("ERROR: Application is not registered for hotplug!\n");
|
|
return;
|
|
}
|
|
|
|
if (ai->hotplug_activated_coremask != sys_info_ptr->core_mask)
|
|
{
|
|
printf("ERROR: Shutdown requested when not all app cores have "
|
|
"activated hotplug\n" "Application coremask: 0x%x Hotplug "
|
|
"coremask: 0x%x\n", (unsigned int)sys_info_ptr->core_mask,
|
|
(unsigned int)ai->hotplug_activated_coremask);
|
|
return;
|
|
}
|
|
|
|
if (mbox & 1ull)
|
|
{
|
|
int core = cvmx_get_core_num();
|
|
if (dbg)
|
|
printf("Shutting down application .\n");
|
|
/* Call the application's own callback function */
|
|
if (ai->shutdown_callback)
|
|
{
|
|
((void(*)(void*))(long)ai->shutdown_callback)(CASTPTR(void *, ai->data));
|
|
}
|
|
else
|
|
{
|
|
printf("ERROR : Shutdown callback has not been registered\n");
|
|
}
|
|
if (!ai->app_shutdown)
|
|
{
|
|
if (dbg)
|
|
printf("%s : core = %d Invoking app shutdown\n", __FUNCTION__, core);
|
|
cvmx_app_hotplug_core_shutdown();
|
|
}
|
|
}
|
|
else if (mbox & 2ull)
|
|
{
|
|
int core = cvmx_get_core_num();
|
|
int unplug = is_core_being_unplugged();
|
|
if (dbg) printf("%s : core=%d Unplug event \n", __FUNCTION__, core);
|
|
|
|
if (unplug)
|
|
{
|
|
/* Call the application's own callback function */
|
|
if (ai->unplug_callback)
|
|
{
|
|
if (dbg) printf("%s : core=%d Calling unplug callback\n",
|
|
__FUNCTION__, core);
|
|
((void(*)(void*))(long)ai->unplug_callback)(CASTPTR(void *,
|
|
ai->data));
|
|
}
|
|
if (!ai->app_shutdown)
|
|
{
|
|
if (dbg) printf("%s : core = %d Invoking app shutdown\n",
|
|
__FUNCTION__, core);
|
|
cvmx_app_hotplug_core_shutdown();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ai->cores_removed_callback)
|
|
{
|
|
if (dbg) printf("%s : core=%d Calling cores removed callback\n",
|
|
__FUNCTION__, core);
|
|
((void(*)(uint32_t, void*))(long)ai->cores_removed_callback)
|
|
(ai->unplug_cores, CASTPTR(void *, ai->data));
|
|
}
|
|
cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0);
|
|
}
|
|
}
|
|
else if (mbox & 4ull)
|
|
{
|
|
int core = cvmx_get_core_num();
|
|
if (dbg) printf("%s : core=%d Add cores event \n", __FUNCTION__, core);
|
|
|
|
if (ai->cores_added_callback)
|
|
{
|
|
if (dbg) printf("%s : core=%d Calling cores added callback\n",
|
|
__FUNCTION__, core);
|
|
((void(*)(uint32_t, void*))(long)ai->cores_added_callback)
|
|
(ai->hplugged_cores, CASTPTR(void *, ai->data));
|
|
}
|
|
cvmx_interrupt_unmask_irq(CVMX_IRQ_MBOX0);
|
|
}
|
|
else
|
|
{
|
|
printf("ERROR: unexpected mbox=%llx\n", (unsigned long long)mbox);
|
|
}
|
|
|
|
}
|
|
|
|
void __cvmx_app_hotplug_reset(void)
|
|
{
|
|
#define IDLE_CORE_BLOCK_NAME "idle-core-loop"
|
|
#define HPLUG_MAKE_XKPHYS(x) ((1ULL << 63) | (x))
|
|
uint64_t reset_addr;
|
|
const cvmx_bootmem_named_block_desc_t *block_desc;
|
|
|
|
block_desc = cvmx_bootmem_find_named_block(IDLE_CORE_BLOCK_NAME);
|
|
if (!block_desc) {
|
|
cvmx_dprintf("Named block(%s) is not created\n", IDLE_CORE_BLOCK_NAME);
|
|
/* loop here, should not happen */
|
|
__asm__ volatile (
|
|
".set noreorder \n"
|
|
"\tsync \n"
|
|
"\tnop \n"
|
|
"1:\twait \n"
|
|
"\tb 1b \n"
|
|
"\tnop \n"
|
|
".set reorder \n"
|
|
::
|
|
);
|
|
}
|
|
|
|
reset_addr = HPLUG_MAKE_XKPHYS(block_desc->base_addr);
|
|
asm volatile (" .set push \n"
|
|
" .set mips64 \n"
|
|
" .set noreorder \n"
|
|
" move $2, %[addr] \n"
|
|
" jr $2 \n"
|
|
" nop \n"
|
|
" .set pop "
|
|
:: [addr] "r"(reset_addr)
|
|
: "$2");
|
|
|
|
/*Should never reach here*/
|
|
while (1) ;
|
|
|
|
}
|
|
|
|
/*
|
|
* We need a separate sync operation from cvmx_coremask_barrier_sync() to
|
|
* avoid a deadlock on state.lock, since the application itself maybe doing a
|
|
* cvmx_coremask_barrier_sync().
|
|
*/
|
|
static void __cvmx_app_hotplug_sync(void)
|
|
{
|
|
static CVMX_SHARED volatile uint32_t sync_coremask = 0;
|
|
cvmx_sysinfo_t *sys_info_ptr = cvmx_sysinfo_get();
|
|
|
|
cvmx_spinlock_lock(&cvmx_app_hotplug_sync_lock);
|
|
|
|
sync_coremask |= cvmx_coremask_core(cvmx_get_core_num());
|
|
|
|
cvmx_spinlock_unlock(&cvmx_app_hotplug_sync_lock);
|
|
|
|
while (sync_coremask != sys_info_ptr->core_mask);
|
|
|
|
cvmx_spinlock_lock(&cvmx_app_hotplug_sync_lock);
|
|
sync_coremask = 0;
|
|
cvmx_spinlock_unlock(&cvmx_app_hotplug_sync_lock);
|
|
|
|
|
|
}
|
|
|
|
#endif /* CVMX_BUILD_FOR_LINUX_USER */
|
|
|
|
/**
|
|
* Returns 1 if the running core is being hotplugged, else it returns 0.
|
|
*/
|
|
int is_core_being_hot_plugged(void)
|
|
{
|
|
|
|
#ifndef CVMX_BUILD_FOR_LINUX_USER
|
|
if (!cvmx_app_hotplug_info_ptr) return 0;
|
|
if (cvmx_app_hotplug_info_ptr->hplugged_cores &
|
|
(1ull << cvmx_get_core_num()))
|
|
return 1;
|
|
return 0;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static cvmx_app_hotplug_global_t *cvmx_app_get_hotplug_global_ptr(void)
|
|
{
|
|
const struct cvmx_bootmem_named_block_desc *block_desc;
|
|
cvmx_app_hotplug_global_t *hgp;
|
|
|
|
if(hotplug_global_ptr != 0) return hotplug_global_ptr;
|
|
|
|
block_desc = cvmx_bootmem_find_named_block(CVMX_APP_HOTPLUG_INFO_REGION_NAME);
|
|
if (!block_desc)
|
|
{
|
|
printf("ERROR: Hotplug info region is not setup\n");
|
|
return NULL;
|
|
}
|
|
else
|
|
#ifdef CVMX_BUILD_FOR_LINUX_USER
|
|
{
|
|
size_t pg_sz = sysconf(_SC_PAGESIZE), size;
|
|
off_t offset;
|
|
char *vaddr;
|
|
int fd;
|
|
|
|
if ((fd = open("/dev/mem", O_RDWR)) == -1) {
|
|
perror("open");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* We need to mmap() this memory, since this was allocated from the
|
|
* kernel bootup code and does not reside in the RESERVE32 region.
|
|
*/
|
|
size = CVMX_APP_HOTPLUG_INFO_REGION_SIZE + pg_sz-1;
|
|
offset = block_desc->base_addr & ~(pg_sz-1);
|
|
if ((vaddr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset))
|
|
== MAP_FAILED)
|
|
{
|
|
perror("mmap");
|
|
return NULL;
|
|
}
|
|
|
|
hgp = (cvmx_app_hotplug_global_t *)(vaddr + ( block_desc->base_addr & (pg_sz-1)));
|
|
}
|
|
#else
|
|
hgp = CASTPTR(void, CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, block_desc->base_addr));
|
|
#endif
|
|
hotplug_global_ptr = hgp;
|
|
return hgp;
|
|
|
|
}
|
|
|
|
/**
|
|
* Return the hotplug info structure (cvmx_app_hotplug_info_t) pointer for the
|
|
* application running on the given coremask.
|
|
*
|
|
* @param coremask Coremask of application.
|
|
* @return Returns hotplug info struct on success, NULL on failure
|
|
*
|
|
*/
|
|
cvmx_app_hotplug_info_t* cvmx_app_hotplug_get_info(uint32_t coremask)
|
|
{
|
|
cvmx_app_hotplug_info_t *hip;
|
|
cvmx_app_hotplug_global_t *hgp;
|
|
int i;
|
|
int dbg = 0;
|
|
|
|
#ifdef DEBUG
|
|
dbg = 1;
|
|
#endif
|
|
hgp = cvmx_app_get_hotplug_global_ptr();
|
|
if (!hgp) return NULL;
|
|
hip = hgp->hotplug_info_array;
|
|
|
|
/* Look for the current app's info */
|
|
for (i=0; i<CVMX_APP_HOTPLUG_MAX_APPS; i++)
|
|
{
|
|
if (hip[i].coremask == coremask)
|
|
{
|
|
if (dbg)
|
|
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);
|
|
return &hip[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Return the hotplug application index structure for the application running on the
|
|
* given coremask.
|
|
*
|
|
* @param coremask Coremask of application.
|
|
* @return Returns hotplug application index on success. -1 on failure
|
|
*
|
|
*/
|
|
int cvmx_app_hotplug_get_index(uint32_t coremask)
|
|
{
|
|
cvmx_app_hotplug_info_t *hip;
|
|
cvmx_app_hotplug_global_t *hgp;
|
|
int i;
|
|
int dbg = 0;
|
|
|
|
#ifdef DEBUG
|
|
dbg = 1;
|
|
#endif
|
|
hgp = cvmx_app_get_hotplug_global_ptr();
|
|
if (!hgp) return -1;
|
|
hip = hgp->hotplug_info_array;
|
|
|
|
/* Look for the current app's info */
|
|
for (i=0; i<CVMX_APP_HOTPLUG_MAX_APPS; i++)
|
|
{
|
|
if (hip[i].coremask == coremask)
|
|
{
|
|
if (dbg)
|
|
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);
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void print_hot_plug_info(cvmx_app_hotplug_info_t* hpinfo)
|
|
{
|
|
printf("name=%s coremask=%08x hotplugged coremask=%08x valid=%d\n", hpinfo->app_name,
|
|
(unsigned int)hpinfo->coremask, (unsigned int)hpinfo->hotplug_activated_coremask, (unsigned int)hpinfo->valid);
|
|
}
|
|
|
|
/**
|
|
* Return the hotplug info structure (cvmx_app_hotplug_info_t) pointer for the
|
|
* application with the specified index.
|
|
*
|
|
* @param index index of application.
|
|
* @return Returns hotplug info struct on success, NULL on failure
|
|
*
|
|
*/
|
|
cvmx_app_hotplug_info_t* cvmx_app_hotplug_get_info_at_index(int index)
|
|
{
|
|
cvmx_app_hotplug_info_t *hip;
|
|
cvmx_app_hotplug_global_t *hgp;
|
|
|
|
hgp = cvmx_app_get_hotplug_global_ptr();
|
|
if (!hgp) return NULL;
|
|
hip = hgp->hotplug_info_array;
|
|
|
|
#ifdef DEBUG
|
|
printf("cvmx_app_hotplug_get_info(): hotplug_info phy addr 0x%llx ptr %p\n",
|
|
block_desc->base_addr, hgp);
|
|
#endif
|
|
if (index < CVMX_APP_HOTPLUG_MAX_APPS)
|
|
{
|
|
if (hip[index].valid)
|
|
{
|
|
//print_hot_plug_info( &hip[index] );
|
|
return &hip[index];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Determines if SE application at the index specified is hotpluggable.
|
|
*
|
|
* @param index index of application.
|
|
* @return Returns -1 on error.
|
|
* 0 -> The application is not hotpluggable
|
|
* 1 -> The application is hotpluggable
|
|
*/
|
|
int is_app_hotpluggable(int index)
|
|
{
|
|
cvmx_app_hotplug_info_t *ai;
|
|
|
|
if (!(ai = cvmx_app_hotplug_get_info_at_index(index)))
|
|
{
|
|
printf("\nERROR: Failed to get hotplug info for app at index=%d\n", index);
|
|
return -1;
|
|
}
|
|
if (ai->hotplug_activated_coremask) return 1;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* This routine sends a shutdown request to a running target application.
|
|
*
|
|
* @param coremask Coremask the application is running on.
|
|
* @param wait 1 - Wait for shutdown completion
|
|
* 0 - Do not wait
|
|
* @return 0 on success, -1 on error
|
|
*
|
|
*/
|
|
|
|
int cvmx_app_hotplug_shutdown_request(uint32_t coremask, int wait)
|
|
{
|
|
int i;
|
|
cvmx_app_hotplug_info_t *hotplug_info_ptr;
|
|
|
|
if (!(hotplug_info_ptr = cvmx_app_hotplug_get_info(coremask)))
|
|
{
|
|
printf("\nERROR: Failed to get hotplug info for coremask: 0x%x\n", (unsigned int)coremask);
|
|
return -1;
|
|
}
|
|
hotplug_info_ptr->shutdown_cores = coremask;
|
|
if (!hotplug_info_ptr->shutdown_callback)
|
|
{
|
|
printf("\nERROR: Target application has not registered for hotplug!\n");
|
|
return -1;
|
|
}
|
|
|
|
if (hotplug_info_ptr->hotplug_activated_coremask != coremask)
|
|
{
|
|
printf("\nERROR: Not all application cores have activated hotplug\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Send IPIs to all application cores to request shutdown */
|
|
for (i=0; i<CVMX_MAX_CORES; i++) {
|
|
if (coremask & (1ull<<i))
|
|
cvmx_write_csr(CVMX_CIU_MBOX_SETX(i), 1);
|
|
}
|
|
|
|
if (wait)
|
|
{
|
|
while (!hotplug_info_ptr->shutdown_done);
|
|
|
|
/* Clean up the hotplug info region for this application */
|
|
bzero(hotplug_info_ptr, sizeof(*hotplug_info_ptr));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* This routine invokes the invoked the cores_added callbacks.
|
|
*/
|
|
int cvmx_app_hotplug_call_add_cores_callback(int index)
|
|
{
|
|
cvmx_app_hotplug_info_t *ai;
|
|
int i;
|
|
if (!(ai = cvmx_app_hotplug_get_info_at_index(index)))
|
|
{
|
|
printf("\nERROR: Failed to get hotplug info for app at index=%d\n", index);
|
|
return -1;
|
|
}
|
|
/* Send IPIs to all application cores to request add_cores callback*/
|
|
for (i=0; i<CVMX_MAX_CORES; i++) {
|
|
if (ai->coremask & (1ull<<i))
|
|
cvmx_write_csr(CVMX_CIU_MBOX_SETX(i), 4);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* This routine sends a request to a running target application
|
|
* to unplug a specified set cores
|
|
* @param index is the index of the target application
|
|
* @param coremask Coremask of the cores to be unplugged from the app.
|
|
* @param wait 1 - Wait for shutdown completion
|
|
* 0 - Do not wait
|
|
* @return 0 on success, -1 on error
|
|
*
|
|
*/
|
|
int cvmx_app_hotplug_unplug_cores(int index, uint32_t coremask, int wait)
|
|
{
|
|
cvmx_app_hotplug_info_t *ai;
|
|
int i;
|
|
|
|
if (!(ai = cvmx_app_hotplug_get_info_at_index(index)))
|
|
{
|
|
printf("\nERROR: Failed to get hotplug info for app at index=%d\n", index);
|
|
return -1;
|
|
}
|
|
ai->unplug_cores = coremask;
|
|
#if 0
|
|
if (!ai->shutdown_callback)
|
|
{
|
|
printf("\nERROR: Target application has not registered for hotplug!\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
if ( (ai->coremask | coremask ) != ai->coremask)
|
|
{
|
|
printf("\nERROR: Not all cores requested are a part of the app "
|
|
"r=%08x:%08x\n", (unsigned int)coremask, (unsigned int)ai->coremask);
|
|
return -1;
|
|
}
|
|
if (ai->coremask == coremask)
|
|
{
|
|
printf("\nERROR: Trying to remove all cores in app. "
|
|
"r=%08x:%08x\n", (unsigned int)coremask, (unsigned int)ai->coremask);
|
|
return -1;
|
|
}
|
|
/* Send IPIs to all application cores to request unplug/remove_cores
|
|
callback */
|
|
for (i=0; i<CVMX_MAX_CORES; i++) {
|
|
if (ai->coremask & (1ull<<i))
|
|
cvmx_write_csr(CVMX_CIU_MBOX_SETX(i), 2);
|
|
}
|
|
|
|
#if 0
|
|
if (wait)
|
|
{
|
|
while (!ai->shutdown_done);
|
|
|
|
/* Clean up the hotplug info region for this application */
|
|
bzero(ai, sizeof(*ai));
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Returns 1 if any app is currently being currently booted , hotplugged or
|
|
* shutdown. Only one app can be under a boot, hotplug or shutdown condition.
|
|
* Before booting an app this methods should be used to check whether boot or
|
|
* shutdown activity is in progress and proceed with the boot or shutdown only
|
|
* when there is no other activity.
|
|
*
|
|
*/
|
|
int is_app_under_boot_or_shutdown(void)
|
|
{
|
|
int ret=0;
|
|
cvmx_app_hotplug_global_t *hgp;
|
|
|
|
hgp = cvmx_app_get_hotplug_global_ptr();
|
|
cvmx_spinlock_lock(&hgp->hotplug_global_lock);
|
|
if (hgp->app_under_boot || hgp->app_under_shutdown) ret=1;
|
|
cvmx_spinlock_unlock(&hgp->hotplug_global_lock);
|
|
return ret;
|
|
|
|
}
|
|
|
|
/**
|
|
* Sets or clear the app_under_boot value. This when set signifies that an app
|
|
* is being currently booted or hotplugged with a new core.
|
|
*
|
|
*
|
|
* @param val sets the app_under_boot to the specified value. This should be
|
|
* set to 1 while app any is being booted and cleared after the
|
|
* application has booted up.
|
|
*
|
|
*/
|
|
void set_app_unber_boot(int val)
|
|
{
|
|
cvmx_app_hotplug_global_t *hgp;
|
|
|
|
hgp = cvmx_app_get_hotplug_global_ptr();
|
|
cvmx_spinlock_lock(&hgp->hotplug_global_lock);
|
|
hgp->app_under_boot = val;
|
|
cvmx_spinlock_unlock(&hgp->hotplug_global_lock);
|
|
}
|
|
|
|
/**
|
|
* Sets or clear the app_under_shutdown value. This when set signifies that an
|
|
* app is being currently shutdown or some cores of an app are being shutdown.
|
|
*
|
|
* @param val sets the app_under_shutdown to the specified value. This
|
|
* should be set to 1 while any app is being shutdown and cleared
|
|
* after the shutdown of the app is complete.
|
|
*
|
|
*/
|
|
void set_app_under_shutdown(int val)
|
|
{
|
|
cvmx_app_hotplug_global_t *hgp;
|
|
|
|
hgp = cvmx_app_get_hotplug_global_ptr();
|
|
cvmx_spinlock_lock(&hgp->hotplug_global_lock);
|
|
hgp->app_under_shutdown = val;
|
|
cvmx_spinlock_unlock(&hgp->hotplug_global_lock);
|
|
}
|