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 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #define	PSMI_1_6
     28 
     29 #include <sys/mutex.h>
     30 #include <sys/types.h>
     31 #include <sys/time.h>
     32 #include <sys/clock.h>
     33 #include <sys/machlock.h>
     34 #include <sys/smp_impldefs.h>
     35 #include <sys/uadmin.h>
     36 #include <sys/promif.h>
     37 #include <sys/psm.h>
     38 #include <sys/psm_common.h>
     39 #include <sys/atomic.h>
     40 #include <sys/archsystm.h>
     41 #include <sys/mach_intr.h>
     42 #include <sys/hypervisor.h>
     43 #include <sys/evtchn_impl.h>
     44 #include <sys/modctl.h>
     45 #include <sys/trap.h>
     46 #include <sys/panic.h>
     47 
     48 #include <xen/public/vcpu.h>
     49 #include <xen/public/physdev.h>
     50 
     51 
     52 /*
     53  * Global Data
     54  */
     55 int xen_uppc_use_acpi = 1;	/* Use ACPI by default */
     56 int xen_uppc_enable_acpi = 0;
     57 
     58 static int xen_clock_irq = -1;
     59 
     60 /*
     61  * For interrupt link devices, if xen_uppc_unconditional_srs is set, an irq
     62  * resource will be assigned (via _SRS). If it is not set, use the current
     63  * irq setting (via _CRS), but only if that irq is in the set of possible
     64  * irqs (returned by _PRS) for the device.
     65  */
     66 int xen_uppc_unconditional_srs = 1;
     67 
     68 /*
     69  * For interrupt link devices, if xen_uppc_prefer_crs is set when we are
     70  * assigning an IRQ resource to a device, prefer the current IRQ setting
     71  * over other possible irq settings under same conditions.
     72  */
     73 int xen_uppc_prefer_crs = 1;
     74 
     75 int xen_uppc_verbose = 0;
     76 
     77 /* flag definitions for xen_uppc_verbose */
     78 #define	XEN_UPPC_VERBOSE_IRQ_FLAG		0x00000001
     79 #define	XEN_UPPC_VERBOSE_POWEROFF_FLAG		0x00000002
     80 #define	XEN_UPPC_VERBOSE_POWEROFF_PAUSE_FLAG	0x00000004
     81 
     82 #define	XEN_UPPC_VERBOSE_IRQ(fmt) \
     83 	if (xen_uppc_verbose & XEN_UPPC_VERBOSE_IRQ_FLAG) \
     84 		cmn_err fmt;
     85 
     86 #define	XEN_UPPC_VERBOSE_POWEROFF(fmt) \
     87 	if (xen_uppc_verbose & XEN_UPPC_VERBOSE_POWEROFF_FLAG) \
     88 		prom_printf fmt;
     89 
     90 uchar_t xen_uppc_reserved_irqlist[MAX_ISA_IRQ + 1];
     91 
     92 static uint16_t xen_uppc_irq_shared_table[MAX_ISA_IRQ + 1];
     93 
     94 /*
     95  * Contains SCI irqno from FADT after initialization
     96  */
     97 static int xen_uppc_sci = -1;
     98 
     99 static struct psm_info xen_uppc_info;
    100 
    101 /*
    102  * Local support routines
    103  */
    104 
    105 static int
    106 xen_uppc_init_acpi(void)
    107 {
    108 	int verboseflags = 0;
    109 	int	sci;
    110 	iflag_t sci_flags;
    111 
    112 	/*
    113 	 * Process SCI configuration here; this may return
    114 	 * an error if acpi-user-options has specified
    115 	 * legacy mode (use ACPI without ACPI mode or SCI)
    116 	 */
    117 	if (acpica_get_sci(&sci, &sci_flags) != AE_OK)
    118 		sci = -1;
    119 
    120 	/*
    121 	 * Initialize sub-system - if error is returns, ACPI is not
    122 	 * used.
    123 	 */
    124 	if (acpica_init() != AE_OK)
    125 		return (0);
    126 
    127 	/*
    128 	 * uppc implies system is in PIC mode; set edge/level
    129 	 * via ELCR based on return value from get_sci; this
    130 	 * will default to level/low if no override present,
    131 	 * as recommended by Intel ACPI CA team.
    132 	 */
    133 	if (sci >= 0) {
    134 		ASSERT((sci_flags.intr_el == INTR_EL_LEVEL) ||
    135 		    (sci_flags.intr_el == INTR_EL_EDGE));
    136 
    137 		psm_set_elcr(sci, sci_flags.intr_el == INTR_EL_LEVEL);
    138 	}
    139 
    140 	/*
    141 	 * Remember SCI for later use
    142 	 */
    143 	xen_uppc_sci = sci;
    144 
    145 	if (xen_uppc_verbose & XEN_UPPC_VERBOSE_IRQ_FLAG)
    146 		verboseflags |= PSM_VERBOSE_IRQ_FLAG;
    147 
    148 	if (xen_uppc_verbose & XEN_UPPC_VERBOSE_POWEROFF_FLAG)
    149 		verboseflags |= PSM_VERBOSE_POWEROFF_FLAG;
    150 
    151 	if (xen_uppc_verbose & XEN_UPPC_VERBOSE_POWEROFF_PAUSE_FLAG)
    152 		verboseflags |= PSM_VERBOSE_POWEROFF_PAUSE_FLAG;
    153 
    154 	if (acpi_psm_init(xen_uppc_info.p_mach_idstring, verboseflags) ==
    155 	    ACPI_PSM_FAILURE) {
    156 		return (0);
    157 	}
    158 
    159 	return (1);
    160 }
    161 
    162 /*
    163  * Autoconfiguration Routines
    164  */
    165 
    166 static int
    167 xen_uppc_probe(void)
    168 {
    169 
    170 	return (PSM_SUCCESS);
    171 }
    172 
    173 static void
    174 xen_uppc_softinit(void)
    175 {
    176 	int i;
    177 
    178 	/* LINTED logical expression always true: op "||" */
    179 	ASSERT((1 << EVTCHN_SHIFT) == NBBY * sizeof (ulong_t));
    180 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
    181 		if (xen_uppc_use_acpi && xen_uppc_init_acpi()) {
    182 			build_reserved_irqlist((uchar_t *)
    183 			    xen_uppc_reserved_irqlist);
    184 			for (i = 0; i <= MAX_ISA_IRQ; i++)
    185 				xen_uppc_irq_shared_table[i] = 0;
    186 			xen_uppc_enable_acpi = 1;
    187 		}
    188 	}
    189 }
    190 
    191 
    192 #define	XEN_NSEC_PER_TICK	10 /* XXX - assume we have a 100 Mhz clock */
    193 
    194 /*ARGSUSED*/
    195 static int
    196 xen_uppc_clkinit(int hertz)
    197 {
    198 	extern enum tod_fault_type tod_fault(enum tod_fault_type, int);
    199 	extern int dosynctodr;
    200 
    201 	/*
    202 	 * domU cannot set the TOD hardware, fault the TOD clock now to
    203 	 * indicate that and turn off attempts to sync TOD hardware
    204 	 * with the hires timer.
    205 	 */
    206 	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
    207 		mutex_enter(&tod_lock);
    208 		(void) tod_fault(TOD_RDONLY, 0);
    209 		dosynctodr = 0;
    210 		mutex_exit(&tod_lock);
    211 	}
    212 	/*
    213 	 * The hypervisor provides a timer based on the local APIC timer.
    214 	 * The interface supports requests of nanosecond resolution.
    215 	 * A common frequency of the apic clock is 100 Mhz which
    216 	 * gives a resolution of 10 nsec per tick.  What we would really like
    217 	 * is a way to get the ns per tick value from xen.
    218 	 * XXPV - This is an assumption that needs checking and may change
    219 	 */
    220 	return (XEN_NSEC_PER_TICK);
    221 }
    222 
    223 static void
    224 xen_uppc_picinit()
    225 {
    226 	int irqno;
    227 
    228 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
    229 #if 0
    230 		/* hypervisor initializes the 8259, don't mess with it */
    231 		picsetup();	 /* initialise the 8259 */
    232 #endif
    233 		/*
    234 		 * We never called xen_uppc_addspl() when the SCI
    235 		 * interrupt was added because that happened before the
    236 		 * PSM module was loaded.  Fix that up here by doing
    237 		 * any missed operations (e.g. bind to CPU)
    238 		 */
    239 		if ((irqno = xen_uppc_sci) >= 0) {
    240 			ec_enable_irq(irqno);
    241 		}
    242 	}
    243 }
    244 
    245 
    246 /*ARGSUSED*/
    247 static int
    248 xen_uppc_addspl(int irqno, int ipl, int min_ipl, int max_ipl)
    249 {
    250 	int ret = PSM_SUCCESS;
    251 	cpuset_t cpus;
    252 
    253 	if (irqno >= 0 && irqno <= MAX_ISA_IRQ)
    254 		atomic_add_16(&xen_uppc_irq_shared_table[irqno], 1);
    255 
    256 	/*
    257 	 * We are called at splhi() so we can't call anything that might end
    258 	 * up trying to context switch.
    259 	 */
    260 	if (irqno >= PIRQ_BASE && irqno < NR_PIRQS &&
    261 	    DOMAIN_IS_INITDOMAIN(xen_info)) {
    262 		CPUSET_ZERO(cpus);
    263 		CPUSET_ADD(cpus, 0);
    264 		ec_setup_pirq(irqno, ipl, &cpus);
    265 	} else {
    266 		/*
    267 		 * Set priority/affinity/enable for non PIRQs
    268 		 */
    269 		ret = ec_set_irq_priority(irqno, ipl);
    270 		ASSERT(ret == 0);
    271 		CPUSET_ZERO(cpus);
    272 		CPUSET_ADD(cpus, 0);
    273 		ec_set_irq_affinity(irqno, cpus);
    274 		ec_enable_irq(irqno);
    275 	}
    276 
    277 	return (ret);
    278 }
    279 
    280 /*ARGSUSED*/
    281 static int
    282 xen_uppc_delspl(int irqno, int ipl, int min_ipl, int max_ipl)
    283 {
    284 	int err = PSM_SUCCESS;
    285 
    286 	if (irqno >= 0 && irqno <= MAX_ISA_IRQ)
    287 		atomic_add_16(&xen_uppc_irq_shared_table[irqno], -1);
    288 
    289 	if (irqno >= PIRQ_BASE && irqno < NR_PIRQS &&
    290 	    DOMAIN_IS_INITDOMAIN(xen_info)) {
    291 		if (max_ipl == PSM_INVALID_IPL) {
    292 			/*
    293 			 * unbind if no more sharers of this irq/evtchn
    294 			 */
    295 			(void) ec_block_irq(irqno);
    296 			ec_unbind_irq(irqno);
    297 		} else {
    298 			/*
    299 			 * If still in use reset priority
    300 			 */
    301 			err = ec_set_irq_priority(irqno, max_ipl);
    302 		}
    303 	} else {
    304 		(void) ec_block_irq(irqno);
    305 		ec_unbind_irq(irqno);
    306 	}
    307 	return (err);
    308 }
    309 
    310 static processorid_t
    311 xen_uppc_get_next_processorid(processorid_t id)
    312 {
    313 	if (id == -1)
    314 		return (0);
    315 	return (-1);
    316 }
    317 
    318 /*ARGSUSED*/
    319 static int
    320 xen_uppc_get_clockirq(int ipl)
    321 {
    322 	if (xen_clock_irq != -1)
    323 		return (xen_clock_irq);
    324 
    325 	xen_clock_irq = ec_bind_virq_to_irq(VIRQ_TIMER, 0);
    326 	return (xen_clock_irq);
    327 }
    328 
    329 /*ARGSUSED*/
    330 static void
    331 xen_uppc_shutdown(int cmd, int fcn)
    332 {
    333 	XEN_UPPC_VERBOSE_POWEROFF(("xen_uppc_shutdown(%d,%d);\n", cmd, fcn));
    334 
    335 	switch (cmd) {
    336 	case A_SHUTDOWN:
    337 		switch (fcn) {
    338 		case AD_BOOT:
    339 		case AD_IBOOT:
    340 			(void) HYPERVISOR_shutdown(SHUTDOWN_reboot);
    341 			break;
    342 		case AD_POWEROFF:
    343 			/* fall through if domU or if poweroff fails */
    344 			if (DOMAIN_IS_INITDOMAIN(xen_info))
    345 				if (xen_uppc_enable_acpi)
    346 					(void) acpi_poweroff();
    347 			/* FALLTHRU */
    348 		case AD_HALT:
    349 		default:
    350 			(void) HYPERVISOR_shutdown(SHUTDOWN_poweroff);
    351 			break;
    352 		}
    353 		break;
    354 	case A_REBOOT:
    355 		(void) HYPERVISOR_shutdown(SHUTDOWN_reboot);
    356 		break;
    357 	default:
    358 		return;
    359 	}
    360 }
    361 
    362 
    363 /*
    364  * This function will reprogram the timer.
    365  *
    366  * When in oneshot mode the argument is the absolute time in future at which to
    367  * generate the interrupt.
    368  *
    369  * When in periodic mode, the argument is the interval at which the
    370  * interrupts should be generated. There is no need to support the periodic
    371  * mode timer change at this time.
    372  *
    373  * Note that we must be careful to convert from hrtime to Xen system time (see
    374  * xpv_timestamp.c).
    375  */
    376 static void
    377 xen_uppc_timer_reprogram(hrtime_t timer_req)
    378 {
    379 	hrtime_t now, timer_new, time_delta, xen_time;
    380 	ulong_t flags;
    381 
    382 	flags = intr_clear();
    383 	/*
    384 	 * We should be called from high PIL context (CBE_HIGH_PIL),
    385 	 * so kpreempt is disabled.
    386 	 */
    387 
    388 	now = xpv_gethrtime();
    389 	xen_time = xpv_getsystime();
    390 	if (timer_req <= now) {
    391 		/*
    392 		 * requested to generate an interrupt in the past
    393 		 * generate an interrupt as soon as possible
    394 		 */
    395 		time_delta = XEN_NSEC_PER_TICK;
    396 	} else
    397 		time_delta = timer_req - now;
    398 
    399 	timer_new = xen_time + time_delta;
    400 	if (HYPERVISOR_set_timer_op(timer_new) != 0)
    401 		panic("can't set hypervisor timer?");
    402 	intr_restore(flags);
    403 }
    404 
    405 /*
    406  * This function will enable timer interrupts.
    407  */
    408 static void
    409 xen_uppc_timer_enable(void)
    410 {
    411 	ec_unmask_irq(xen_clock_irq);
    412 }
    413 
    414 /*
    415  * This function will disable timer interrupts on the current cpu.
    416  */
    417 static void
    418 xen_uppc_timer_disable(void)
    419 {
    420 	(void) ec_block_irq(xen_clock_irq);
    421 	/*
    422 	 * If the clock irq is pending on this cpu then we need to
    423 	 * clear the pending interrupt.
    424 	 */
    425 	ec_unpend_irq(xen_clock_irq);
    426 }
    427 
    428 
    429 /*
    430  * Configures the irq for the interrupt link device identified by
    431  * acpipsmlnkp.
    432  *
    433  * Gets the current and the list of possible irq settings for the
    434  * device. If xen_uppc_unconditional_srs is not set, and the current
    435  * resource setting is in the list of possible irq settings,
    436  * current irq resource setting is passed to the caller.
    437  *
    438  * Otherwise, picks an irq number from the list of possible irq
    439  * settings, and sets the irq of the device to this value.
    440  * If prefer_crs is set, among a set of irq numbers in the list that have
    441  * the least number of devices sharing the interrupt, we pick current irq
    442  * resource setting if it is a member of this set.
    443  *
    444  * Passes the irq number in the value pointed to by pci_irqp, and
    445  * polarity and sensitivity in the structure pointed to by dipintrflagp
    446  * to the caller.
    447  *
    448  * Note that if setting the irq resource failed, but successfuly obtained
    449  * the current irq resource settings, passes the current irq resources
    450  * and considers it a success.
    451  *
    452  * Returns:
    453  * ACPI_PSM_SUCCESS on success.
    454  *
    455  * ACPI_PSM_FAILURE if an error occured during the configuration or
    456  * if a suitable irq was not found for this device, or if setting the
    457  * irq resource and obtaining the current resource fails.
    458  *
    459  */
    460 static int
    461 xen_uppc_acpi_irq_configure(acpi_psm_lnk_t *acpipsmlnkp, dev_info_t *dip,
    462     int *pci_irqp, iflag_t *dipintr_flagp)
    463 {
    464 	int i, min_share, foundnow, done = 0;
    465 	int32_t irq;
    466 	int32_t share_irq = -1;
    467 	int32_t chosen_irq = -1;
    468 	int cur_irq = -1;
    469 	acpi_irqlist_t *irqlistp;
    470 	acpi_irqlist_t *irqlistent;
    471 
    472 	if ((acpi_get_possible_irq_resources(acpipsmlnkp, &irqlistp))
    473 	    == ACPI_PSM_FAILURE) {
    474 		XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: Unable to determine "
    475 		    "or assign IRQ for device %s, instance #%d: The system was "
    476 		    "unable to get the list of potential IRQs from ACPI.",
    477 		    ddi_get_name(dip), ddi_get_instance(dip)));
    478 
    479 		return (ACPI_PSM_FAILURE);
    480 	}
    481 
    482 	if ((acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq,
    483 	    dipintr_flagp) == ACPI_PSM_SUCCESS) &&
    484 	    (!xen_uppc_unconditional_srs) &&
    485 	    (cur_irq > 0)) {
    486 
    487 		if (acpi_irqlist_find_irq(irqlistp, cur_irq, NULL)
    488 		    == ACPI_PSM_SUCCESS) {
    489 
    490 			acpi_free_irqlist(irqlistp);
    491 			ASSERT(pci_irqp != NULL);
    492 			*pci_irqp = cur_irq;
    493 			return (ACPI_PSM_SUCCESS);
    494 		}
    495 		XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: Could not find the "
    496 		    "current irq %d for device %s, instance #%d in ACPI's "
    497 		    "list of possible irqs for this device. Picking one from "
    498 		    " the latter list.", cur_irq, ddi_get_name(dip),
    499 		    ddi_get_instance(dip)));
    500 
    501 	}
    502 
    503 	irqlistent = irqlistp;
    504 	min_share = 255;
    505 
    506 	while (irqlistent != NULL) {
    507 
    508 		for (foundnow = 0, i = 0; i < irqlistent->num_irqs; i++) {
    509 
    510 			irq = irqlistp->irqs[i];
    511 
    512 			if ((irq > MAX_ISA_IRQ) ||
    513 			    (irqlistent->intr_flags.intr_el == INTR_EL_EDGE) ||
    514 			    (irq == 0))
    515 				continue;
    516 
    517 			if (xen_uppc_reserved_irqlist[irq])
    518 				continue;
    519 
    520 			if (xen_uppc_irq_shared_table[irq] == 0) {
    521 				chosen_irq = irq;
    522 				foundnow = 1;
    523 				if (!(xen_uppc_prefer_crs) ||
    524 				    (irq == cur_irq)) {
    525 					done = 1;
    526 					break;
    527 				}
    528 			}
    529 
    530 			if ((xen_uppc_irq_shared_table[irq] < min_share) ||
    531 			    ((xen_uppc_irq_shared_table[irq] == min_share) &&
    532 			    (cur_irq == irq) && (xen_uppc_prefer_crs))) {
    533 				min_share = xen_uppc_irq_shared_table[irq];
    534 				share_irq = irq;
    535 				foundnow = 1;
    536 			}
    537 		}
    538 
    539 		/* If we found an IRQ in the inner loop, save the details */
    540 		if (foundnow && ((chosen_irq != -1) || (share_irq != -1))) {
    541 			/*
    542 			 * Copy the acpi_prs_private_t and flags from this
    543 			 * irq list entry, since we found an irq from this
    544 			 * entry.
    545 			 */
    546 			acpipsmlnkp->acpi_prs_prv = irqlistent->acpi_prs_prv;
    547 			*dipintr_flagp = irqlistent->intr_flags;
    548 		}
    549 
    550 		if (done)
    551 			break;
    552 
    553 		/* Load the next entry in the irqlist */
    554 		irqlistent = irqlistent->next;
    555 	}
    556 
    557 	acpi_free_irqlist(irqlistp);
    558 
    559 	if (chosen_irq != -1)
    560 		irq = chosen_irq;
    561 	else if (share_irq != -1)
    562 		irq = share_irq;
    563 	else {
    564 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Could not find a "
    565 		    "suitable irq from the list of possible irqs for device "
    566 		    "%s, instance #%d in ACPI's list of possible\n",
    567 		    ddi_get_name(dip), ddi_get_instance(dip)));
    568 
    569 		return (ACPI_PSM_FAILURE);
    570 	}
    571 
    572 
    573 	XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Setting irq %d "
    574 	    "for device %s instance #%d\n", irq, ddi_get_name(dip),
    575 	    ddi_get_instance(dip)));
    576 
    577 	if ((acpi_set_irq_resource(acpipsmlnkp, irq)) == ACPI_PSM_SUCCESS) {
    578 		/*
    579 		 * setting irq was successful, check to make sure CRS
    580 		 * reflects that. If CRS does not agree with what we
    581 		 * set, return the irq that was set.
    582 		 */
    583 
    584 		if (acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq,
    585 		    dipintr_flagp) == ACPI_PSM_SUCCESS) {
    586 
    587 			if (cur_irq != irq)
    588 				XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: "
    589 				    "IRQ resource set (irqno %d) for device %s "
    590 				    "instance #%d, differs from current "
    591 				    "setting irqno %d",
    592 				    irq, ddi_get_name(dip),
    593 				    ddi_get_instance(dip), cur_irq));
    594 		}
    595 		/*
    596 		 * return the irq that was set, and not what CRS reports,
    597 		 * since CRS has been seen to be bogus on some systems
    598 		 */
    599 		cur_irq = irq;
    600 	} else {
    601 		XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: set resource irq %d "
    602 		    "failed for device %s instance #%d",
    603 		    irq, ddi_get_name(dip), ddi_get_instance(dip)));
    604 		if (cur_irq == -1)
    605 			return (ACPI_PSM_FAILURE);
    606 	}
    607 
    608 	ASSERT(pci_irqp != NULL);
    609 	*pci_irqp = cur_irq;
    610 	return (ACPI_PSM_SUCCESS);
    611 }
    612 
    613 
    614 static int
    615 xen_uppc_acpi_translate_pci_irq(dev_info_t *dip, int busid, int devid,
    616     int ipin, int *pci_irqp, iflag_t *intr_flagp)
    617 {
    618 	int status;
    619 	acpi_psm_lnk_t acpipsmlnk;
    620 
    621 	if ((status = acpi_get_irq_cache_ent(busid, devid, ipin, pci_irqp,
    622 	    intr_flagp)) == ACPI_PSM_SUCCESS) {
    623 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Found irqno %d "
    624 		    "from cache for device %s, instance #%d\n", *pci_irqp,
    625 		    ddi_get_name(dip), ddi_get_instance(dip)));
    626 		return (status);
    627 	}
    628 
    629 	bzero(&acpipsmlnk, sizeof (acpi_psm_lnk_t));
    630 
    631 	if ((status = acpi_translate_pci_irq(dip, ipin, pci_irqp,
    632 	    intr_flagp, &acpipsmlnk)) == ACPI_PSM_FAILURE) {
    633 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: "
    634 		    " acpi_translate_pci_irq failed for device %s, instance"
    635 		    " #%d\n", ddi_get_name(dip), ddi_get_instance(dip)));
    636 
    637 		return (status);
    638 	}
    639 
    640 	if (status == ACPI_PSM_PARTIAL && acpipsmlnk.lnkobj != NULL) {
    641 		status = xen_uppc_acpi_irq_configure(&acpipsmlnk, dip, pci_irqp,
    642 		    intr_flagp);
    643 		if (status != ACPI_PSM_SUCCESS) {
    644 			status = acpi_get_current_irq_resource(&acpipsmlnk,
    645 			    pci_irqp, intr_flagp);
    646 		}
    647 	}
    648 
    649 	if (status == ACPI_PSM_SUCCESS) {
    650 		acpi_new_irq_cache_ent(busid, devid, ipin, *pci_irqp,
    651 		    intr_flagp, &acpipsmlnk);
    652 		psm_set_elcr(*pci_irqp, 1); 	/* set IRQ to PCI mode */
    653 
    654 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: [ACPI] "
    655 		    "new irq %d for device %s, instance #%d\n",
    656 		    *pci_irqp, ddi_get_name(dip), ddi_get_instance(dip)));
    657 	}
    658 
    659 	return (status);
    660 }
    661 
    662 
    663 /*ARGSUSED*/
    664 static int
    665 xen_uppc_translate_irq(dev_info_t *dip, int irqno)
    666 {
    667 	char dev_type[16];
    668 	int dev_len, pci_irq, devid, busid;
    669 	ddi_acc_handle_t cfg_handle;
    670 	uchar_t ipin, iline;
    671 	iflag_t intr_flag;
    672 
    673 	if (dip == NULL) {
    674 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: irqno = %d"
    675 		    " dip = NULL\n", irqno));
    676 		return (irqno);
    677 	}
    678 
    679 	if (!xen_uppc_enable_acpi) {
    680 		return (irqno);
    681 	}
    682 
    683 	dev_len = sizeof (dev_type);
    684 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(dip),
    685 	    DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type,
    686 	    &dev_len) != DDI_PROP_SUCCESS) {
    687 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: irqno %d"
    688 		    " device %s instance %d no device_type\n", irqno,
    689 		    ddi_get_name(dip), ddi_get_instance(dip)));
    690 		return (irqno);
    691 	}
    692 
    693 	if ((strcmp(dev_type, "pci") == 0) ||
    694 	    (strcmp(dev_type, "pciex") == 0)) {
    695 
    696 		/* pci device */
    697 		if (acpica_get_bdf(dip, &busid, &devid, NULL) != 0)
    698 			return (irqno);
    699 
    700 		if (pci_config_setup(dip, &cfg_handle) != DDI_SUCCESS)
    701 			return (irqno);
    702 
    703 		ipin = pci_config_get8(cfg_handle, PCI_CONF_IPIN) - PCI_INTA;
    704 		iline = pci_config_get8(cfg_handle, PCI_CONF_ILINE);
    705 		if (xen_uppc_acpi_translate_pci_irq(dip, busid, devid,
    706 		    ipin, &pci_irq, &intr_flag) == ACPI_PSM_SUCCESS) {
    707 
    708 			XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: [ACPI] "
    709 			    "new irq %d old irq %d device %s, instance %d\n",
    710 			    pci_irq, irqno, ddi_get_name(dip),
    711 			    ddi_get_instance(dip)));
    712 
    713 			/*
    714 			 * Make sure pci_irq is within range.
    715 			 * Otherwise, fall through and return irqno.
    716 			 */
    717 			if (pci_irq <= MAX_ISA_IRQ) {
    718 				if (iline != pci_irq) {
    719 					/*
    720 					 * Update the device's ILINE byte,
    721 					 * in case uppc_acpi_translate_pci_irq
    722 					 * has choosen a different pci_irq
    723 					 * than the BIOS has configured.
    724 					 * Some chipsets use the value in
    725 					 * ILINE to control interrupt routing,
    726 					 * in conflict with the PCI spec.
    727 					 */
    728 					pci_config_put8(cfg_handle,
    729 					    PCI_CONF_ILINE, pci_irq);
    730 				}
    731 				pci_config_teardown(&cfg_handle);
    732 				return (pci_irq);
    733 			}
    734 		}
    735 		pci_config_teardown(&cfg_handle);
    736 
    737 		/* FALLTHRU to common case - returning irqno */
    738 	} else {
    739 		/* non-PCI; assumes ISA-style edge-triggered */
    740 		psm_set_elcr(irqno, 0); 	/* set IRQ to ISA mode */
    741 
    742 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: non-pci,"
    743 		    "irqno %d device %s instance %d\n", irqno,
    744 		    ddi_get_name(dip), ddi_get_instance(dip)));
    745 	}
    746 
    747 	return (irqno);
    748 }
    749 
    750 /*
    751  * xen_uppc_intr_enter() acks the event that triggered the interrupt and
    752  * returns the new priority level,
    753  */
    754 /*ARGSUSED*/
    755 static int
    756 xen_uppc_intr_enter(int ipl, int *vector)
    757 {
    758 	int newipl;
    759 	uint_t intno;
    760 	cpu_t *cpu = CPU;
    761 
    762 	intno = (*vector);
    763 
    764 	ASSERT(intno < NR_IRQS);
    765 	ASSERT(cpu->cpu_m.mcpu_vcpu_info->evtchn_upcall_mask != 0);
    766 
    767 	ec_clear_irq(intno);
    768 
    769 	newipl = autovect[intno].avh_hi_pri;
    770 	if (newipl == 0) {
    771 		/*
    772 		 * (newipl == 0) means we have no service routines for this
    773 		 * vector.  We will treat this as a spurious interrupt.
    774 		 * We have cleared the pending bit already, clear the event
    775 		 * mask and return a spurious interrupt.  This case can happen
    776 		 * when an interrupt delivery is racing with the removal of
    777 		 * of the service routine for that interrupt.
    778 		 */
    779 		ec_unmask_irq(intno);
    780 		newipl = -1;	/* flag spurious interrupt */
    781 	} else if (newipl <= cpu->cpu_pri) {
    782 		/*
    783 		 * (newipl <= cpu->cpu_pri) means that we must be trying to
    784 		 * service a vector that was shared with a higher priority
    785 		 * isr.  The higher priority handler has been removed and
    786 		 * we need to service this int.  We can't return a lower
    787 		 * priority than current cpu priority.  Just synthesize a
    788 		 * priority to return that should be acceptable.
    789 		 */
    790 		newipl = cpu->cpu_pri + 1;	/* synthetic priority */
    791 	}
    792 	return (newipl);
    793 }
    794 
    795 
    796 static void xen_uppc_setspl(int);
    797 
    798 /*
    799  * xen_uppc_intr_exit() restores the old interrupt
    800  * priority level after processing an interrupt.
    801  * It is called with interrupts disabled, and does not enable interrupts.
    802  */
    803 /* ARGSUSED */
    804 static void
    805 xen_uppc_intr_exit(int ipl, int vector)
    806 {
    807 	ec_try_unmask_irq(vector);
    808 	xen_uppc_setspl(ipl);
    809 }
    810 
    811 intr_exit_fn_t
    812 psm_intr_exit_fn(void)
    813 {
    814 	return (xen_uppc_intr_exit);
    815 }
    816 
    817 /*
    818  * Check if new ipl level allows delivery of previously unserviced events
    819  */
    820 static void
    821 xen_uppc_setspl(int ipl)
    822 {
    823 	struct cpu *cpu = CPU;
    824 	volatile vcpu_info_t *vci = cpu->cpu_m.mcpu_vcpu_info;
    825 	uint16_t pending;
    826 
    827 	ASSERT(vci->evtchn_upcall_mask != 0);
    828 
    829 	/*
    830 	 * If new ipl level will enable any pending interrupts, setup so the
    831 	 * upcoming sti will cause us to get an upcall.
    832 	 */
    833 	pending = cpu->cpu_m.mcpu_intr_pending & ~((1 << (ipl + 1)) - 1);
    834 	if (pending) {
    835 		int i;
    836 		ulong_t pending_sels = 0;
    837 		volatile ulong_t *selp;
    838 		struct xen_evt_data *cpe = cpu->cpu_m.mcpu_evt_pend;
    839 
    840 		for (i = bsrw_insn(pending); i > ipl; i--)
    841 			pending_sels |= cpe->pending_sel[i];
    842 		ASSERT(pending_sels);
    843 		selp = (volatile ulong_t *)&vci->evtchn_pending_sel;
    844 		atomic_or_ulong(selp, pending_sels);
    845 		vci->evtchn_upcall_pending = 1;
    846 	}
    847 }
    848 
    849 /*
    850  * The rest of the file is just generic psm module boilerplate
    851  */
    852 
    853 static struct psm_ops xen_uppc_ops = {
    854 	xen_uppc_probe,				/* psm_probe		*/
    855 
    856 	xen_uppc_softinit,			/* psm_init		*/
    857 	xen_uppc_picinit,			/* psm_picinit		*/
    858 	xen_uppc_intr_enter,			/* psm_intr_enter	*/
    859 	xen_uppc_intr_exit,			/* psm_intr_exit	*/
    860 	xen_uppc_setspl,			/* psm_setspl		*/
    861 	xen_uppc_addspl,			/* psm_addspl		*/
    862 	xen_uppc_delspl,			/* psm_delspl		*/
    863 	(int (*)(processorid_t))NULL,		/* psm_disable_intr	*/
    864 	(void (*)(processorid_t))NULL,		/* psm_enable_intr	*/
    865 	(int (*)(int))NULL,			/* psm_softlvl_to_irq	*/
    866 	(void (*)(int))NULL,			/* psm_set_softintr	*/
    867 	(void (*)(processorid_t))NULL,		/* psm_set_idlecpu	*/
    868 	(void (*)(processorid_t))NULL,		/* psm_unset_idlecpu	*/
    869 
    870 	xen_uppc_clkinit,			/* psm_clkinit		*/
    871 	xen_uppc_get_clockirq,			/* psm_get_clockirq	*/
    872 	(void (*)(void))NULL,			/* psm_hrtimeinit	*/
    873 	xpv_gethrtime,				/* psm_gethrtime	*/
    874 
    875 	xen_uppc_get_next_processorid,		/* psm_get_next_processorid */
    876 	(int (*)(processorid_t, caddr_t))NULL,	/* psm_cpu_start	*/
    877 	(int (*)(void))NULL,			/* psm_post_cpu_start	*/
    878 	xen_uppc_shutdown,			/* psm_shutdown		*/
    879 	(int (*)(int, int))NULL,		/* psm_get_ipivect	*/
    880 	(void (*)(processorid_t, int))NULL,	/* psm_send_ipi		*/
    881 
    882 	xen_uppc_translate_irq,			/* psm_translate_irq	*/
    883 
    884 	(void (*)(int, char *))NULL,		/* psm_notify_error	*/
    885 	(void (*)(int msg))NULL,		/* psm_notify_func	*/
    886 	xen_uppc_timer_reprogram,		/* psm_timer_reprogram	*/
    887 	xen_uppc_timer_enable,			/* psm_timer_enable	*/
    888 	xen_uppc_timer_disable,			/* psm_timer_disable	*/
    889 	(void (*)(void *arg))NULL,		/* psm_post_cyclic_setup */
    890 	(void (*)(int, int))NULL,		/* psm_preshutdown	*/
    891 
    892 	(int (*)(dev_info_t *, ddi_intr_handle_impl_t *,
    893 	    psm_intr_op_t, int *))NULL,		/* psm_intr_ops		*/
    894 	(int (*)(psm_state_request_t *))NULL	/* psm_state		*/
    895 };
    896 
    897 static struct psm_info xen_uppc_info = {
    898 	PSM_INFO_VER01_5,	/* version				*/
    899 	PSM_OWN_SYS_DEFAULT,	/* ownership				*/
    900 	&xen_uppc_ops,		/* operation				*/
    901 	"xVM_uppc",		/* machine name				*/
    902 	"UniProcessor PC"	/* machine descriptions			*/
    903 };
    904 
    905 static void *xen_uppc_hdlp;
    906 
    907 int
    908 _init(void)
    909 {
    910 	return (psm_mod_init(&xen_uppc_hdlp, &xen_uppc_info));
    911 }
    912 
    913 int
    914 _fini(void)
    915 {
    916 	return (psm_mod_fini(&xen_uppc_hdlp, &xen_uppc_info));
    917 }
    918 
    919 int
    920 _info(struct modinfo *modinfop)
    921 {
    922 	return (psm_mod_info(&xen_uppc_hdlp, &xen_uppc_info, modinfop));
    923 }
    924