bbus_intr.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/cpu_sgnblk_defs.h>
#include <sys/machsystm.h>
extern void power_down(const char *);
/*
* Support for sgnblk polling.
*/
/* Internal function prototypes */
static void sgnblk_poll_init();
static void sgnblk_poll_handler(void *unused);
#ifdef THROTTLE
#endif /* THROTTLE */
/* Default sgnblk polling interval is every 5 seconds. */
#ifdef THROTTLE
#else /* THROTTLE */
/*
* Until we can find a way to throttle back to 0.5 second intervals
* we're stuck fixed on 2.5 second intervals.
*/
#endif /* THROTTLE */
#define MAX_SGNBLK_POLL_CLNT 5
void (*pollclntfunc[MAX_SGNBLK_POLL_CLNT])();
/*
* sgnblk_mutex Protects juggling & sgnblk_poll_refs[].
* sgnblk_poll_mutex Protects pollclntfunc[].
*/
#ifdef THROTTLE
#endif /* THROTTLE */
/*
* Note that the sigblock polling depends on CY_HIGH_LEVEL
* being higher than PIL_13 since we ultimately need to
* dispatch a PIL_13 soft handler.
* Also, we assume one sgnblk handler for the entire system.
* Once upon a time we had them per-cpu. With the Cyclic stuff
* we would have to bind our cyclic handler to a cpu and doing
* this prevents that cpu from being offlined. Since the Cyclic
* subsystem could indirectly juggle us without us knowing we
* have to assume we're running from any possible cpu and not
* always SIGBCPU.
*/
#ifdef THROTTLE
#endif /* THROTTLE */
static cyc_handler_t sgnblk_poll_cychandler = {
NULL,
};
static cyc_time_t sgnblk_poll_time;
/*
* Anybody that references the polling (SIGBCPU) can
* register a callback function that will be called if
* the polling cpu is juggled, e.g. during a DR operation.
*/
#define MAX_SGNBLK_POLL_REFS 10
struct sgnblk_poll_refs {
void *arg;
/*
* interrupt requests initiated via the hw bootbus intr
* mechanism. This is similar to the level15
* interrupt handling for sigb commands in the CS6400.
* Most of these code were stolen from the sigb stuff in
* in CS6400.
*/
/*ARGSUSED*/
static uint_t
{
int cmd = 0;
int retflag;
int resp = 0;
/*
* Check for unsolicited messages in the host's mailbox.
*/
switch (retflag) {
case CBS_TO_HOST:
break;
default:
break;
}
if (retflag == SIGB_MBOX_EMPTY)
return (0); /* interrupt not claimed */
/*
* We only look for UNSOLICITED messages, i.e. commands.
* Responses to these commands are returned into the same
* mailbox from which the command was received, i.e. host's.
*
* If the host should solicit a message from the SSP, that
* The responses (from the SSP) to these messages will be
* read from the ssp mailbox by whomever solicited it, but
* will NOT be handled through this level 15 interrupt
* mechanism.
*
* Note that use of the flag field of the signature block mailbox
* structure and the mailbox protocol itself, serializes access
* to these mailboxes.
*/
resp = 0;
/*
* The first sizeof (uint_t) bytes of the data field
* is the command.
*/
switch (cmd) {
case SSP_GOTO_OBP:
/*
* Let's set the mailbox flag to BUSY while we are in OBP
*/
debug_enter("SSP requested (SSP_GOTO_OBP)");
/*
* This command does NOT require a response.
*/
resp = 0;
break;
case SSP_GOTO_PANIC:
/*
* Let's reset the mailbox flag before we bail.
*/
/* should never reach this point */
resp = 0;
break;
case SSP_ENVIRON:
/*
* Environmental Interrupt.
*/
/*
* Send SIGPWR to init(1) it will run rc0, which will uadmin to
* powerdown.
*/
/*
* If we're still booting and init(1) isn't set up yet,
* simply halt.
*/
extern void halt(char *);
power_down((char *)NULL);
}
/*
* else, graceful shutdown with inittab and all getting involved
*
* XXX: Do we Need to modify the init process for the Cray 6400!
*/
/*
* when we return from psignal.
*
* cmn_err(CE_PANIC, "SSP requested (SSP_ENVIRON)\n");
* should never reach this point
*/
resp = 0;
break;
/*
* Could handle more mailbox commands right here.
*/
default:
break;
}
/*
* If resp is non-zero then we'll automatically reset
* the handler_sigb lock once we've sent the response,
* however if no response is needed, then resetlck must
* be set so that the handler_sigb lock is reset.
*/
if (resp != 0) {
/*
* Had some kind of trouble handling the mailbox
* command. Need to send back an error response
* and back out of the cpu_sgnblk handling.
*/
sizeof (cmd));
} else {
/*
* No response expected, but we still have to
* reset the flag to empty for the next person.
*/
}
return (1); /* interrupt claimed */
}
void
{
/*
* Starfire's ASIC have the capability to generate a mondo
* vector. The SSP uses this capability via the Boot Bus to
* send an interrupt to a domain.
*
* The SSP generates a mondo with:
* ign = UPAID_TO_IGN(bootcpu_upaid)
* ino = 0
*
* An interrupt handler is added for this inum.
*/
/*
* Due to a HW flaw in starfire, liberal use
* of bootbus intrs under heavy system load
* may cause the machine to arbstop. The workaround
* is to provide a polling mechanism thru the signature
* block interface to allow another way for the SSP to
* interrupt the host. Applications like IDN which generate
* a high degree of SSP to host interruptions for
* synchronization will need to use the polling facility
* instead of the hw bootbus interrupt mechanism.
* The HW bootbus intr support is left intact as it
* will still be used by existing SSP applications for system
* recovery in the event of system hangs etc.. In such situations,
* HW bootbus intr is a better mechanism as it is HW generated
* level 15 interrupt that has a better chance of kicking
* a otherwise hung OS into recovery.
*
* Polling is done by scheduling a constant tick timer
* interrupt at a certain predefined interval.
* The handler will do a poll and if there is a
* "intr" request, scheduled a soft level 13 intr
* to handle it. Allocate the inum for the level
* 13 intr here.
*/
}
static void
{
#ifdef THROTTLE
#else /* THROTTLE */
#endif /* THROTTLE */
}
int
{
int i;
/*
* See if we need to initialize
* sgnblk polling
*/
if (sgnblk_pollcpu == -1)
/*
* Look for a empty slot
*/
for (i = 0; i < MAX_SGNBLK_POLL_CLNT; i++) {
if (pollclntfunc[i] == NULL) {
pollclntfunc[i] = func;
return (1);
}
}
return (0); /* failed */
}
int
{
int i;
/*
* Look for the slot matching the function passed in.
*/
for (i = 0; i < MAX_SGNBLK_POLL_CLNT; i++) {
if (pollclntfunc[i] == func) {
pollclntfunc[i] = NULL;
return (1);
}
}
return (0); /* failed */
}
/*
* For DR support.
* Juggle poll tick client to another cpu
* Assumed to be called single threaded.
*/
void
{
int i;
if (sgnblk_pollcpu == -1 ||
return;
}
/*
* Disable by simply returning here
* Passing a null cp is assumed to be
* sgnpoll disable request.
*/
for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) {
}
}
return;
}
for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) {
}
}
}
#ifdef THROTTLE
/*ARGSUSED0*/
static void
_sgnblk_poll_throttle(void *unused)
{
if (sgnblk_poll_cycid != CYCLIC_NONE) {
}
}
/*
* We don't want to remove the cyclic within the context of
* the handler so we kick off the throttle in background
* via a timeout call.
*/
static void
{
}
#endif /* THROTTLE */
/*
* High priority interrupt handler (PIL_14)
* for signature block mbox polling.
*/
/*ARGSUSED0*/
static void
sgnblk_poll_handler(void *unused)
{
#ifdef THROTTLE
static uint64_t sb_interval = 0;
#endif /* THROTTLE */
return;
/*
* Poll for SSP requests
*/
/* reset the flag - sure hope this is atomic */
#ifdef THROTTLE
/*
* Go into fast poll mode for a short duration
* (SGNBLK_POLL_FAST_WIN) in SGNBLK_POLL_FAST interval.
* The assumption here is that we just got activity
* on the mbox poll, the probability of more coming down
* the pipe is high - so let's look more often.
*/
}
#endif /* THROTTLE */
/* schedule poll processing */
#ifdef THROTTLE
} else if (sb_window >= 0) {
/* Revert to slow polling once fast window ends */
if ((--sb_window < 0) &&
(sb_interval < sgnblk_poll_interval)) {
}
#endif /* THROTTLE */
}
}
/*ARGSUSED*/
static uint_t
{
int i;
/*
* Go thru the poll client array and call the
* poll client functions one by one
*/
for (i = 0; i < MAX_SGNBLK_POLL_CLNT; i++) {
}
}
return (1);
}
int
void *arg)
{
int i, slot;
return (-1);
/*
* First verify caller is not already registered.
*/
slot = -1;
for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) {
slot = i;
continue;
}
return (-1);
}
}
/*
* Now find an empty entry.
*/
if (slot == -1) {
return (-1);
}
return (0);
}
void
{
int i;
for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) {
void *arg;
break;
}
}
}