10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*2973Sgovinda * Common Development and Distribution License (the "License").
6*2973Sgovinda * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*2973Sgovinda * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/kmem.h>
310Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h>
320Sstevel@tonic-gate #include <vm/seg.h>
330Sstevel@tonic-gate #include <sys/iommu.h>
340Sstevel@tonic-gate #include <sys/vtrace.h>
350Sstevel@tonic-gate #include <sys/intreg.h>
360Sstevel@tonic-gate #include <sys/ivintr.h>
370Sstevel@tonic-gate #include <sys/cpuvar.h>
380Sstevel@tonic-gate #include <sys/systm.h>
390Sstevel@tonic-gate #include <sys/machsystm.h>
400Sstevel@tonic-gate #include <sys/cyclic.h>
410Sstevel@tonic-gate #include <sys/cpu_sgn.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate extern cpu_sgnblk_t *cpu_sgnblkp[NCPU];
440Sstevel@tonic-gate extern struct cpu *SIGBCPU;
450Sstevel@tonic-gate extern void power_down(const char *);
460Sstevel@tonic-gate
470Sstevel@tonic-gate uint_t bbus_intr_inum;
48*2973Sgovinda uint64_t bbus_poll_inum;
490Sstevel@tonic-gate
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate * Support for sgnblk polling.
520Sstevel@tonic-gate */
530Sstevel@tonic-gate
540Sstevel@tonic-gate /* Internal function prototypes */
550Sstevel@tonic-gate static void sgnblk_poll_init();
560Sstevel@tonic-gate static uint_t bbus_poll(caddr_t arg1, caddr_t arg2);
570Sstevel@tonic-gate static void sgnblk_poll_handler(void *unused);
580Sstevel@tonic-gate #ifdef THROTTLE
590Sstevel@tonic-gate static void sgnblk_poll_throttle(uint64_t interval);
600Sstevel@tonic-gate #endif /* THROTTLE */
610Sstevel@tonic-gate
620Sstevel@tonic-gate /* Default sgnblk polling interval is every 5 seconds. */
630Sstevel@tonic-gate #define ONE_SECOND (1000000) /* in usecs */
640Sstevel@tonic-gate #ifdef THROTTLE
650Sstevel@tonic-gate #define SGNBLK_POLL_INTERVAL (5 * ONE_SECOND)
660Sstevel@tonic-gate #define SGNBLK_POLL_FAST (ONE_SECOND >> 1)
670Sstevel@tonic-gate #define SGNBLK_POLL_FAST_WIN ((60 * ONE_SECOND) / \
680Sstevel@tonic-gate SGNBLK_POLL_FAST)
690Sstevel@tonic-gate #else /* THROTTLE */
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate * Until we can find a way to throttle back to 0.5 second intervals
720Sstevel@tonic-gate * we're stuck fixed on 2.5 second intervals.
730Sstevel@tonic-gate */
740Sstevel@tonic-gate #define SGNBLK_POLL_INTERVAL ((2 * ONE_SECOND) + (ONE_SECOND >> 1))
750Sstevel@tonic-gate #endif /* THROTTLE */
760Sstevel@tonic-gate
770Sstevel@tonic-gate #define MAX_SGNBLK_POLL_CLNT 5
780Sstevel@tonic-gate
790Sstevel@tonic-gate void (*pollclntfunc[MAX_SGNBLK_POLL_CLNT])();
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate * sgnblk_mutex Protects juggling & sgnblk_poll_refs[].
820Sstevel@tonic-gate * sgnblk_poll_mutex Protects pollclntfunc[].
830Sstevel@tonic-gate */
840Sstevel@tonic-gate kmutex_t sgnblk_mutex;
850Sstevel@tonic-gate kmutex_t sgnblk_poll_mutex;
860Sstevel@tonic-gate static uint64_t sgnblk_poll_interval = SGNBLK_POLL_INTERVAL;
870Sstevel@tonic-gate #ifdef THROTTLE
880Sstevel@tonic-gate static uint64_t sgnblk_poll_fast = SGNBLK_POLL_FAST;
890Sstevel@tonic-gate static int64_t sgnblk_poll_fast_win = SGNBLK_POLL_FAST_WIN;
900Sstevel@tonic-gate #endif /* THROTTLE */
910Sstevel@tonic-gate static processorid_t sgnblk_pollcpu = -1;
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate * Note that the sigblock polling depends on CY_HIGH_LEVEL
940Sstevel@tonic-gate * being higher than PIL_13 since we ultimately need to
950Sstevel@tonic-gate * dispatch a PIL_13 soft handler.
960Sstevel@tonic-gate * Also, we assume one sgnblk handler for the entire system.
970Sstevel@tonic-gate * Once upon a time we had them per-cpu. With the Cyclic stuff
980Sstevel@tonic-gate * we would have to bind our cyclic handler to a cpu and doing
990Sstevel@tonic-gate * this prevents that cpu from being offlined. Since the Cyclic
1000Sstevel@tonic-gate * subsystem could indirectly juggle us without us knowing we
1010Sstevel@tonic-gate * have to assume we're running from any possible cpu and not
1020Sstevel@tonic-gate * always SIGBCPU.
1030Sstevel@tonic-gate */
1040Sstevel@tonic-gate #ifdef THROTTLE
1050Sstevel@tonic-gate static cyclic_id_t sgnblk_poll_cycid = CYCLIC_NONE;
1060Sstevel@tonic-gate #endif /* THROTTLE */
1070Sstevel@tonic-gate static cyc_handler_t sgnblk_poll_cychandler = {
1080Sstevel@tonic-gate sgnblk_poll_handler,
1090Sstevel@tonic-gate NULL,
1100Sstevel@tonic-gate CY_HIGH_LEVEL
1110Sstevel@tonic-gate };
1120Sstevel@tonic-gate static cyc_time_t sgnblk_poll_time;
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate /*
1150Sstevel@tonic-gate * Anybody that references the polling (SIGBCPU) can
1160Sstevel@tonic-gate * register a callback function that will be called if
1170Sstevel@tonic-gate * the polling cpu is juggled, e.g. during a DR operation.
1180Sstevel@tonic-gate */
1190Sstevel@tonic-gate #define MAX_SGNBLK_POLL_REFS 10
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate struct sgnblk_poll_refs {
1220Sstevel@tonic-gate void (*callback)(cpu_sgnblk_t *sigbp, void *arg);
1230Sstevel@tonic-gate void *arg;
1240Sstevel@tonic-gate } sgnblk_poll_refs[MAX_SGNBLK_POLL_REFS];
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate * Bootbus intr handler: Generic handler for all SSP/CBS
1280Sstevel@tonic-gate * interrupt requests initiated via the hw bootbus intr
1290Sstevel@tonic-gate * mechanism. This is similar to the level15
1300Sstevel@tonic-gate * interrupt handling for sigb commands in the CS6400.
1310Sstevel@tonic-gate * Most of these code were stolen from the sigb stuff in
1320Sstevel@tonic-gate * in CS6400.
1330Sstevel@tonic-gate */
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate extern struct cpu cpu0;
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate /*ARGSUSED*/
1380Sstevel@tonic-gate static uint_t
bbus_intr(caddr_t arg)1390Sstevel@tonic-gate bbus_intr(caddr_t arg)
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate int cmd = 0;
1420Sstevel@tonic-gate processorid_t cpu_id = CPU->cpu_id;
1430Sstevel@tonic-gate int retflag;
1440Sstevel@tonic-gate int resp = 0;
1450Sstevel@tonic-gate proc_t *initpp;
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate ASSERT(cpu_sgnblkp[cpu_id] != NULL);
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate * Check for unsolicited messages in the host's mailbox.
1510Sstevel@tonic-gate */
1520Sstevel@tonic-gate retflag = cpu_sgnblkp[cpu_id]->sigb_host_mbox.flag;
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate switch (retflag) {
1550Sstevel@tonic-gate case CBS_TO_HOST:
1560Sstevel@tonic-gate retflag = HOST_TO_CBS;
1570Sstevel@tonic-gate break;
1580Sstevel@tonic-gate default:
1590Sstevel@tonic-gate retflag = SIGB_MBOX_EMPTY;
1600Sstevel@tonic-gate break;
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate if (retflag == SIGB_MBOX_EMPTY)
1630Sstevel@tonic-gate return (0); /* interrupt not claimed */
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate * We only look for UNSOLICITED messages, i.e. commands.
1670Sstevel@tonic-gate * Responses to these commands are returned into the same
1680Sstevel@tonic-gate * mailbox from which the command was received, i.e. host's.
1690Sstevel@tonic-gate *
1700Sstevel@tonic-gate * If the host should solicit a message from the SSP, that
1710Sstevel@tonic-gate * message/command goes into the SSP's mailbox (sigb_ssp_mbox).
1720Sstevel@tonic-gate * The responses (from the SSP) to these messages will be
1730Sstevel@tonic-gate * read from the ssp mailbox by whomever solicited it, but
1740Sstevel@tonic-gate * will NOT be handled through this level 15 interrupt
1750Sstevel@tonic-gate * mechanism.
1760Sstevel@tonic-gate *
1770Sstevel@tonic-gate * Note that use of the flag field of the signature block mailbox
1780Sstevel@tonic-gate * structure and the mailbox protocol itself, serializes access
1790Sstevel@tonic-gate * to these mailboxes.
1800Sstevel@tonic-gate */
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate resp = 0;
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate * The first sizeof (uint_t) bytes of the data field
1860Sstevel@tonic-gate * is the command.
1870Sstevel@tonic-gate */
1880Sstevel@tonic-gate cmd = cpu_sgnblkp[cpu_id]->sigb_host_mbox.cmd;
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate switch (cmd) {
1910Sstevel@tonic-gate case SSP_GOTO_OBP:
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate * Let's set the mailbox flag to BUSY while we are in OBP
1940Sstevel@tonic-gate */
1950Sstevel@tonic-gate cpu_sgnblkp[cpu_id]->sigb_host_mbox.flag = SIGB_MBOX_BUSY;
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate debug_enter("SSP requested (SSP_GOTO_OBP)");
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * This command does NOT require a response.
2000Sstevel@tonic-gate */
2010Sstevel@tonic-gate resp = 0;
2020Sstevel@tonic-gate break;
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate case SSP_GOTO_PANIC:
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate * Let's reset the mailbox flag before we bail.
2070Sstevel@tonic-gate */
2080Sstevel@tonic-gate cpu_sgnblkp[cpu_id]->sigb_host_mbox.flag = SIGB_MBOX_EMPTY;
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate cmn_err(CE_PANIC, "SSP requested (SSP_GOTO_PANIC)\n");
2110Sstevel@tonic-gate /* should never reach this point */
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate resp = 0;
2140Sstevel@tonic-gate break;
2150Sstevel@tonic-gate case SSP_ENVIRON:
2160Sstevel@tonic-gate /*
2170Sstevel@tonic-gate * Environmental Interrupt.
2180Sstevel@tonic-gate */
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate /*
2210Sstevel@tonic-gate * Send SIGPWR to init(1) it will run rc0, which will uadmin to
2220Sstevel@tonic-gate * powerdown.
2230Sstevel@tonic-gate */
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate mutex_enter(&pidlock);
2260Sstevel@tonic-gate initpp = prfind(P_INITPID);
2270Sstevel@tonic-gate mutex_exit(&pidlock);
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate /*
2300Sstevel@tonic-gate * If we're still booting and init(1) isn't set up yet,
2310Sstevel@tonic-gate * simply halt.
2320Sstevel@tonic-gate */
2330Sstevel@tonic-gate if (initpp == NULL) {
2340Sstevel@tonic-gate extern void halt(char *);
2350Sstevel@tonic-gate cmn_err(CE_WARN, "?Environmental Interrupt");
2360Sstevel@tonic-gate power_down((char *)NULL);
2370Sstevel@tonic-gate halt("Power off the System!\n"); /* just in case */
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate /*
2410Sstevel@tonic-gate * else, graceful shutdown with inittab and all getting involved
2420Sstevel@tonic-gate *
2430Sstevel@tonic-gate * XXX: Do we Need to modify the init process for the Cray 6400!
2440Sstevel@tonic-gate */
2450Sstevel@tonic-gate psignal(initpp, SIGPWR);
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate /*
2480Sstevel@tonic-gate * XXX: kick off a sanity timeout panic in case the /etc/inittab
2490Sstevel@tonic-gate * or /etc/rc0 files are hosed. The 6400 needs to hang here
2500Sstevel@tonic-gate * when we return from psignal.
2510Sstevel@tonic-gate *
2520Sstevel@tonic-gate * cmn_err(CE_PANIC, "SSP requested (SSP_ENVIRON)\n");
2530Sstevel@tonic-gate * should never reach this point
2540Sstevel@tonic-gate */
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate resp = 0;
2570Sstevel@tonic-gate break;
2580Sstevel@tonic-gate /*
2590Sstevel@tonic-gate * Could handle more mailbox commands right here.
2600Sstevel@tonic-gate */
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate default:
2630Sstevel@tonic-gate resp = SIGB_BAD_MBOX_CMD;
2640Sstevel@tonic-gate break;
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate /*
2680Sstevel@tonic-gate * If resp is non-zero then we'll automatically reset
2690Sstevel@tonic-gate * the handler_sigb lock once we've sent the response,
2700Sstevel@tonic-gate * however if no response is needed, then resetlck must
2710Sstevel@tonic-gate * be set so that the handler_sigb lock is reset.
2720Sstevel@tonic-gate */
2730Sstevel@tonic-gate if (resp != 0) {
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate * Had some kind of trouble handling the mailbox
2760Sstevel@tonic-gate * command. Need to send back an error response
2770Sstevel@tonic-gate * and back out of the cpu_sgnblk handling.
2780Sstevel@tonic-gate */
2790Sstevel@tonic-gate cpu_sgnblkp[cpu_id]->sigb_host_mbox.cmd = resp;
2800Sstevel@tonic-gate bcopy((caddr_t)&cmd,
2810Sstevel@tonic-gate (caddr_t)&cpu_sgnblkp[cpu_id]->sigb_host_mbox.data[0],
2820Sstevel@tonic-gate sizeof (cmd));
2830Sstevel@tonic-gate cpu_sgnblkp[cpu_id]->sigb_host_mbox.flag = retflag;
2840Sstevel@tonic-gate } else {
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate * No response expected, but we still have to
2870Sstevel@tonic-gate * reset the flag to empty for the next person.
2880Sstevel@tonic-gate */
2890Sstevel@tonic-gate cpu_sgnblkp[cpu_id]->sigb_host_mbox.flag = SIGB_MBOX_EMPTY;
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate return (1); /* interrupt claimed */
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate void
register_bbus_intr()2950Sstevel@tonic-gate register_bbus_intr()
2960Sstevel@tonic-gate {
2970Sstevel@tonic-gate /*
2980Sstevel@tonic-gate * Starfire's ASIC have the capability to generate a mondo
2990Sstevel@tonic-gate * vector. The SSP uses this capability via the Boot Bus to
3000Sstevel@tonic-gate * send an interrupt to a domain.
3010Sstevel@tonic-gate *
3020Sstevel@tonic-gate * The SSP generates a mondo with:
3030Sstevel@tonic-gate * ign = UPAID_TO_IGN(bootcpu_upaid)
3040Sstevel@tonic-gate * ino = 0
3050Sstevel@tonic-gate *
3060Sstevel@tonic-gate * An interrupt handler is added for this inum.
3070Sstevel@tonic-gate */
3080Sstevel@tonic-gate bbus_intr_inum = UPAID_TO_IGN(cpu0.cpu_id) * MAX_INO;
309*2973Sgovinda VERIFY(add_ivintr(bbus_intr_inum, PIL_13, (intrfunc)bbus_intr,
310*2973Sgovinda NULL, NULL, NULL) == 0);
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate /*
3140Sstevel@tonic-gate * Due to a HW flaw in starfire, liberal use
3150Sstevel@tonic-gate * of bootbus intrs under heavy system load
3160Sstevel@tonic-gate * may cause the machine to arbstop. The workaround
3170Sstevel@tonic-gate * is to provide a polling mechanism thru the signature
3180Sstevel@tonic-gate * block interface to allow another way for the SSP to
3190Sstevel@tonic-gate * interrupt the host. Applications like IDN which generate
3200Sstevel@tonic-gate * a high degree of SSP to host interruptions for
3210Sstevel@tonic-gate * synchronization will need to use the polling facility
3220Sstevel@tonic-gate * instead of the hw bootbus interrupt mechanism.
3230Sstevel@tonic-gate * The HW bootbus intr support is left intact as it
3240Sstevel@tonic-gate * will still be used by existing SSP applications for system
3250Sstevel@tonic-gate * recovery in the event of system hangs etc.. In such situations,
3260Sstevel@tonic-gate * HW bootbus intr is a better mechanism as it is HW generated
3270Sstevel@tonic-gate * level 15 interrupt that has a better chance of kicking
3280Sstevel@tonic-gate * a otherwise hung OS into recovery.
3290Sstevel@tonic-gate *
3300Sstevel@tonic-gate * Polling is done by scheduling a constant tick timer
3310Sstevel@tonic-gate * interrupt at a certain predefined interval.
3320Sstevel@tonic-gate * The handler will do a poll and if there is a
3330Sstevel@tonic-gate * "intr" request, scheduled a soft level 13 intr
3340Sstevel@tonic-gate * to handle it. Allocate the inum for the level
3350Sstevel@tonic-gate * 13 intr here.
3360Sstevel@tonic-gate */
337*2973Sgovinda bbus_poll_inum = add_softintr(PIL_13, bbus_poll, 0, SOFTINT_ST);
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate static void
sgnblk_poll_init()3410Sstevel@tonic-gate sgnblk_poll_init()
3420Sstevel@tonic-gate {
3430Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sgnblk_mutex));
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate mutex_init(&sgnblk_poll_mutex, NULL,
3460Sstevel@tonic-gate MUTEX_SPIN, (void *)ipltospl(PIL_14));
3470Sstevel@tonic-gate sgnblk_pollcpu = SIGBCPU->cpu_id;
3480Sstevel@tonic-gate mutex_enter(&cpu_lock);
3490Sstevel@tonic-gate sgnblk_poll_time.cyt_when = 0ull;
3500Sstevel@tonic-gate sgnblk_poll_time.cyt_interval = sgnblk_poll_interval * 1000ull;
3510Sstevel@tonic-gate #ifdef THROTTLE
3520Sstevel@tonic-gate sgnblk_poll_cycid = cyclic_add(&sgnblk_poll_cychandler,
3530Sstevel@tonic-gate &sgnblk_poll_time);
3540Sstevel@tonic-gate #else /* THROTTLE */
3550Sstevel@tonic-gate (void) cyclic_add(&sgnblk_poll_cychandler, &sgnblk_poll_time);
3560Sstevel@tonic-gate #endif /* THROTTLE */
3570Sstevel@tonic-gate mutex_exit(&cpu_lock);
3580Sstevel@tonic-gate ASSERT(sgnblk_pollcpu == SIGBCPU->cpu_id);
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate int
sgnblk_poll_register(void (* func)(processorid_t cpu_id,cpu_sgnblk_t * cpu_sgnblkp))3620Sstevel@tonic-gate sgnblk_poll_register(void(*func)(processorid_t cpu_id,
3630Sstevel@tonic-gate cpu_sgnblk_t *cpu_sgnblkp))
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate int i;
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate /*
3680Sstevel@tonic-gate * See if we need to initialize
3690Sstevel@tonic-gate * sgnblk polling
3700Sstevel@tonic-gate */
3710Sstevel@tonic-gate mutex_enter(&sgnblk_mutex);
3720Sstevel@tonic-gate if (sgnblk_pollcpu == -1)
3730Sstevel@tonic-gate sgnblk_poll_init();
3740Sstevel@tonic-gate mutex_exit(&sgnblk_mutex);
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate mutex_enter(&sgnblk_poll_mutex);
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate /*
3790Sstevel@tonic-gate * Look for a empty slot
3800Sstevel@tonic-gate */
3810Sstevel@tonic-gate for (i = 0; i < MAX_SGNBLK_POLL_CLNT; i++) {
3820Sstevel@tonic-gate if (pollclntfunc[i] == NULL) {
3830Sstevel@tonic-gate pollclntfunc[i] = func;
3840Sstevel@tonic-gate mutex_exit(&sgnblk_poll_mutex);
3850Sstevel@tonic-gate return (1);
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate mutex_exit(&sgnblk_poll_mutex);
3890Sstevel@tonic-gate return (0); /* failed */
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate int
sgnblk_poll_unregister(void (* func)(processorid_t cpu_id,cpu_sgnblk_t * cpu_sgnblkp))3930Sstevel@tonic-gate sgnblk_poll_unregister(void(*func)(processorid_t cpu_id,
3940Sstevel@tonic-gate cpu_sgnblk_t *cpu_sgnblkp))
3950Sstevel@tonic-gate {
3960Sstevel@tonic-gate int i;
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate mutex_enter(&sgnblk_poll_mutex);
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate /*
4010Sstevel@tonic-gate * Look for the slot matching the function passed in.
4020Sstevel@tonic-gate */
4030Sstevel@tonic-gate for (i = 0; i < MAX_SGNBLK_POLL_CLNT; i++) {
4040Sstevel@tonic-gate if (pollclntfunc[i] == func) {
4050Sstevel@tonic-gate pollclntfunc[i] = NULL;
4060Sstevel@tonic-gate mutex_exit(&sgnblk_poll_mutex);
4070Sstevel@tonic-gate return (1);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate mutex_exit(&sgnblk_poll_mutex);
4110Sstevel@tonic-gate return (0); /* failed */
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate /*
4160Sstevel@tonic-gate * For DR support.
4170Sstevel@tonic-gate * Juggle poll tick client to another cpu
4180Sstevel@tonic-gate * Assumed to be called single threaded.
4190Sstevel@tonic-gate */
4200Sstevel@tonic-gate void
juggle_sgnblk_poll(struct cpu * cp)4210Sstevel@tonic-gate juggle_sgnblk_poll(struct cpu *cp)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate int i;
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate mutex_enter(&sgnblk_mutex);
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate if (sgnblk_pollcpu == -1 ||
4280Sstevel@tonic-gate (cp != NULL && sgnblk_pollcpu == cp->cpu_id)) {
4290Sstevel@tonic-gate mutex_exit(&sgnblk_mutex);
4300Sstevel@tonic-gate return;
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate /*
4340Sstevel@tonic-gate * Disable by simply returning here
4350Sstevel@tonic-gate * Passing a null cp is assumed to be
4360Sstevel@tonic-gate * sgnpoll disable request.
4370Sstevel@tonic-gate */
4380Sstevel@tonic-gate if (cp == NULL) {
4390Sstevel@tonic-gate for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) {
4400Sstevel@tonic-gate void (*func)(), *arg;
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate if ((func = sgnblk_poll_refs[i].callback) != NULL) {
4430Sstevel@tonic-gate arg = sgnblk_poll_refs[i].arg;
4440Sstevel@tonic-gate (*func)(NULL, arg);
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate mutex_exit(&sgnblk_mutex);
4480Sstevel@tonic-gate return;
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate sgnblk_pollcpu = cp->cpu_id;
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) {
4540Sstevel@tonic-gate void (*func)(), *arg;
4550Sstevel@tonic-gate
4560Sstevel@tonic-gate if ((func = sgnblk_poll_refs[i].callback) != NULL) {
4570Sstevel@tonic-gate arg = sgnblk_poll_refs[i].arg;
4580Sstevel@tonic-gate (*func)(cpu_sgnblkp[sgnblk_pollcpu], arg);
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate
4620Sstevel@tonic-gate mutex_exit(&sgnblk_mutex);
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate #ifdef THROTTLE
4660Sstevel@tonic-gate /*ARGSUSED0*/
4670Sstevel@tonic-gate static void
_sgnblk_poll_throttle(void * unused)4680Sstevel@tonic-gate _sgnblk_poll_throttle(void *unused)
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate mutex_enter(&cpu_lock);
4710Sstevel@tonic-gate if (sgnblk_poll_cycid != CYCLIC_NONE) {
4720Sstevel@tonic-gate cyclic_remove(sgnblk_poll_cycid);
4730Sstevel@tonic-gate sgnblk_poll_cycid = CYCLIC_NONE;
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate if (sgnblk_poll_time.cyt_interval > 0ull)
4770Sstevel@tonic-gate sgnblk_poll_cycid = cyclic_add(&sgnblk_poll_cychandler,
4780Sstevel@tonic-gate &sgnblk_poll_time);
4790Sstevel@tonic-gate mutex_exit(&cpu_lock);
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate /*
4830Sstevel@tonic-gate * We don't want to remove the cyclic within the context of
4840Sstevel@tonic-gate * the handler so we kick off the throttle in background
4850Sstevel@tonic-gate * via a timeout call.
4860Sstevel@tonic-gate */
4870Sstevel@tonic-gate static void
sgnblk_poll_throttle(uint64_t new_interval)4880Sstevel@tonic-gate sgnblk_poll_throttle(uint64_t new_interval)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate mutex_enter(&cpu_lock);
4910Sstevel@tonic-gate sgnblk_poll_time.cyt_when = 0ull;
4920Sstevel@tonic-gate sgnblk_poll_time.cyt_interval = new_interval * 1000ull;
4930Sstevel@tonic-gate mutex_exit(&cpu_lock);
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate (void) timeout(_sgnblk_poll_throttle, NULL, (clock_t)0);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate #endif /* THROTTLE */
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate /*
5000Sstevel@tonic-gate * High priority interrupt handler (PIL_14)
5010Sstevel@tonic-gate * for signature block mbox polling.
5020Sstevel@tonic-gate */
5030Sstevel@tonic-gate /*ARGSUSED0*/
5040Sstevel@tonic-gate static void
sgnblk_poll_handler(void * unused)5050Sstevel@tonic-gate sgnblk_poll_handler(void *unused)
5060Sstevel@tonic-gate {
5070Sstevel@tonic-gate processorid_t cpuid = SIGBCPU->cpu_id;
5080Sstevel@tonic-gate #ifdef THROTTLE
5090Sstevel@tonic-gate static int64_t sb_window = -1;
5100Sstevel@tonic-gate static uint64_t sb_interval = 0;
5110Sstevel@tonic-gate #endif /* THROTTLE */
5120Sstevel@tonic-gate
5130Sstevel@tonic-gate if (cpu_sgnblkp[cpuid] == NULL)
5140Sstevel@tonic-gate return;
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate * Poll for SSP requests
5180Sstevel@tonic-gate */
5190Sstevel@tonic-gate if (cpu_sgnblkp[cpuid]->sigb_host_mbox.intr == SIGB_INTR_SEND) {
5200Sstevel@tonic-gate /* reset the flag - sure hope this is atomic */
5210Sstevel@tonic-gate cpu_sgnblkp[cpuid]->sigb_host_mbox.intr = SIGB_INTR_OFF;
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate #ifdef THROTTLE
5240Sstevel@tonic-gate /*
5250Sstevel@tonic-gate * Go into fast poll mode for a short duration
5260Sstevel@tonic-gate * (SGNBLK_POLL_FAST_WIN) in SGNBLK_POLL_FAST interval.
5270Sstevel@tonic-gate * The assumption here is that we just got activity
5280Sstevel@tonic-gate * on the mbox poll, the probability of more coming down
5290Sstevel@tonic-gate * the pipe is high - so let's look more often.
5300Sstevel@tonic-gate */
5310Sstevel@tonic-gate if ((sb_window < 0) && (sb_interval > sgnblk_poll_fast)) {
5320Sstevel@tonic-gate sb_interval = sgnblk_poll_fast;
5330Sstevel@tonic-gate sgnblk_poll_throttle(sb_interval);
5340Sstevel@tonic-gate }
5350Sstevel@tonic-gate sb_window = sgnblk_poll_fast_win;
5360Sstevel@tonic-gate #endif /* THROTTLE */
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate /* schedule poll processing */
5390Sstevel@tonic-gate setsoftint(bbus_poll_inum);
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate #ifdef THROTTLE
5420Sstevel@tonic-gate } else if (sb_window >= 0) {
5430Sstevel@tonic-gate /* Revert to slow polling once fast window ends */
5440Sstevel@tonic-gate if ((--sb_window < 0) &&
5450Sstevel@tonic-gate (sb_interval < sgnblk_poll_interval)) {
5460Sstevel@tonic-gate sb_interval = sgnblk_poll_interval;
5470Sstevel@tonic-gate sgnblk_poll_throttle(sb_interval);
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate #endif /* THROTTLE */
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate /*ARGSUSED*/
5540Sstevel@tonic-gate static uint_t
bbus_poll(caddr_t arg1,caddr_t arg2)5550Sstevel@tonic-gate bbus_poll(caddr_t arg1, caddr_t arg2)
5560Sstevel@tonic-gate {
5570Sstevel@tonic-gate int i;
5580Sstevel@tonic-gate processorid_t cpu_id = SIGBCPU->cpu_id;
5590Sstevel@tonic-gate cpu_sgnblk_t *sgnblkp = cpu_sgnblkp[cpu_id];
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate /*
5620Sstevel@tonic-gate * Go thru the poll client array and call the
5630Sstevel@tonic-gate * poll client functions one by one
5640Sstevel@tonic-gate */
5650Sstevel@tonic-gate mutex_enter(&sgnblk_poll_mutex);
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate for (i = 0; i < MAX_SGNBLK_POLL_CLNT; i++) {
5680Sstevel@tonic-gate void (*func)(processorid_t cpuid, cpu_sgnblk_t *sgnblkp);
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate if ((func = pollclntfunc[i]) != NULL) {
5710Sstevel@tonic-gate mutex_exit(&sgnblk_poll_mutex);
5720Sstevel@tonic-gate (*func)(cpu_id, sgnblkp);
5730Sstevel@tonic-gate mutex_enter(&sgnblk_poll_mutex);
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate mutex_exit(&sgnblk_poll_mutex);
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate return (1);
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate int
sgnblk_poll_reference(void (* callback)(cpu_sgnblk_t * sigb,void * arg),void * arg)5820Sstevel@tonic-gate sgnblk_poll_reference(void (*callback)(cpu_sgnblk_t *sigb, void *arg),
5830Sstevel@tonic-gate void *arg)
5840Sstevel@tonic-gate {
5850Sstevel@tonic-gate int i, slot;
5860Sstevel@tonic-gate cpu_sgnblk_t *sigbp;
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate if (callback == NULL)
5890Sstevel@tonic-gate return (-1);
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate mutex_enter(&sgnblk_mutex);
5920Sstevel@tonic-gate /*
5930Sstevel@tonic-gate * First verify caller is not already registered.
5940Sstevel@tonic-gate */
5950Sstevel@tonic-gate slot = -1;
5960Sstevel@tonic-gate for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) {
5970Sstevel@tonic-gate if ((slot == -1) && (sgnblk_poll_refs[i].callback == NULL)) {
5980Sstevel@tonic-gate slot = i;
5990Sstevel@tonic-gate continue;
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate if (sgnblk_poll_refs[i].callback == callback) {
6020Sstevel@tonic-gate mutex_exit(&sgnblk_mutex);
6030Sstevel@tonic-gate return (-1);
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate /*
6070Sstevel@tonic-gate * Now find an empty entry.
6080Sstevel@tonic-gate */
6090Sstevel@tonic-gate if (slot == -1) {
6100Sstevel@tonic-gate mutex_exit(&sgnblk_mutex);
6110Sstevel@tonic-gate return (-1);
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate sgnblk_poll_refs[slot].callback = callback;
6140Sstevel@tonic-gate sgnblk_poll_refs[slot].arg = arg;
6150Sstevel@tonic-gate
6160Sstevel@tonic-gate sigbp = (sgnblk_pollcpu != -1) ? cpu_sgnblkp[sgnblk_pollcpu] : NULL;
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate (*callback)(sigbp, arg);
6190Sstevel@tonic-gate
6200Sstevel@tonic-gate mutex_exit(&sgnblk_mutex);
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate return (0);
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate
6250Sstevel@tonic-gate void
sgnblk_poll_unreference(void (* callback)(cpu_sgnblk_t * sigb,void * arg))6260Sstevel@tonic-gate sgnblk_poll_unreference(void (*callback)(cpu_sgnblk_t *sigb, void *arg))
6270Sstevel@tonic-gate {
6280Sstevel@tonic-gate int i;
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate mutex_enter(&sgnblk_mutex);
6310Sstevel@tonic-gate for (i = 0; i < MAX_SGNBLK_POLL_REFS; i++) {
6320Sstevel@tonic-gate if (sgnblk_poll_refs[i].callback == callback) {
6330Sstevel@tonic-gate void *arg;
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate arg = sgnblk_poll_refs[i].arg;
6360Sstevel@tonic-gate (*callback)(NULL, arg);
6370Sstevel@tonic-gate sgnblk_poll_refs[i].callback = NULL;
6380Sstevel@tonic-gate sgnblk_poll_refs[i].arg = NULL;
6390Sstevel@tonic-gate break;
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate mutex_exit(&sgnblk_mutex);
6430Sstevel@tonic-gate }
644