Home | History | Annotate | Download | only in psm
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #define	PSMI_1_6
     27 
     28 #include <sys/mutex.h>
     29 #include <sys/types.h>
     30 #include <sys/time.h>
     31 #include <sys/machlock.h>
     32 #include <sys/smp_impldefs.h>
     33 #include <sys/uadmin.h>
     34 #include <sys/promif.h>
     35 #include <sys/psm.h>
     36 #include <sys/pit.h>
     37 #include <sys/apic.h>
     38 #include <sys/psm_common.h>
     39 #include <sys/atomic.h>
     40 #include <sys/archsystm.h>
     41 
     42 #define	NSEC_IN_SEC		1000000000
     43 
     44 /*
     45  * Local Function Prototypes
     46  */
     47 static void uppc_softinit(void);
     48 static void uppc_picinit();
     49 static int uppc_post_cpu_start(void);
     50 static int uppc_clkinit(int);
     51 static int uppc_addspl(int irqno, int ipl, int min_ipl, int max_ipl);
     52 static int uppc_delspl(int irqno, int ipl, int min_ipl, int max_ipl);
     53 static processorid_t uppc_get_next_processorid(processorid_t cpu_id);
     54 static int uppc_get_clockirq(int ipl);
     55 static int uppc_probe(void);
     56 static int uppc_translate_irq(dev_info_t *dip, int irqno);
     57 static void uppc_shutdown(int cmd, int fcn);
     58 static void uppc_preshutdown(int cmd, int fcn);
     59 static int uppc_state(psm_state_request_t *request);
     60 static int uppc_init_acpi(void);
     61 static void uppc_setspl(int);
     62 static int uppc_intr_enter(int, int *);
     63 static void uppc_intr_exit(int, int);
     64 static hrtime_t uppc_gethrtime();
     65 
     66 static int uppc_acpi_irq_configure(acpi_psm_lnk_t *acpipsmlnkp, dev_info_t *dip,
     67     int *pci_irqp, iflag_t *intr_flagp);
     68 
     69 /*
     70  * Global Data
     71  */
     72 static struct standard_pic pics0;
     73 int uppc_use_acpi = 1;	/* Use ACPI by default */
     74 int uppc_enable_acpi = 0;
     75 
     76 
     77 /*
     78  * For interrupt link devices, if uppc_unconditional_srs is set, an irq resource
     79  * will be assigned (via _SRS). If it is not set, use the current
     80  * irq setting (via _CRS), but only if that irq is in the set of possible
     81  * irqs (returned by _PRS) for the device.
     82  */
     83 int uppc_unconditional_srs = 1;
     84 
     85 /*
     86  * For interrupt link devices, if uppc_prefer_crs is set when we are
     87  * assigning an IRQ resource to a device, prefer the current IRQ setting
     88  * over other possible irq settings under same conditions.
     89  */
     90 int uppc_prefer_crs = 1;
     91 
     92 int uppc_verbose = 0;
     93 
     94 /* flag definitions for uppc_verbose */
     95 #define	UPPC_VERBOSE_IRQ_FLAG			0x00000001
     96 #define	UPPC_VERBOSE_POWEROFF_FLAG		0x00000002
     97 #define	UPPC_VERBOSE_POWEROFF_PAUSE_FLAG	0x00000004
     98 
     99 
    100 #define	UPPC_VERBOSE_IRQ(fmt) \
    101 	if (uppc_verbose & UPPC_VERBOSE_IRQ_FLAG) \
    102 		cmn_err fmt;
    103 
    104 #define	UPPC_VERBOSE_POWEROFF(fmt) \
    105 	if (uppc_verbose & UPPC_VERBOSE_POWEROFF_FLAG) \
    106 		prom_printf fmt;
    107 
    108 uchar_t uppc_reserved_irqlist[MAX_ISA_IRQ + 1];
    109 
    110 static uint16_t uppc_irq_shared_table[MAX_ISA_IRQ + 1];
    111 
    112 /*
    113  * Contains SCI irqno from FADT after initialization
    114  */
    115 static int uppc_sci = -1;
    116 
    117 /*
    118  * Local Static Data
    119  */
    120 
    121 static lock_t uppc_gethrtime_lock;
    122 static hrtime_t uppc_lasthrtime;
    123 
    124 
    125 #ifdef UPPC_DEBUG
    126 #define	DENT	0x0001
    127 
    128 static int	uppc_debug = 0;
    129 
    130 
    131 #endif
    132 
    133 
    134 static struct	psm_ops uppc_ops = {
    135 	uppc_probe,				/* psm_probe		*/
    136 
    137 	uppc_softinit,				/* psm_init		*/
    138 	uppc_picinit,				/* psm_picinit		*/
    139 	uppc_intr_enter,			/* psm_intr_enter	*/
    140 	uppc_intr_exit,				/* psm_intr_exit	*/
    141 	uppc_setspl,				/* psm_setspl		*/
    142 	uppc_addspl,				/* psm_addspl		*/
    143 	uppc_delspl,				/* psm_delspl		*/
    144 	(int (*)(processorid_t))NULL,		/* psm_disable_intr	*/
    145 	(void (*)(processorid_t))NULL,		/* psm_enable_intr	*/
    146 	(int (*)(int))NULL,			/* psm_softlvl_to_irq	*/
    147 	(void (*)(int))NULL,			/* psm_set_softintr	*/
    148 	(void (*)(processorid_t))NULL,		/* psm_set_idlecpu	*/
    149 	(void (*)(processorid_t))NULL,		/* psm_unset_idlecpu	*/
    150 
    151 	uppc_clkinit,				/* psm_clkinit		*/
    152 	uppc_get_clockirq,			/* psm_get_clockirq	*/
    153 	(void (*)(void))NULL,			/* psm_hrtimeinit	*/
    154 	uppc_gethrtime,				/* psm_gethrtime	*/
    155 
    156 	uppc_get_next_processorid,		/* psm_get_next_processorid */
    157 	(int (*)(processorid_t, caddr_t))NULL,	/* psm_cpu_start	*/
    158 	uppc_post_cpu_start,			/* psm_post_cpu_start	*/
    159 	uppc_shutdown,				/* psm_shutdown		*/
    160 	(int (*)(int, int))NULL,		/* psm_get_ipivect	*/
    161 	(void (*)(processorid_t, int))NULL,	/* psm_send_ipi		*/
    162 
    163 	uppc_translate_irq,			/* psm_translate_irq	*/
    164 
    165 	(void (*)(int, char *))NULL,		/* psm_notify_error	*/
    166 	(void (*)(int msg))NULL,		/* psm_notify_func	*/
    167 	(void (*)(hrtime_t time))NULL,		/* psm_timer_reprogram	*/
    168 	(void (*)(void))NULL,			/* psm_timer_enable	*/
    169 	(void (*)(void))NULL,			/* psm_timer_disable	*/
    170 	(void (*)(void *arg))NULL,		/* psm_post_cyclic_setup */
    171 	uppc_preshutdown,			/* psm_preshutdown	*/
    172 
    173 	(int (*)(dev_info_t *, ddi_intr_handle_impl_t *,
    174 	    psm_intr_op_t, int *))NULL,		/* psm_intr_ops		*/
    175 
    176 	uppc_state				/* psm_state		*/
    177 };
    178 
    179 
    180 static struct	psm_info uppc_info = {
    181 	PSM_INFO_VER01_6,	/* version				*/
    182 	PSM_OWN_SYS_DEFAULT,	/* ownership				*/
    183 	(struct psm_ops *)&uppc_ops, /* operation			*/
    184 	"uppc",			/* machine name				*/
    185 	"UniProcessor PC",	/* machine descriptions			*/
    186 };
    187 
    188 /*
    189  * Configuration Data
    190  */
    191 
    192 /*
    193  * This is the loadable module wrapper.
    194  */
    195 #include <sys/modctl.h>
    196 
    197 static void *uppc_hdlp;
    198 
    199 int
    200 _init(void)
    201 {
    202 	return (psm_mod_init(&uppc_hdlp, &uppc_info));
    203 }
    204 
    205 int
    206 _fini(void)
    207 {
    208 	return (psm_mod_fini(&uppc_hdlp, &uppc_info));
    209 }
    210 
    211 int
    212 _info(struct modinfo *modinfop)
    213 {
    214 	return (psm_mod_info(&uppc_hdlp, &uppc_info, modinfop));
    215 }
    216 
    217 /*
    218  * Autoconfiguration Routines
    219  */
    220 
    221 static int
    222 uppc_probe(void)
    223 {
    224 
    225 
    226 	return (PSM_SUCCESS);
    227 }
    228 
    229 static void
    230 uppc_softinit(void)
    231 {
    232 	struct standard_pic *pp;
    233 	int i;
    234 
    235 	pp = &pics0;
    236 
    237 
    238 	if (uppc_use_acpi && uppc_init_acpi()) {
    239 		build_reserved_irqlist((uchar_t *)uppc_reserved_irqlist);
    240 		for (i = 0; i <= MAX_ISA_IRQ; i++)
    241 			uppc_irq_shared_table[i] = 0;
    242 		uppc_enable_acpi = 1;
    243 	}
    244 
    245 	/*
    246 	 * initialize the ipl mask
    247 	 */
    248 	for (i = 0; i < (MAXIPL << 1); i += 2) {
    249 		/* enable slave lines on master */
    250 		pp->c_iplmask[i] = 0xff;
    251 		pp->c_iplmask[i+1] = (0xff & ~(1 << MASTERLINE));
    252 	}
    253 }
    254 
    255 /*ARGSUSED*/
    256 static int
    257 uppc_clkinit(int hertz)
    258 {
    259 	ulong_t clkticks = PIT_HZ / hz;
    260 
    261 	if (hertz == 0)
    262 		return (0);	/* One shot mode not supported */
    263 
    264 	/*
    265 	 * program timer 0
    266 	 */
    267 	outb(PITCTL_PORT, (PIT_C0|PIT_NDIVMODE|PIT_READMODE));
    268 	outb(PITCTR0_PORT, (uchar_t)clkticks);
    269 	outb(PITCTR0_PORT, (uchar_t)(clkticks>>8));
    270 
    271 	return (NSEC_IN_SEC / hertz);
    272 }
    273 
    274 static void
    275 uppc_picinit()
    276 {
    277 	picsetup();
    278 
    279 	/*
    280 	 * If a valid SCI is present, manually addspl()
    281 	 * since we're not set-up early enough in boot
    282 	 * to do it "conventionally" (via add_avintr)
    283 	 */
    284 	if (uppc_sci >= 0)
    285 		(void) uppc_addspl(uppc_sci, SCI_IPL, SCI_IPL, SCI_IPL);
    286 }
    287 
    288 static int
    289 uppc_post_cpu_start(void)
    290 {
    291 	/*
    292 	 * On uppc machines psm_post_cpu_start is called during S3 resume
    293 	 * on the boot cpu from assembly, using the ap_mlsetup vector.
    294 	 */
    295 
    296 	/*
    297 	 * Init master and slave pic
    298 	 */
    299 	picsetup();
    300 
    301 	/*
    302 	 * program timer 0
    303 	 */
    304 	(void) uppc_clkinit(hz);
    305 
    306 	return (PSM_SUCCESS);
    307 }
    308 
    309 /*ARGSUSED3*/
    310 static int
    311 uppc_addspl(int irqno, int ipl, int min_ipl, int max_ipl)
    312 {
    313 	struct standard_pic *pp;
    314 	int i;
    315 	int startidx;
    316 	uchar_t	vectmask;
    317 
    318 	if (irqno <= MAX_ISA_IRQ)
    319 		atomic_add_16(&uppc_irq_shared_table[irqno], 1);
    320 
    321 	if (ipl != min_ipl)
    322 		return (0);
    323 
    324 	if (irqno > 7) {
    325 		vectmask = 1 << (irqno - 8);
    326 		startidx = (ipl << 1);
    327 	} else {
    328 		vectmask = 1 << irqno;
    329 		startidx = (ipl << 1) + 1;
    330 	}
    331 
    332 	/*
    333 	 * mask intr same or above ipl
    334 	 * level MAXIPL has all intr off as init. default
    335 	 */
    336 	pp = &pics0;
    337 	for (i = startidx; i < (MAXIPL << 1); i += 2) {
    338 		if (pp->c_iplmask[i] & vectmask)
    339 			break;
    340 		pp->c_iplmask[i] |= vectmask;
    341 	}
    342 
    343 	/*
    344 	 * unmask intr below ipl
    345 	 */
    346 	for (i = startidx-2; i >= 0; i -= 2) {
    347 		if (!(pp->c_iplmask[i] & vectmask))
    348 			break;
    349 		pp->c_iplmask[i] &= ~vectmask;
    350 	}
    351 	return (0);
    352 }
    353 
    354 static int
    355 uppc_delspl(int irqno, int ipl, int min_ipl, int max_ipl)
    356 {
    357 	struct standard_pic *pp;
    358 	int i;
    359 	uchar_t	vectmask;
    360 
    361 	if (irqno <= MAX_ISA_IRQ)
    362 		atomic_add_16(&uppc_irq_shared_table[irqno], -1);
    363 
    364 	/*
    365 	 * skip if we are not deleting the last handler
    366 	 * and the ipl is higher than minimum
    367 	 */
    368 	if ((max_ipl != PSM_INVALID_IPL) && (ipl >= min_ipl))
    369 		return (0);
    370 
    371 	if (irqno > 7) {
    372 		vectmask = 1 << (irqno - 8);
    373 		i = 0;
    374 	} else {
    375 		vectmask = 1 << irqno;
    376 		i = 1;
    377 	}
    378 
    379 	pp = &pics0;
    380 
    381 	/*
    382 	 * check any handlers left for this irqno
    383 	 */
    384 	if (max_ipl != PSM_INVALID_IPL) {
    385 		/*
    386 		 * unmasks all levels below the lowest priority
    387 		 */
    388 		i += ((min_ipl - 1) << 1);
    389 		for (; i >= 0; i -= 2) {
    390 			if (!(pp->c_iplmask[i] & vectmask))
    391 				break;
    392 			pp->c_iplmask[i] &= ~vectmask;
    393 		}
    394 	} else {
    395 		/*
    396 		 * set mask to all levels
    397 		 */
    398 		for (; i < (MAXIPL << 1); i += 2) {
    399 			if (pp->c_iplmask[i] & vectmask)
    400 				break;
    401 			pp->c_iplmask[i] |= vectmask;
    402 		}
    403 	}
    404 	return (0);
    405 }
    406 
    407 static processorid_t
    408 uppc_get_next_processorid(processorid_t cpu_id)
    409 {
    410 	if (cpu_id == -1)
    411 		return (0);
    412 	return (-1);
    413 }
    414 
    415 /*ARGSUSED*/
    416 static int
    417 uppc_get_clockirq(int ipl)
    418 {
    419 	return (CLOCK_VECTOR);
    420 }
    421 
    422 
    423 static int
    424 uppc_init_acpi(void)
    425 {
    426 	int verboseflags = 0;
    427 	int	sci;
    428 	iflag_t sci_flags;
    429 
    430 	/*
    431 	 * Process SCI configuration here; this may return
    432 	 * an error if acpi-user-options has specified
    433 	 * legacy mode (use ACPI without ACPI mode or SCI)
    434 	 */
    435 	if (acpica_get_sci(&sci, &sci_flags) != AE_OK)
    436 		sci = -1;
    437 
    438 	/*
    439 	 * Initialize sub-system - if error is returns, ACPI is not
    440 	 * used.
    441 	 */
    442 	if (acpica_init() != AE_OK)
    443 		return (0);
    444 
    445 	/*
    446 	 * uppc implies system is in PIC mode; set edge/level
    447 	 * via ELCR based on return value from get_sci; this
    448 	 * will default to level/low if no override present,
    449 	 * as recommended by Intel ACPI CA team.
    450 	 */
    451 	if (sci >= 0) {
    452 		ASSERT((sci_flags.intr_el == INTR_EL_LEVEL) ||
    453 		    (sci_flags.intr_el == INTR_EL_EDGE));
    454 
    455 		psm_set_elcr(sci, sci_flags.intr_el == INTR_EL_LEVEL);
    456 	}
    457 
    458 	/*
    459 	 * Remember SCI for later use
    460 	 */
    461 	uppc_sci = sci;
    462 
    463 	if (uppc_verbose & UPPC_VERBOSE_IRQ_FLAG)
    464 		verboseflags |= PSM_VERBOSE_IRQ_FLAG;
    465 
    466 	if (uppc_verbose & UPPC_VERBOSE_POWEROFF_FLAG)
    467 		verboseflags |= PSM_VERBOSE_POWEROFF_FLAG;
    468 
    469 	if (uppc_verbose & UPPC_VERBOSE_POWEROFF_PAUSE_FLAG)
    470 		verboseflags |= PSM_VERBOSE_POWEROFF_PAUSE_FLAG;
    471 
    472 	if (acpi_psm_init(uppc_info.p_mach_idstring, verboseflags) ==
    473 	    ACPI_PSM_FAILURE) {
    474 		return (0);
    475 	}
    476 
    477 	return (1);
    478 }
    479 
    480 
    481 static void
    482 uppc_preshutdown(int cmd, int fcn)
    483 {
    484 	UPPC_VERBOSE_POWEROFF(("uppc_preshutdown(%d,%d);\n", cmd, fcn));
    485 
    486 }
    487 
    488 static void
    489 uppc_shutdown(int cmd, int fcn)
    490 {
    491 	UPPC_VERBOSE_POWEROFF(("uppc_shutdown(%d,%d);\n", cmd, fcn));
    492 
    493 	/*
    494 	 * Return if passed a command other than A_SHUTDOWN or
    495 	 * if we're not using ACPI.
    496 	 */
    497 	if ((cmd != A_SHUTDOWN) || (!uppc_enable_acpi))
    498 		return;
    499 
    500 	/*
    501 	 * Switch system back into Legacy-Mode if using ACPI and
    502 	 * not powering-off.  Some BIOSes need to remain in ACPI-mode
    503 	 * for power-off to succeed (Dell Dimension 4600)
    504 	 */
    505 	if (fcn != AD_POWEROFF) {
    506 		(void) AcpiDisable();
    507 		return;
    508 	}
    509 
    510 	(void) acpi_poweroff();
    511 }
    512 
    513 
    514 static int
    515 uppc_acpi_enter_picmode(void)
    516 {
    517 	ACPI_OBJECT_LIST	arglist;
    518 	ACPI_OBJECT		arg;
    519 	ACPI_STATUS		status;
    520 
    521 	/* Setup parameter object */
    522 	arglist.Count = 1;
    523 	arglist.Pointer = &arg;
    524 	arg.Type = ACPI_TYPE_INTEGER;
    525 	arg.Integer.Value = ACPI_PIC_MODE;
    526 
    527 	status = AcpiEvaluateObject(NULL, "\\_PIC", &arglist, NULL);
    528 	if (ACPI_FAILURE(status))
    529 		return (PSM_FAILURE);
    530 	else
    531 		return (PSM_SUCCESS);
    532 }
    533 
    534 
    535 struct pic_state {
    536 	int8_t		mmask;
    537 	int8_t		smask;
    538 	uint16_t	elcr;
    539 };
    540 
    541 
    542 static void
    543 pic_save_state(struct pic_state *sp)
    544 {
    545 	struct standard_pic *pp;
    546 	int	vecno;
    547 
    548 	/*
    549 	 * Only the PIC masks and the ELCR can be saved;
    550 	 * other 8259 state is write-only
    551 	 */
    552 
    553 	/*
    554 	 * save current master and slave interrupt mask
    555 	 */
    556 	pp = &pics0;
    557 	sp->smask = pp->c_curmask[0];
    558 	sp->mmask = pp->c_curmask[1];
    559 
    560 	/*
    561 	 * save edge/level configuration for isa interrupts
    562 	 */
    563 	sp->elcr = 0;
    564 	for (vecno = 0; vecno <= MAX_ISA_IRQ; vecno++)
    565 		sp->elcr |= psm_get_elcr(vecno) << vecno;
    566 }
    567 
    568 static void
    569 pic_restore_state(struct pic_state *sp)
    570 {
    571 	int	vecno;
    572 
    573 	/* Restore master and slave interrupt masks */
    574 	outb(SIMR_PORT, sp->smask);
    575 	outb(MIMR_PORT, sp->mmask);
    576 
    577 	/* Read master to allow pics to settle */
    578 	(void) inb(MIMR_PORT);
    579 
    580 	/* Restore edge/level configuration for isa interupts */
    581 	for (vecno = 0; vecno <= MAX_ISA_IRQ; vecno++)
    582 		psm_set_elcr(vecno, sp->elcr & (1 << vecno));
    583 
    584 	/* Reenter PIC mode before restoring LNK devices */
    585 	(void) uppc_acpi_enter_picmode();
    586 
    587 	/* Restore ACPI link device mappings */
    588 	acpi_restore_link_devices();
    589 }
    590 
    591 static int
    592 uppc_state(psm_state_request_t *rp)
    593 {
    594 	switch (rp->psr_cmd) {
    595 	case PSM_STATE_ALLOC:
    596 		rp->req.psm_state_req.psr_state =
    597 		    kmem_zalloc(sizeof (struct pic_state), KM_NOSLEEP);
    598 		if (rp->req.psm_state_req.psr_state == NULL)
    599 			return (ENOMEM);
    600 		rp->req.psm_state_req.psr_state_size =
    601 		    sizeof (struct pic_state);
    602 		return (0);
    603 	case PSM_STATE_FREE:
    604 		kmem_free(rp->req.psm_state_req.psr_state,
    605 		    rp->req.psm_state_req.psr_state_size);
    606 		return (0);
    607 	case PSM_STATE_SAVE:
    608 		pic_save_state(rp->req.psm_state_req.psr_state);
    609 		return (0);
    610 	case PSM_STATE_RESTORE:
    611 		pic_restore_state(rp->req.psm_state_req.psr_state);
    612 		return (0);
    613 	default:
    614 		return (EINVAL);
    615 	}
    616 }
    617 
    618 
    619 static int
    620 uppc_acpi_translate_pci_irq(dev_info_t *dip, int busid, int devid,
    621     int ipin, int *pci_irqp, iflag_t *intr_flagp)
    622 {
    623 	int status;
    624 	acpi_psm_lnk_t acpipsmlnk;
    625 
    626 	if ((status = acpi_get_irq_cache_ent(busid, devid, ipin, pci_irqp,
    627 	    intr_flagp)) == ACPI_PSM_SUCCESS) {
    628 		UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: Found irqno %d "
    629 		    "from cache for device %s, instance #%d\n", *pci_irqp,
    630 		    ddi_get_name(dip), ddi_get_instance(dip)));
    631 		return (status);
    632 	}
    633 
    634 	bzero(&acpipsmlnk, sizeof (acpi_psm_lnk_t));
    635 
    636 	if ((status = acpi_translate_pci_irq(dip, ipin, pci_irqp,
    637 	    intr_flagp, &acpipsmlnk)) == ACPI_PSM_FAILURE) {
    638 		UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: "
    639 		    " acpi_translate_pci_irq failed for device %s, instance"
    640 		    " #%d\n", ddi_get_name(dip), ddi_get_instance(dip)));
    641 
    642 		return (status);
    643 	}
    644 
    645 	if (status == ACPI_PSM_PARTIAL && acpipsmlnk.lnkobj != NULL) {
    646 		status = uppc_acpi_irq_configure(&acpipsmlnk, dip, pci_irqp,
    647 		    intr_flagp);
    648 		if (status != ACPI_PSM_SUCCESS) {
    649 			status = acpi_get_current_irq_resource(&acpipsmlnk,
    650 			    pci_irqp, intr_flagp);
    651 		}
    652 	}
    653 
    654 	if (status == ACPI_PSM_SUCCESS) {
    655 		acpi_new_irq_cache_ent(busid, devid, ipin, *pci_irqp,
    656 		    intr_flagp, &acpipsmlnk);
    657 		psm_set_elcr(*pci_irqp, 1); 	/* set IRQ to PCI mode */
    658 
    659 		UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: [ACPI] "
    660 		    "new irq %d for device %s, instance #%d\n",
    661 		    *pci_irqp, ddi_get_name(dip), ddi_get_instance(dip)));
    662 	}
    663 
    664 	return (status);
    665 }
    666 
    667 /*
    668  * Configures the irq for the interrupt link device identified by
    669  * acpipsmlnkp.
    670  *
    671  * Gets the current and the list of possible irq settings for the
    672  * device. If uppc_unconditional_srs is not set, and the current
    673  * resource setting is in the list of possible irq settings,
    674  * current irq resource setting is passed to the caller.
    675  *
    676  * Otherwise, picks an irq number from the list of possible irq
    677  * settings, and sets the irq of the device to this value.
    678  * If prefer_crs is set, among a set of irq numbers in the list that have
    679  * the least number of devices sharing the interrupt, we pick current irq
    680  * resource setting if it is a member of this set.
    681  *
    682  * Passes the irq number in the value pointed to by pci_irqp, and
    683  * polarity and sensitivity in the structure pointed to by dipintrflagp
    684  * to the caller.
    685  *
    686  * Note that if setting the irq resource failed, but successfuly obtained
    687  * the current irq resource settings, passes the current irq resources
    688  * and considers it a success.
    689  *
    690  * Returns:
    691  * ACPI_PSM_SUCCESS on success.
    692  *
    693  * ACPI_PSM_FAILURE if an error occured during the configuration or
    694  * if a suitable irq was not found for this device, or if setting the
    695  * irq resource and obtaining the current resource fails.
    696  *
    697  */
    698 static int
    699 uppc_acpi_irq_configure(acpi_psm_lnk_t *acpipsmlnkp, dev_info_t *dip,
    700     int *pci_irqp, iflag_t *dipintr_flagp)
    701 {
    702 	int i, min_share, foundnow, done = 0;
    703 	int32_t irq;
    704 	int32_t share_irq = -1;
    705 	int32_t chosen_irq = -1;
    706 	int cur_irq = -1;
    707 	acpi_irqlist_t *irqlistp;
    708 	acpi_irqlist_t *irqlistent;
    709 
    710 	if ((acpi_get_possible_irq_resources(acpipsmlnkp, &irqlistp))
    711 	    == ACPI_PSM_FAILURE) {
    712 		UPPC_VERBOSE_IRQ((CE_WARN, "!uppc: Unable to determine "
    713 		    "or assign IRQ for device %s, instance #%d: The system was "
    714 		    "unable to get the list of potential IRQs from ACPI.",
    715 		    ddi_get_name(dip), ddi_get_instance(dip)));
    716 
    717 		return (ACPI_PSM_FAILURE);
    718 	}
    719 
    720 	if ((acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq,
    721 	    dipintr_flagp) == ACPI_PSM_SUCCESS) && (!uppc_unconditional_srs) &&
    722 	    (cur_irq > 0)) {
    723 
    724 		if (acpi_irqlist_find_irq(irqlistp, cur_irq, NULL)
    725 		    == ACPI_PSM_SUCCESS) {
    726 
    727 			acpi_free_irqlist(irqlistp);
    728 			ASSERT(pci_irqp != NULL);
    729 			*pci_irqp = cur_irq;
    730 			return (ACPI_PSM_SUCCESS);
    731 		}
    732 		UPPC_VERBOSE_IRQ((CE_WARN, "!uppc: Could not find the "
    733 		    "current irq %d for device %s, instance #%d in ACPI's "
    734 		    "list of possible irqs for this device. Picking one from "
    735 		    " the latter list.", cur_irq, ddi_get_name(dip),
    736 		    ddi_get_instance(dip)));
    737 
    738 	}
    739 
    740 	irqlistent = irqlistp;
    741 	min_share = 255;
    742 
    743 	while (irqlistent != NULL) {
    744 
    745 		for (foundnow = 0, i = 0; i < irqlistent->num_irqs; i++) {
    746 
    747 			irq = irqlistp->irqs[i];
    748 
    749 			if ((irq > MAX_ISA_IRQ) ||
    750 			    (irqlistent->intr_flags.intr_el == INTR_EL_EDGE) ||
    751 			    (irq == 0))
    752 				continue;
    753 
    754 			if (uppc_reserved_irqlist[irq])
    755 				continue;
    756 
    757 			if (uppc_irq_shared_table[irq] == 0) {
    758 				chosen_irq = irq;
    759 				foundnow = 1;
    760 				if (!(uppc_prefer_crs) || (irq == cur_irq)) {
    761 					done = 1;
    762 					break;
    763 				}
    764 			}
    765 
    766 			if ((uppc_irq_shared_table[irq] < min_share) ||
    767 			    ((uppc_irq_shared_table[irq] == min_share) &&
    768 			    (cur_irq == irq) && (uppc_prefer_crs))) {
    769 				min_share = uppc_irq_shared_table[irq];
    770 				share_irq = irq;
    771 				foundnow = 1;
    772 			}
    773 		}
    774 
    775 		/* If we found an IRQ in the inner loop, save the details */
    776 		if (foundnow && ((chosen_irq != -1) || (share_irq != -1))) {
    777 			/*
    778 			 * Copy the acpi_prs_private_t and flags from this
    779 			 * irq list entry, since we found an irq from this
    780 			 * entry.
    781 			 */
    782 			acpipsmlnkp->acpi_prs_prv = irqlistent->acpi_prs_prv;
    783 			*dipintr_flagp = irqlistent->intr_flags;
    784 		}
    785 
    786 		if (done)
    787 			break;
    788 
    789 		/* Load the next entry in the irqlist */
    790 		irqlistent = irqlistent->next;
    791 	}
    792 
    793 	acpi_free_irqlist(irqlistp);
    794 
    795 	if (chosen_irq != -1)
    796 		irq = chosen_irq;
    797 	else if (share_irq != -1)
    798 		irq = share_irq;
    799 	else {
    800 		UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: Could not find a "
    801 		    "suitable irq from the list of possible irqs for device "
    802 		    "%s, instance #%d in ACPI's list of possible\n",
    803 		    ddi_get_name(dip), ddi_get_instance(dip)));
    804 
    805 		return (ACPI_PSM_FAILURE);
    806 	}
    807 
    808 
    809 	UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: Setting irq %d for device %s "
    810 	    "instance #%d\n", irq, ddi_get_name(dip), ddi_get_instance(dip)));
    811 
    812 	if ((acpi_set_irq_resource(acpipsmlnkp, irq)) == ACPI_PSM_SUCCESS) {
    813 		/*
    814 		 * setting irq was successful, check to make sure CRS
    815 		 * reflects that. If CRS does not agree with what we
    816 		 * set, return the irq that was set.
    817 		 */
    818 
    819 		if (acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq,
    820 		    dipintr_flagp) == ACPI_PSM_SUCCESS) {
    821 
    822 			if (cur_irq != irq)
    823 				UPPC_VERBOSE_IRQ((CE_WARN, "!uppc: "
    824 				    "IRQ resource set (irqno %d) for device %s "
    825 				    "instance #%d, differs from current "
    826 				    "setting irqno %d",
    827 				    irq, ddi_get_name(dip),
    828 				    ddi_get_instance(dip), cur_irq));
    829 		}
    830 		/*
    831 		 * return the irq that was set, and not what CRS reports,
    832 		 * since CRS has been seen to be bogus on some systems
    833 		 */
    834 		cur_irq = irq;
    835 	} else {
    836 		UPPC_VERBOSE_IRQ((CE_WARN, "!uppc: set resource irq %d "
    837 		    "failed for device %s instance #%d",
    838 		    irq, ddi_get_name(dip), ddi_get_instance(dip)));
    839 		if (cur_irq == -1)
    840 			return (ACPI_PSM_FAILURE);
    841 	}
    842 
    843 	ASSERT(pci_irqp != NULL);
    844 	*pci_irqp = cur_irq;
    845 	return (ACPI_PSM_SUCCESS);
    846 }
    847 
    848 
    849 /*ARGSUSED*/
    850 static int
    851 uppc_translate_irq(dev_info_t *dip, int irqno)
    852 {
    853 	char dev_type[16];
    854 	int dev_len, pci_irq, devid, busid;
    855 	ddi_acc_handle_t cfg_handle;
    856 	uchar_t ipin, iline;
    857 	iflag_t intr_flag;
    858 
    859 	if (dip == NULL) {
    860 		UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: irqno = %d"
    861 		    " dip = NULL\n", irqno));
    862 		return (irqno);
    863 	}
    864 
    865 	if (!uppc_enable_acpi) {
    866 		return (irqno);
    867 	}
    868 
    869 	dev_len = sizeof (dev_type);
    870 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(dip),
    871 	    DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type,
    872 	    &dev_len) != DDI_PROP_SUCCESS) {
    873 		UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: irqno %d"
    874 		    "device %s instance %d no device_type\n", irqno,
    875 		    ddi_get_name(dip), ddi_get_instance(dip)));
    876 		return (irqno);
    877 	}
    878 
    879 	if ((strcmp(dev_type, "pci") == 0) ||
    880 	    (strcmp(dev_type, "pciex") == 0)) {
    881 
    882 		/* pci device */
    883 		if (acpica_get_bdf(dip, &busid, &devid, NULL) != 0)
    884 			return (irqno);
    885 
    886 		if (pci_config_setup(dip, &cfg_handle) != DDI_SUCCESS)
    887 			return (irqno);
    888 
    889 		ipin = pci_config_get8(cfg_handle, PCI_CONF_IPIN) - PCI_INTA;
    890 		iline = pci_config_get8(cfg_handle, PCI_CONF_ILINE);
    891 		if (uppc_acpi_translate_pci_irq(dip, busid, devid,
    892 		    ipin, &pci_irq, &intr_flag) == ACPI_PSM_SUCCESS) {
    893 
    894 			UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: [ACPI] new irq "
    895 			    "%d old irq %d device %s, instance %d\n", pci_irq,
    896 			    irqno, ddi_get_name(dip), ddi_get_instance(dip)));
    897 
    898 			/*
    899 			 * Make sure pci_irq is within range.
    900 			 * Otherwise, fall through and return irqno.
    901 			 */
    902 			if (pci_irq <= MAX_ISA_IRQ) {
    903 				if (iline != pci_irq) {
    904 					/*
    905 					 * Update the device's ILINE byte,
    906 					 * in case uppc_acpi_translate_pci_irq
    907 					 * has choosen a different pci_irq
    908 					 * than the BIOS has configured.
    909 					 * Some chipsets use the value in
    910 					 * ILINE to control interrupt routing,
    911 					 * in conflict with the PCI spec.
    912 					 */
    913 					pci_config_put8(cfg_handle,
    914 					    PCI_CONF_ILINE, pci_irq);
    915 				}
    916 				pci_config_teardown(&cfg_handle);
    917 				return (pci_irq);
    918 			}
    919 		}
    920 		pci_config_teardown(&cfg_handle);
    921 
    922 		/* FALLTHRU to common case - returning irqno */
    923 	} else {
    924 		/* non-PCI; assumes ISA-style edge-triggered */
    925 		psm_set_elcr(irqno, 0); 	/* set IRQ to ISA mode */
    926 
    927 		UPPC_VERBOSE_IRQ((CE_CONT, "!uppc: non-pci,"
    928 		    "irqno %d device %s instance %d\n", irqno,
    929 		    ddi_get_name(dip), ddi_get_instance(dip)));
    930 	}
    931 
    932 	return (irqno);
    933 }
    934 
    935 /*
    936  * uppc_intr_enter() raises the ipl to the level of the current interrupt,
    937  * and sends EOI to the pics.
    938  * If interrupt is 7 or 15 and not spurious interrupt, send specific EOI
    939  * else send non-specific EOI
    940  * uppc_intr_enter() returns the new priority level,
    941  * or -1 for spurious interrupt
    942  */
    943 static int
    944 uppc_intr_enter(int ipl, int *vector)
    945 {
    946 	int newipl;
    947 	int intno;
    948 
    949 	intno = (*vector);
    950 
    951 	ASSERT(intno < 256);
    952 
    953 	newipl = autovect[intno].avh_hi_pri;
    954 
    955 	/*
    956 	 * During wait_till_seen() periods when interrupt vector is being
    957 	 * removed in remove_av(), the removed hardware interrupt could
    958 	 * trigger and got here with newipl 0.  It has to send EOI
    959 	 * as usual but no need to call setspl and returns -1 like spurious.
    960 	 */
    961 	if ((intno & 7) != 7) {
    962 		if (newipl)
    963 			uppc_setspl(newipl);
    964 		outb(MCMD_PORT, PIC_NSEOI);
    965 		if (intno >= 8) {
    966 			outb(SCMD_PORT, PIC_NSEOI);
    967 		}
    968 	} else { /* int was 7 or 15 */
    969 		if (newipl && newipl <= ipl) { /* Check for spurious int */
    970 			if (intno != 7)
    971 				outb(MCMD_PORT, PIC_NSEOI);
    972 			return (-1); /* Spurious int */
    973 		} else {
    974 			if (newipl)
    975 				uppc_setspl(newipl);
    976 			if (intno != 7) {
    977 				outb(MCMD_PORT, PIC_NSEOI);
    978 				outb(SCMD_PORT, PIC_SEOI_LVL7);
    979 			} else  {
    980 				outb(MCMD_PORT, PIC_SEOI_LVL7);
    981 			}
    982 		}
    983 	}
    984 
    985 	if (newipl)
    986 		return (newipl);
    987 	else
    988 		return (-1); /* not real spurious int */
    989 }
    990 
    991 /*
    992  * uppc_intr_exit() restores the old interrupt
    993  * priority level after processing an interrupt.
    994  * It is called with interrupts disabled, and does not enable interrupts.
    995  */
    996 /* ARGSUSED */
    997 static void
    998 uppc_intr_exit(int ipl, int vector)
    999 {
   1000 	uppc_setspl(ipl);
   1001 }
   1002 
   1003 /*
   1004  * uppc_setspl() loads new interrupt masks into the pics
   1005  * based on input ipl.
   1006  */
   1007 /* ARGSUSED */
   1008 static void
   1009 uppc_setspl(int ipl)
   1010 {
   1011 	struct standard_pic *pp;
   1012 	uint8_t smask, mmask;
   1013 	uint8_t cursmask, curmmask;
   1014 
   1015 	pp = &pics0;
   1016 	smask = pp->c_iplmask[ipl * 2];
   1017 	mmask = pp->c_iplmask[ipl * 2 + 1];
   1018 	cursmask = pp->c_curmask[0];
   1019 	curmmask = pp->c_curmask[1];
   1020 	if (cursmask == smask && curmmask == mmask)
   1021 		return;
   1022 	pp->c_curmask[0] = smask;
   1023 	pp->c_curmask[1] = mmask;
   1024 
   1025 	if (cursmask != smask) {
   1026 		/*
   1027 		 * program new slave pic mask
   1028 		 */
   1029 		outb(SIMR_PORT, smask);
   1030 	}
   1031 	if (curmmask != mmask) {
   1032 		/*
   1033 		 * program new master pic mask
   1034 		 */
   1035 		outb(MIMR_PORT, mmask);
   1036 	}
   1037 	/*
   1038 	 * read master to allow pics to settle
   1039 	 */
   1040 	(void) inb(MIMR_PORT);
   1041 }
   1042 
   1043 /*
   1044  * uppc_gethrtime() returns high resolution timer value
   1045  */
   1046 static hrtime_t
   1047 uppc_gethrtime()
   1048 {
   1049 	hrtime_t timeval, temp;
   1050 	unsigned int ctr0;
   1051 	ulong_t oflags;
   1052 
   1053 	oflags = intr_clear(); /* disable ints */
   1054 	lock_set(&uppc_gethrtime_lock);
   1055 retry:
   1056 	temp = hrtime_base;
   1057 	outb(PITCTL_PORT, 0);	/* latch counter 0 */
   1058 	/*
   1059 	 * read counter 0
   1060 	 */
   1061 	ctr0 = inb(PITCTR0_PORT);
   1062 	ctr0 |= inb(PITCTR0_PORT) << 8;
   1063 	timeval = (hrtime_t)ctr0 * (NANOSEC / PIT_HZ);
   1064 	if (temp != hrtime_base)
   1065 		goto retry;
   1066 	timeval -= temp;
   1067 	if (timeval < uppc_lasthrtime)
   1068 		timeval = uppc_lasthrtime;
   1069 	uppc_lasthrtime = timeval;
   1070 	lock_clear(&uppc_gethrtime_lock);
   1071 	intr_restore(oflags);
   1072 	return (timeval);
   1073 }
   1074