1
0
Files
irix-657m-src/irix/kern/cell/cell.c
2022-09-29 17:59:04 +03:00

321 lines
7.2 KiB
C

/**************************************************************************
* *
* Copyright (C) 1994-1996 Silicon Graphics, Inc. *
* *
* These coded instructions, statements, and computer programs contain *
* unpublished proprietary information of Silicon Graphics, Inc., and *
* are protected by Federal copyright law. They may not be disclosed *
* to third parties or copied or duplicated in any form, in whole or *
* in part, without the prior written consent of Silicon Graphics, Inc. *
* *
**************************************************************************/
#include <sys/debug.h>
#include <sys/types.h>
#include <sys/atomic_ops.h>
#include <sys/systm.h>
#include <ksys/cell.h>
#include <ksys/sthread.h>
#include <ksys/cell/tkm.h>
#include <ksys/cell/mesg.h>
#include <ksys/cell/cell_hb.h>
#include <ksys/cell/membership.h>
#include <ksys/partition.h>
#include <ksys/cell/recovery.h>
#include <sys/cmn_err.h>
/*
* Global data for the Cell module itself.
*/
short kdebug_running = 0; /* if set then idbg is running */
cell_t golden_cell = 0; /* 'golden_cell' may not be shutdown */
cell_t my_cellid = 0; /* Set before boot, returned by cellid() */
/*
* Cell private variables.
*/
static volatile int cell_initted;
volatile int allowcells;
#ifdef DEBUG
/*
* Cell test stuff to send a receive a test message using
* syssgi.
*/
#include "ksys/cell/subsysid.h"
#include "I_cell_test_stubs.h"
#include "invk_cell_test_stubs.h"
sv_t cell_test_sv;
lock_t cell_test_lock;
#endif
/*
* Called once on each cpu to initialize the cell private data & join
* a particular cell.
*
* It's important that cpus come here before allocating any memory
* since its here that they get a cell identity and therefore
* can access cell private memory and allocate cell specific virtual
* memory.
*
* WARNING - in this routine - use 'cellid' NOT cellid().
* NOTE - we aren't called with any thread identity
* so the only reason we can access cell private data is that cellda() uses
* private.p_cellid when there is no thread, and we set that up here FIRST.
*/
void
cell_cpu_init(void)
{
cell_t cellid;
int rv;
/*
* init our cellid ....
* XXX currently a simple split of cpus -> cells
* Once we assign p_cellid we can access cell private data.
*/
#if defined(EVEREST) && defined(MULTIKERNEL)
cellid = evmk_cellid;
#else /* !EVEREST || !MULTIKERNEL */
cellid = 0; /* CELLBAD - need to get cellid. */
#endif /* !EVEREST || !MULTIKERNEL */
/* Assign this cpu's pda to cell's pdaindr */
pdaindr[cpuid()].pda = pdaindr[cpuid()].pda;
pdaindr[cpuid()].CpuId = cpuid();
/*
* All cells come up with all cpus running so we have to
* synchronize.
*/
rv = test_and_set_int((int *)&cell_initted, 2); /* returns old value */
if (rv == 2) {
/* someone else initializing - wait */
while (cell_initted == 2)
;
return;
} else if (rv == 1) {
cell_initted = 1;
return;
}
/*
* Only one cpu per cell gets to this point.
*/
/*
* Special hack for cpu 0 / cell 0 - per-cell initialization
* called as part of mainline initialization, so it doesn't
* have to be done here -> i.e., just return.
*/
#ifdef MULTIKERNEL
if (cpuid() == 0) {
#else
if (cpuid() == master_procid) {
#endif
ASSERT(cellid == 0);
allowcells = 1;
cell_initted = 1; /* well, not really */
return;
}
/*
* Perform per-cell initialization, but must wait for cpu 0 to
* do the mainline initialization.
*/
while (!allowcells)
#if defined(EVEREST) && defined(MULTIKERNEL)
/* need to import this here since an evmk_replicate() from
* master cell does not work (allowcells is in BSS and gets
* explicitly zeroed by non-golden cell master cpu).
* So import it from golden cell.
*/
if (evmk_cellid != evmk_golden_cellid) {
evmk_import( evmk_golden_cellid, (void*)&allowcells,
sizeof(allowcells));
}
#endif
;
#if defined(EVEREST) && defined(MULTIKERNEL)
if ((evmk_cellid == cpuid()) && (evmk_cellid != evmk.golden_cellid))
cell_initted = 1;
#endif /* EVEREST && MULTIKERNEL */
/*
* Wait for cell_init_one() to be executed for this cpu's cell.
*/
while (cell_initted != 1) {
#if DEBUG
if (kdebug) du_conpoll();
#endif
}
/*
* Let the game begin!
*/
}
/*
* cell_up_init:
* Enable new cell notifications. This is a separate
* init routine. Its called after the subsystems which are interested
* in knowing when cells come up have been initted. For now these are
* heart beat and messaging subsystems.
*/
void
cell_up_init()
{
part_register_handlers(cell_up, cell_down);
#ifdef DEBUG
mesg_handler_register(cell_test_msg_dispatcher, CELL_TEST_SUBSYSID);
sv_init(&cell_test_sv, SV_DEFAULT, "Cell test sv");
init_spinlock(&cell_test_lock, "Cell test lock", 0);
#endif
}
/*
* Generic cell backoff. Used when a client is asked to wait for a
* previous server response. It backs off relative to the number
* iterations it has been waiting.
*/
void
cell_backoff(int iter)
{
timespec_t lookup_delay;
if (iter > 10) {
lookup_delay.tv_sec = 0;
/* 10s of uS */
lookup_delay.tv_nsec = (iter * 10) * 1000;
nano_delay(&lookup_delay);
}
}
void
cell_down(partid_t part)
{
cell_t cell;
cell = PARTID_TO_CELLID(part);
cms_notify_cell(cell, B_FALSE);
#ifdef DEBUG
cmn_err(CE_NOTE,
"WARNING: cell %d has gone down\n", PARTID_TO_CELLID(part));
#endif
/*
* Disconnect any channels.
*/
if (cell != cellid()) {
mesg_disconnect(cell, MESG_CHANNEL_MAIN);
mesg_disconnect(cell, MESG_CHANNEL_MEMBERSHIP);
}
}
void
cell_up(partid_t part)
{
cell_t cell;
cell = PARTID_TO_CELLID(part);
if (cell != cellid()) {
if (!mesg_connect(cell, MESG_CHANNEL_MEMBERSHIP))
panic("cell_up: No membership message channel");
mesg_channel_set_state(cell, MESG_CHANNEL_MEMBERSHIP,
MESG_CHAN_READY);
cms_notify_cell(cell, B_TRUE);
}
}
/*
* Called by the membership services to connect cells together
* Returns B_FALSE on failure and B_TRUE on success.
*/
boolean_t
cell_connect(cell_t cell)
{
if (cell != cellid()) {
if (!mesg_connect(cell, MESG_CHANNEL_MAIN))
return B_FALSE;
if (!hb_add_cell(cell))
return B_TRUE;
}
return B_TRUE;
}
void
cell_disconnect(cell_t cell)
{
if (cell != cellid()) {
mesg_channel_set_state(cell, MESG_CHANNEL_MAIN,
MESG_CHAN_CLOSED);
mesg_disconnect(cell, MESG_CHANNEL_MAIN);
hb_remove_cell(cell);
}
}
#ifdef DEBUG
void
cell_test_mesg(cell_t cell)
{
service_t svc;
int error;
SERVICE_MAKE(svc, cell, SVC_CELL_TEST);
error = invk_cell_test_mesg_send(svc, cell);
printf("Invk returns error %d\n", error);
}
int cell_test_first_time = 1;
/* ARGSUSED */
int
I_cell_test_mesg_send(cell_t cell)
{
int spl;
spl = mutex_spinlock(&cell_test_lock);
if (sv_wait_sig(&cell_test_sv, PZERO|PLTWAIT, &cell_test_lock, spl)) {
cmn_err(CE_CONT,"Sv wait sig. Interrupted thread for "
"cell %d\n", cell);
return 1;
}
return 0;
}
#include "sys/pda.h"
void cell_cpu_spin(void);
void
cell_cpu_spin()
{
splhi();
for(;;) ;
}
void
cell_suicide()
{
cpuid_t cpu;
for (cpu = 0; cpu < maxcpus; cpu++) {
if (!cpu_enabled(cpu))
continue;
if (cpu == cpuid())
continue;
cpuaction(cpu, (cpuacfunc_t)cell_cpu_spin, A_NOW);
}
cell_cpu_spin();
}
#endif