xref: /onnv-gate/usr/src/uts/i86xpv/io/psm/xpv_uppc.c (revision 12004:93f274d4a367)
16356Smrj /*
26356Smrj  * CDDL HEADER START
36356Smrj  *
46356Smrj  * The contents of this file are subject to the terms of the
56356Smrj  * Common Development and Distribution License (the "License").
66356Smrj  * You may not use this file except in compliance with the License.
76356Smrj  *
86356Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96356Smrj  * or http://www.opensolaris.org/os/licensing.
106356Smrj  * See the License for the specific language governing permissions
116356Smrj  * and limitations under the License.
126356Smrj  *
136356Smrj  * When distributing Covered Code, include this CDDL HEADER in each
146356Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156356Smrj  * If applicable, add the following below this CDDL HEADER, with the
166356Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
176356Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
186356Smrj  *
196356Smrj  * CDDL HEADER END
206356Smrj  */
216356Smrj 
226356Smrj /*
236356Smrj  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
246356Smrj  * Use is subject to license terms.
256356Smrj  */
266356Smrj 
27*12004Sjiang.liu@intel.com #define	PSMI_1_7
286356Smrj 
296356Smrj #include <sys/mutex.h>
306356Smrj #include <sys/types.h>
316356Smrj #include <sys/time.h>
326356Smrj #include <sys/clock.h>
336356Smrj #include <sys/machlock.h>
346356Smrj #include <sys/smp_impldefs.h>
356356Smrj #include <sys/uadmin.h>
366356Smrj #include <sys/promif.h>
376356Smrj #include <sys/psm.h>
386356Smrj #include <sys/psm_common.h>
396356Smrj #include <sys/atomic.h>
406356Smrj #include <sys/archsystm.h>
416356Smrj #include <sys/mach_intr.h>
426356Smrj #include <sys/hypervisor.h>
436356Smrj #include <sys/evtchn_impl.h>
446356Smrj #include <sys/modctl.h>
456356Smrj #include <sys/trap.h>
466356Smrj #include <sys/panic.h>
476356Smrj 
486356Smrj #include <xen/public/vcpu.h>
496356Smrj #include <xen/public/physdev.h>
506356Smrj 
516356Smrj 
526356Smrj /*
536356Smrj  * Global Data
546356Smrj  */
556356Smrj int xen_uppc_use_acpi = 1;	/* Use ACPI by default */
566356Smrj int xen_uppc_enable_acpi = 0;
576356Smrj 
586356Smrj static int xen_clock_irq = -1;
596356Smrj 
606356Smrj /*
616356Smrj  * For interrupt link devices, if xen_uppc_unconditional_srs is set, an irq
626356Smrj  * resource will be assigned (via _SRS). If it is not set, use the current
636356Smrj  * irq setting (via _CRS), but only if that irq is in the set of possible
646356Smrj  * irqs (returned by _PRS) for the device.
656356Smrj  */
666356Smrj int xen_uppc_unconditional_srs = 1;
676356Smrj 
686356Smrj /*
696356Smrj  * For interrupt link devices, if xen_uppc_prefer_crs is set when we are
706356Smrj  * assigning an IRQ resource to a device, prefer the current IRQ setting
716356Smrj  * over other possible irq settings under same conditions.
726356Smrj  */
736356Smrj int xen_uppc_prefer_crs = 1;
746356Smrj 
756356Smrj int xen_uppc_verbose = 0;
766356Smrj 
776356Smrj /* flag definitions for xen_uppc_verbose */
786356Smrj #define	XEN_UPPC_VERBOSE_IRQ_FLAG		0x00000001
796356Smrj #define	XEN_UPPC_VERBOSE_POWEROFF_FLAG		0x00000002
806356Smrj #define	XEN_UPPC_VERBOSE_POWEROFF_PAUSE_FLAG	0x00000004
816356Smrj 
826356Smrj #define	XEN_UPPC_VERBOSE_IRQ(fmt) \
836356Smrj 	if (xen_uppc_verbose & XEN_UPPC_VERBOSE_IRQ_FLAG) \
846356Smrj 		cmn_err fmt;
856356Smrj 
866356Smrj #define	XEN_UPPC_VERBOSE_POWEROFF(fmt) \
876356Smrj 	if (xen_uppc_verbose & XEN_UPPC_VERBOSE_POWEROFF_FLAG) \
886356Smrj 		prom_printf fmt;
896356Smrj 
906356Smrj uchar_t xen_uppc_reserved_irqlist[MAX_ISA_IRQ + 1];
916356Smrj 
926356Smrj static uint16_t xen_uppc_irq_shared_table[MAX_ISA_IRQ + 1];
936356Smrj 
946356Smrj /*
956356Smrj  * Contains SCI irqno from FADT after initialization
966356Smrj  */
976356Smrj static int xen_uppc_sci = -1;
986356Smrj 
996356Smrj static struct psm_info xen_uppc_info;
1006356Smrj 
1016356Smrj /*
1026356Smrj  * Local support routines
1036356Smrj  */
1046356Smrj 
1056356Smrj static int
xen_uppc_init_acpi(void)1066356Smrj xen_uppc_init_acpi(void)
1076356Smrj {
1086356Smrj 	int verboseflags = 0;
1096356Smrj 	int	sci;
1106356Smrj 	iflag_t sci_flags;
1116356Smrj 
1126356Smrj 	/*
1136356Smrj 	 * Process SCI configuration here; this may return
1146356Smrj 	 * an error if acpi-user-options has specified
1156356Smrj 	 * legacy mode (use ACPI without ACPI mode or SCI)
1166356Smrj 	 */
1176356Smrj 	if (acpica_get_sci(&sci, &sci_flags) != AE_OK)
1186356Smrj 		sci = -1;
1196356Smrj 
1206356Smrj 	/*
1216356Smrj 	 * Initialize sub-system - if error is returns, ACPI is not
1226356Smrj 	 * used.
1236356Smrj 	 */
1246356Smrj 	if (acpica_init() != AE_OK)
1256356Smrj 		return (0);
1266356Smrj 
1276356Smrj 	/*
1286356Smrj 	 * uppc implies system is in PIC mode; set edge/level
1296356Smrj 	 * via ELCR based on return value from get_sci; this
1306356Smrj 	 * will default to level/low if no override present,
1316356Smrj 	 * as recommended by Intel ACPI CA team.
1326356Smrj 	 */
1336356Smrj 	if (sci >= 0) {
1346356Smrj 		ASSERT((sci_flags.intr_el == INTR_EL_LEVEL) ||
1356356Smrj 		    (sci_flags.intr_el == INTR_EL_EDGE));
1366356Smrj 
1376356Smrj 		psm_set_elcr(sci, sci_flags.intr_el == INTR_EL_LEVEL);
1386356Smrj 	}
1396356Smrj 
1406356Smrj 	/*
1416356Smrj 	 * Remember SCI for later use
1426356Smrj 	 */
1436356Smrj 	xen_uppc_sci = sci;
1446356Smrj 
1456356Smrj 	if (xen_uppc_verbose & XEN_UPPC_VERBOSE_IRQ_FLAG)
1466356Smrj 		verboseflags |= PSM_VERBOSE_IRQ_FLAG;
1476356Smrj 
1486356Smrj 	if (xen_uppc_verbose & XEN_UPPC_VERBOSE_POWEROFF_FLAG)
1496356Smrj 		verboseflags |= PSM_VERBOSE_POWEROFF_FLAG;
1506356Smrj 
1516356Smrj 	if (xen_uppc_verbose & XEN_UPPC_VERBOSE_POWEROFF_PAUSE_FLAG)
1526356Smrj 		verboseflags |= PSM_VERBOSE_POWEROFF_PAUSE_FLAG;
1536356Smrj 
1546356Smrj 	if (acpi_psm_init(xen_uppc_info.p_mach_idstring, verboseflags) ==
1556356Smrj 	    ACPI_PSM_FAILURE) {
1566356Smrj 		return (0);
1576356Smrj 	}
1586356Smrj 
1596356Smrj 	return (1);
1606356Smrj }
1616356Smrj 
1626356Smrj /*
1636356Smrj  * Autoconfiguration Routines
1646356Smrj  */
1656356Smrj 
1666356Smrj static int
xen_uppc_probe(void)1676356Smrj xen_uppc_probe(void)
1686356Smrj {
1696356Smrj 
1706356Smrj 	return (PSM_SUCCESS);
1716356Smrj }
1726356Smrj 
1736356Smrj static void
xen_uppc_softinit(void)1746356Smrj xen_uppc_softinit(void)
1756356Smrj {
1766356Smrj 	int i;
1776356Smrj 
1786356Smrj 	/* LINTED logical expression always true: op "||" */
1796356Smrj 	ASSERT((1 << EVTCHN_SHIFT) == NBBY * sizeof (ulong_t));
1806356Smrj 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
1816356Smrj 		if (xen_uppc_use_acpi && xen_uppc_init_acpi()) {
1826356Smrj 			build_reserved_irqlist((uchar_t *)
1836356Smrj 			    xen_uppc_reserved_irqlist);
1846356Smrj 			for (i = 0; i <= MAX_ISA_IRQ; i++)
1856356Smrj 				xen_uppc_irq_shared_table[i] = 0;
1866356Smrj 			xen_uppc_enable_acpi = 1;
1876356Smrj 		}
1886356Smrj 	}
1896356Smrj }
1906356Smrj 
1916356Smrj 
1926356Smrj #define	XEN_NSEC_PER_TICK	10 /* XXX - assume we have a 100 Mhz clock */
1936356Smrj 
1946356Smrj /*ARGSUSED*/
1956356Smrj static int
xen_uppc_clkinit(int hertz)1966356Smrj xen_uppc_clkinit(int hertz)
1976356Smrj {
1986356Smrj 	extern enum tod_fault_type tod_fault(enum tod_fault_type, int);
1996356Smrj 	extern int dosynctodr;
2006356Smrj 
2016356Smrj 	/*
2026356Smrj 	 * domU cannot set the TOD hardware, fault the TOD clock now to
2036356Smrj 	 * indicate that and turn off attempts to sync TOD hardware
2046356Smrj 	 * with the hires timer.
2056356Smrj 	 */
2066356Smrj 	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
2076356Smrj 		mutex_enter(&tod_lock);
2086356Smrj 		(void) tod_fault(TOD_RDONLY, 0);
2096356Smrj 		dosynctodr = 0;
2106356Smrj 		mutex_exit(&tod_lock);
2116356Smrj 	}
2126356Smrj 	/*
2136356Smrj 	 * The hypervisor provides a timer based on the local APIC timer.
2146356Smrj 	 * The interface supports requests of nanosecond resolution.
2156356Smrj 	 * A common frequency of the apic clock is 100 Mhz which
2166356Smrj 	 * gives a resolution of 10 nsec per tick.  What we would really like
2176356Smrj 	 * is a way to get the ns per tick value from xen.
2186356Smrj 	 * XXPV - This is an assumption that needs checking and may change
2196356Smrj 	 */
2206356Smrj 	return (XEN_NSEC_PER_TICK);
2216356Smrj }
2226356Smrj 
2236356Smrj static void
xen_uppc_picinit()2246356Smrj xen_uppc_picinit()
2256356Smrj {
2266356Smrj 	int irqno;
2276356Smrj 
2286356Smrj 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
2296356Smrj #if 0
2306356Smrj 		/* hypervisor initializes the 8259, don't mess with it */
2316356Smrj 		picsetup();	 /* initialise the 8259 */
2326356Smrj #endif
2336356Smrj 		/*
2346356Smrj 		 * We never called xen_uppc_addspl() when the SCI
2356356Smrj 		 * interrupt was added because that happened before the
2366356Smrj 		 * PSM module was loaded.  Fix that up here by doing
2376356Smrj 		 * any missed operations (e.g. bind to CPU)
2386356Smrj 		 */
2396356Smrj 		if ((irqno = xen_uppc_sci) >= 0) {
2406356Smrj 			ec_enable_irq(irqno);
2416356Smrj 		}
2426356Smrj 	}
2436356Smrj }
2446356Smrj 
2456356Smrj 
2466356Smrj /*ARGSUSED*/
2476356Smrj static int
xen_uppc_addspl(int irqno,int ipl,int min_ipl,int max_ipl)2486356Smrj xen_uppc_addspl(int irqno, int ipl, int min_ipl, int max_ipl)
2496356Smrj {
2506356Smrj 	int ret = PSM_SUCCESS;
2516356Smrj 	cpuset_t cpus;
2526356Smrj 
2536356Smrj 	if (irqno >= 0 && irqno <= MAX_ISA_IRQ)
2546356Smrj 		atomic_add_16(&xen_uppc_irq_shared_table[irqno], 1);
2556356Smrj 
2566356Smrj 	/*
2576356Smrj 	 * We are called at splhi() so we can't call anything that might end
2586356Smrj 	 * up trying to context switch.
2596356Smrj 	 */
2606356Smrj 	if (irqno >= PIRQ_BASE && irqno < NR_PIRQS &&
2616356Smrj 	    DOMAIN_IS_INITDOMAIN(xen_info)) {
2626356Smrj 		CPUSET_ZERO(cpus);
2636356Smrj 		CPUSET_ADD(cpus, 0);
2646356Smrj 		ec_setup_pirq(irqno, ipl, &cpus);
2656356Smrj 	} else {
2666356Smrj 		/*
2676356Smrj 		 * Set priority/affinity/enable for non PIRQs
2686356Smrj 		 */
2696356Smrj 		ret = ec_set_irq_priority(irqno, ipl);
2706356Smrj 		ASSERT(ret == 0);
2716356Smrj 		CPUSET_ZERO(cpus);
2726356Smrj 		CPUSET_ADD(cpus, 0);
2736356Smrj 		ec_set_irq_affinity(irqno, cpus);
2746356Smrj 		ec_enable_irq(irqno);
2756356Smrj 	}
2766356Smrj 
2776356Smrj 	return (ret);
2786356Smrj }
2796356Smrj 
2806356Smrj /*ARGSUSED*/
2816356Smrj static int
xen_uppc_delspl(int irqno,int ipl,int min_ipl,int max_ipl)2826356Smrj xen_uppc_delspl(int irqno, int ipl, int min_ipl, int max_ipl)
2836356Smrj {
2846356Smrj 	int err = PSM_SUCCESS;
2856356Smrj 
2866356Smrj 	if (irqno >= 0 && irqno <= MAX_ISA_IRQ)
2876356Smrj 		atomic_add_16(&xen_uppc_irq_shared_table[irqno], -1);
2886356Smrj 
2896356Smrj 	if (irqno >= PIRQ_BASE && irqno < NR_PIRQS &&
2906356Smrj 	    DOMAIN_IS_INITDOMAIN(xen_info)) {
2916356Smrj 		if (max_ipl == PSM_INVALID_IPL) {
2926356Smrj 			/*
2936356Smrj 			 * unbind if no more sharers of this irq/evtchn
2946356Smrj 			 */
2956356Smrj 			(void) ec_block_irq(irqno);
2966356Smrj 			ec_unbind_irq(irqno);
2976356Smrj 		} else {
2986356Smrj 			/*
2996356Smrj 			 * If still in use reset priority
3006356Smrj 			 */
3016356Smrj 			err = ec_set_irq_priority(irqno, max_ipl);
3026356Smrj 		}
3036356Smrj 	} else {
3046356Smrj 		(void) ec_block_irq(irqno);
3056356Smrj 		ec_unbind_irq(irqno);
3066356Smrj 	}
3076356Smrj 	return (err);
3086356Smrj }
3096356Smrj 
3106356Smrj static processorid_t
xen_uppc_get_next_processorid(processorid_t id)3116356Smrj xen_uppc_get_next_processorid(processorid_t id)
3126356Smrj {
3136356Smrj 	if (id == -1)
3146356Smrj 		return (0);
3156356Smrj 	return (-1);
3166356Smrj }
3176356Smrj 
3186356Smrj /*ARGSUSED*/
3196356Smrj static int
xen_uppc_get_clockirq(int ipl)3206356Smrj xen_uppc_get_clockirq(int ipl)
3216356Smrj {
3226356Smrj 	if (xen_clock_irq != -1)
3236356Smrj 		return (xen_clock_irq);
3246356Smrj 
3256356Smrj 	xen_clock_irq = ec_bind_virq_to_irq(VIRQ_TIMER, 0);
3266356Smrj 	return (xen_clock_irq);
3276356Smrj }
3286356Smrj 
3296356Smrj /*ARGSUSED*/
3306356Smrj static void
xen_uppc_shutdown(int cmd,int fcn)3316356Smrj xen_uppc_shutdown(int cmd, int fcn)
3326356Smrj {
3336356Smrj 	XEN_UPPC_VERBOSE_POWEROFF(("xen_uppc_shutdown(%d,%d);\n", cmd, fcn));
3346356Smrj 
3356356Smrj 	switch (cmd) {
3366356Smrj 	case A_SHUTDOWN:
3376356Smrj 		switch (fcn) {
3386356Smrj 		case AD_BOOT:
3396356Smrj 		case AD_IBOOT:
3406356Smrj 			(void) HYPERVISOR_shutdown(SHUTDOWN_reboot);
3416356Smrj 			break;
3426356Smrj 		case AD_POWEROFF:
3436356Smrj 			/* fall through if domU or if poweroff fails */
3446356Smrj 			if (DOMAIN_IS_INITDOMAIN(xen_info))
3456356Smrj 				if (xen_uppc_enable_acpi)
3466356Smrj 					(void) acpi_poweroff();
3476356Smrj 			/* FALLTHRU */
3486356Smrj 		case AD_HALT:
3496356Smrj 		default:
3506356Smrj 			(void) HYPERVISOR_shutdown(SHUTDOWN_poweroff);
3516356Smrj 			break;
3526356Smrj 		}
3536356Smrj 		break;
3546356Smrj 	case A_REBOOT:
3556356Smrj 		(void) HYPERVISOR_shutdown(SHUTDOWN_reboot);
3566356Smrj 		break;
3576356Smrj 	default:
3586356Smrj 		return;
3596356Smrj 	}
3606356Smrj }
3616356Smrj 
3626356Smrj 
3636356Smrj /*
3646356Smrj  * This function will reprogram the timer.
3656356Smrj  *
3666356Smrj  * When in oneshot mode the argument is the absolute time in future at which to
3676356Smrj  * generate the interrupt.
3686356Smrj  *
3696356Smrj  * When in periodic mode, the argument is the interval at which the
3706356Smrj  * interrupts should be generated. There is no need to support the periodic
3716356Smrj  * mode timer change at this time.
3726356Smrj  *
3736356Smrj  * Note that we must be careful to convert from hrtime to Xen system time (see
3746356Smrj  * xpv_timestamp.c).
3756356Smrj  */
3766356Smrj static void
xen_uppc_timer_reprogram(hrtime_t timer_req)3776356Smrj xen_uppc_timer_reprogram(hrtime_t timer_req)
3786356Smrj {
3796356Smrj 	hrtime_t now, timer_new, time_delta, xen_time;
3806356Smrj 	ulong_t flags;
3816356Smrj 
3826356Smrj 	flags = intr_clear();
3836356Smrj 	/*
3846356Smrj 	 * We should be called from high PIL context (CBE_HIGH_PIL),
3856356Smrj 	 * so kpreempt is disabled.
3866356Smrj 	 */
3876356Smrj 
3886356Smrj 	now = xpv_gethrtime();
3896356Smrj 	xen_time = xpv_getsystime();
3906356Smrj 	if (timer_req <= now) {
3916356Smrj 		/*
3926356Smrj 		 * requested to generate an interrupt in the past
3936356Smrj 		 * generate an interrupt as soon as possible
3946356Smrj 		 */
3956356Smrj 		time_delta = XEN_NSEC_PER_TICK;
3966356Smrj 	} else
3976356Smrj 		time_delta = timer_req - now;
3986356Smrj 
3996356Smrj 	timer_new = xen_time + time_delta;
4006356Smrj 	if (HYPERVISOR_set_timer_op(timer_new) != 0)
4016356Smrj 		panic("can't set hypervisor timer?");
4026356Smrj 	intr_restore(flags);
4036356Smrj }
4046356Smrj 
4056356Smrj /*
4066356Smrj  * This function will enable timer interrupts.
4076356Smrj  */
4086356Smrj static void
xen_uppc_timer_enable(void)4096356Smrj xen_uppc_timer_enable(void)
4106356Smrj {
4116356Smrj 	ec_unmask_irq(xen_clock_irq);
4126356Smrj }
4136356Smrj 
4146356Smrj /*
4156356Smrj  * This function will disable timer interrupts on the current cpu.
4166356Smrj  */
4176356Smrj static void
xen_uppc_timer_disable(void)4186356Smrj xen_uppc_timer_disable(void)
4196356Smrj {
4206356Smrj 	(void) ec_block_irq(xen_clock_irq);
4216356Smrj 	/*
4226356Smrj 	 * If the clock irq is pending on this cpu then we need to
4236356Smrj 	 * clear the pending interrupt.
4246356Smrj 	 */
4256356Smrj 	ec_unpend_irq(xen_clock_irq);
4266356Smrj }
4276356Smrj 
4286356Smrj 
4296356Smrj /*
4306356Smrj  * Configures the irq for the interrupt link device identified by
4316356Smrj  * acpipsmlnkp.
4326356Smrj  *
4336356Smrj  * Gets the current and the list of possible irq settings for the
4346356Smrj  * device. If xen_uppc_unconditional_srs is not set, and the current
4356356Smrj  * resource setting is in the list of possible irq settings,
4366356Smrj  * current irq resource setting is passed to the caller.
4376356Smrj  *
4386356Smrj  * Otherwise, picks an irq number from the list of possible irq
4396356Smrj  * settings, and sets the irq of the device to this value.
4406356Smrj  * If prefer_crs is set, among a set of irq numbers in the list that have
4416356Smrj  * the least number of devices sharing the interrupt, we pick current irq
4426356Smrj  * resource setting if it is a member of this set.
4436356Smrj  *
4446356Smrj  * Passes the irq number in the value pointed to by pci_irqp, and
4456356Smrj  * polarity and sensitivity in the structure pointed to by dipintrflagp
4466356Smrj  * to the caller.
4476356Smrj  *
4486356Smrj  * Note that if setting the irq resource failed, but successfuly obtained
4496356Smrj  * the current irq resource settings, passes the current irq resources
4506356Smrj  * and considers it a success.
4516356Smrj  *
4526356Smrj  * Returns:
4536356Smrj  * ACPI_PSM_SUCCESS on success.
4546356Smrj  *
4556356Smrj  * ACPI_PSM_FAILURE if an error occured during the configuration or
4566356Smrj  * if a suitable irq was not found for this device, or if setting the
4576356Smrj  * irq resource and obtaining the current resource fails.
4586356Smrj  *
4596356Smrj  */
4606356Smrj static int
xen_uppc_acpi_irq_configure(acpi_psm_lnk_t * acpipsmlnkp,dev_info_t * dip,int * pci_irqp,iflag_t * dipintr_flagp)4616356Smrj xen_uppc_acpi_irq_configure(acpi_psm_lnk_t *acpipsmlnkp, dev_info_t *dip,
4626356Smrj     int *pci_irqp, iflag_t *dipintr_flagp)
4636356Smrj {
4646356Smrj 	int i, min_share, foundnow, done = 0;
4656356Smrj 	int32_t irq;
4666356Smrj 	int32_t share_irq = -1;
4676356Smrj 	int32_t chosen_irq = -1;
4686356Smrj 	int cur_irq = -1;
4696356Smrj 	acpi_irqlist_t *irqlistp;
4706356Smrj 	acpi_irqlist_t *irqlistent;
4716356Smrj 
4726356Smrj 	if ((acpi_get_possible_irq_resources(acpipsmlnkp, &irqlistp))
4736356Smrj 	    == ACPI_PSM_FAILURE) {
4746356Smrj 		XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: Unable to determine "
4756356Smrj 		    "or assign IRQ for device %s, instance #%d: The system was "
4766356Smrj 		    "unable to get the list of potential IRQs from ACPI.",
4776356Smrj 		    ddi_get_name(dip), ddi_get_instance(dip)));
4786356Smrj 
4796356Smrj 		return (ACPI_PSM_FAILURE);
4806356Smrj 	}
4816356Smrj 
4826356Smrj 	if ((acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq,
4836356Smrj 	    dipintr_flagp) == ACPI_PSM_SUCCESS) &&
4846356Smrj 	    (!xen_uppc_unconditional_srs) &&
4856356Smrj 	    (cur_irq > 0)) {
4866356Smrj 
4876356Smrj 		if (acpi_irqlist_find_irq(irqlistp, cur_irq, NULL)
4886356Smrj 		    == ACPI_PSM_SUCCESS) {
4896356Smrj 
4906356Smrj 			acpi_free_irqlist(irqlistp);
4916356Smrj 			ASSERT(pci_irqp != NULL);
4926356Smrj 			*pci_irqp = cur_irq;
4936356Smrj 			return (ACPI_PSM_SUCCESS);
4946356Smrj 		}
4956356Smrj 		XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: Could not find the "
4966356Smrj 		    "current irq %d for device %s, instance #%d in ACPI's "
4976356Smrj 		    "list of possible irqs for this device. Picking one from "
4986356Smrj 		    " the latter list.", cur_irq, ddi_get_name(dip),
4996356Smrj 		    ddi_get_instance(dip)));
5006356Smrj 
5016356Smrj 	}
5026356Smrj 
5036356Smrj 	irqlistent = irqlistp;
5046356Smrj 	min_share = 255;
5056356Smrj 
5066356Smrj 	while (irqlistent != NULL) {
5076356Smrj 
5086356Smrj 		for (foundnow = 0, i = 0; i < irqlistent->num_irqs; i++) {
5096356Smrj 
5106356Smrj 			irq = irqlistp->irqs[i];
5116356Smrj 
5126356Smrj 			if ((irq > MAX_ISA_IRQ) ||
5136356Smrj 			    (irqlistent->intr_flags.intr_el == INTR_EL_EDGE) ||
5146356Smrj 			    (irq == 0))
5156356Smrj 				continue;
5166356Smrj 
5176356Smrj 			if (xen_uppc_reserved_irqlist[irq])
5186356Smrj 				continue;
5196356Smrj 
5206356Smrj 			if (xen_uppc_irq_shared_table[irq] == 0) {
5216356Smrj 				chosen_irq = irq;
5226356Smrj 				foundnow = 1;
5236356Smrj 				if (!(xen_uppc_prefer_crs) ||
5246356Smrj 				    (irq == cur_irq)) {
5256356Smrj 					done = 1;
5266356Smrj 					break;
5276356Smrj 				}
5286356Smrj 			}
5296356Smrj 
5306356Smrj 			if ((xen_uppc_irq_shared_table[irq] < min_share) ||
5316356Smrj 			    ((xen_uppc_irq_shared_table[irq] == min_share) &&
5326356Smrj 			    (cur_irq == irq) && (xen_uppc_prefer_crs))) {
5336356Smrj 				min_share = xen_uppc_irq_shared_table[irq];
5346356Smrj 				share_irq = irq;
5356356Smrj 				foundnow = 1;
5366356Smrj 			}
5376356Smrj 		}
5386356Smrj 
5396356Smrj 		/* If we found an IRQ in the inner loop, save the details */
5406356Smrj 		if (foundnow && ((chosen_irq != -1) || (share_irq != -1))) {
5416356Smrj 			/*
5426356Smrj 			 * Copy the acpi_prs_private_t and flags from this
5436356Smrj 			 * irq list entry, since we found an irq from this
5446356Smrj 			 * entry.
5456356Smrj 			 */
5466356Smrj 			acpipsmlnkp->acpi_prs_prv = irqlistent->acpi_prs_prv;
5476356Smrj 			*dipintr_flagp = irqlistent->intr_flags;
5486356Smrj 		}
5496356Smrj 
5506356Smrj 		if (done)
5516356Smrj 			break;
5526356Smrj 
5536356Smrj 		/* Load the next entry in the irqlist */
5546356Smrj 		irqlistent = irqlistent->next;
5556356Smrj 	}
5566356Smrj 
5576356Smrj 	acpi_free_irqlist(irqlistp);
5586356Smrj 
5596356Smrj 	if (chosen_irq != -1)
5606356Smrj 		irq = chosen_irq;
5616356Smrj 	else if (share_irq != -1)
5626356Smrj 		irq = share_irq;
5636356Smrj 	else {
5646356Smrj 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Could not find a "
5656356Smrj 		    "suitable irq from the list of possible irqs for device "
5666356Smrj 		    "%s, instance #%d in ACPI's list of possible\n",
5676356Smrj 		    ddi_get_name(dip), ddi_get_instance(dip)));
5686356Smrj 
5696356Smrj 		return (ACPI_PSM_FAILURE);
5706356Smrj 	}
5716356Smrj 
5726356Smrj 
5736356Smrj 	XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Setting irq %d "
5746356Smrj 	    "for device %s instance #%d\n", irq, ddi_get_name(dip),
5756356Smrj 	    ddi_get_instance(dip)));
5766356Smrj 
5776356Smrj 	if ((acpi_set_irq_resource(acpipsmlnkp, irq)) == ACPI_PSM_SUCCESS) {
5786356Smrj 		/*
5796356Smrj 		 * setting irq was successful, check to make sure CRS
5806356Smrj 		 * reflects that. If CRS does not agree with what we
5816356Smrj 		 * set, return the irq that was set.
5826356Smrj 		 */
5836356Smrj 
5846356Smrj 		if (acpi_get_current_irq_resource(acpipsmlnkp, &cur_irq,
5856356Smrj 		    dipintr_flagp) == ACPI_PSM_SUCCESS) {
5866356Smrj 
5876356Smrj 			if (cur_irq != irq)
5886356Smrj 				XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: "
5896356Smrj 				    "IRQ resource set (irqno %d) for device %s "
5906356Smrj 				    "instance #%d, differs from current "
5916356Smrj 				    "setting irqno %d",
5926356Smrj 				    irq, ddi_get_name(dip),
5936356Smrj 				    ddi_get_instance(dip), cur_irq));
5946356Smrj 		}
5956356Smrj 		/*
5966356Smrj 		 * return the irq that was set, and not what CRS reports,
5976356Smrj 		 * since CRS has been seen to be bogus on some systems
5986356Smrj 		 */
5996356Smrj 		cur_irq = irq;
6006356Smrj 	} else {
6016356Smrj 		XEN_UPPC_VERBOSE_IRQ((CE_WARN, "!xVM_uppc: set resource irq %d "
6026356Smrj 		    "failed for device %s instance #%d",
6036356Smrj 		    irq, ddi_get_name(dip), ddi_get_instance(dip)));
6046356Smrj 		if (cur_irq == -1)
6056356Smrj 			return (ACPI_PSM_FAILURE);
6066356Smrj 	}
6076356Smrj 
6086356Smrj 	ASSERT(pci_irqp != NULL);
6096356Smrj 	*pci_irqp = cur_irq;
6106356Smrj 	return (ACPI_PSM_SUCCESS);
6116356Smrj }
6126356Smrj 
6136356Smrj 
6146356Smrj static int
xen_uppc_acpi_translate_pci_irq(dev_info_t * dip,int busid,int devid,int ipin,int * pci_irqp,iflag_t * intr_flagp)6156356Smrj xen_uppc_acpi_translate_pci_irq(dev_info_t *dip, int busid, int devid,
6166356Smrj     int ipin, int *pci_irqp, iflag_t *intr_flagp)
6176356Smrj {
6186356Smrj 	int status;
6196356Smrj 	acpi_psm_lnk_t acpipsmlnk;
6206356Smrj 
6216356Smrj 	if ((status = acpi_get_irq_cache_ent(busid, devid, ipin, pci_irqp,
6226356Smrj 	    intr_flagp)) == ACPI_PSM_SUCCESS) {
6236356Smrj 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: Found irqno %d "
6246356Smrj 		    "from cache for device %s, instance #%d\n", *pci_irqp,
6256356Smrj 		    ddi_get_name(dip), ddi_get_instance(dip)));
6266356Smrj 		return (status);
6276356Smrj 	}
6286356Smrj 
6296356Smrj 	bzero(&acpipsmlnk, sizeof (acpi_psm_lnk_t));
6306356Smrj 
6316356Smrj 	if ((status = acpi_translate_pci_irq(dip, ipin, pci_irqp,
6326356Smrj 	    intr_flagp, &acpipsmlnk)) == ACPI_PSM_FAILURE) {
6336356Smrj 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: "
6346356Smrj 		    " acpi_translate_pci_irq failed for device %s, instance"
6356356Smrj 		    " #%d\n", ddi_get_name(dip), ddi_get_instance(dip)));
6366356Smrj 
6376356Smrj 		return (status);
6386356Smrj 	}
6396356Smrj 
6406356Smrj 	if (status == ACPI_PSM_PARTIAL && acpipsmlnk.lnkobj != NULL) {
6416356Smrj 		status = xen_uppc_acpi_irq_configure(&acpipsmlnk, dip, pci_irqp,
6426356Smrj 		    intr_flagp);
6436356Smrj 		if (status != ACPI_PSM_SUCCESS) {
6446356Smrj 			status = acpi_get_current_irq_resource(&acpipsmlnk,
6456356Smrj 			    pci_irqp, intr_flagp);
6466356Smrj 		}
6476356Smrj 	}
6486356Smrj 
6496356Smrj 	if (status == ACPI_PSM_SUCCESS) {
6506356Smrj 		acpi_new_irq_cache_ent(busid, devid, ipin, *pci_irqp,
6516356Smrj 		    intr_flagp, &acpipsmlnk);
6526356Smrj 		psm_set_elcr(*pci_irqp, 1); 	/* set IRQ to PCI mode */
6536356Smrj 
6546356Smrj 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: [ACPI] "
6556356Smrj 		    "new irq %d for device %s, instance #%d\n",
6566356Smrj 		    *pci_irqp, ddi_get_name(dip), ddi_get_instance(dip)));
6576356Smrj 	}
6586356Smrj 
6596356Smrj 	return (status);
6606356Smrj }
6616356Smrj 
6626356Smrj 
6636356Smrj /*ARGSUSED*/
6646356Smrj static int
xen_uppc_translate_irq(dev_info_t * dip,int irqno)6656356Smrj xen_uppc_translate_irq(dev_info_t *dip, int irqno)
6666356Smrj {
6676356Smrj 	char dev_type[16];
6686356Smrj 	int dev_len, pci_irq, devid, busid;
6696356Smrj 	ddi_acc_handle_t cfg_handle;
6706356Smrj 	uchar_t ipin, iline;
6716356Smrj 	iflag_t intr_flag;
6726356Smrj 
6736356Smrj 	if (dip == NULL) {
6746356Smrj 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: irqno = %d"
6756356Smrj 		    " dip = NULL\n", irqno));
6766356Smrj 		return (irqno);
6776356Smrj 	}
6786356Smrj 
6796356Smrj 	if (!xen_uppc_enable_acpi) {
6806356Smrj 		return (irqno);
6816356Smrj 	}
6826356Smrj 
6836356Smrj 	dev_len = sizeof (dev_type);
6846356Smrj 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(dip),
6856356Smrj 	    DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type,
6866356Smrj 	    &dev_len) != DDI_PROP_SUCCESS) {
6876356Smrj 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: irqno %d"
6886356Smrj 		    " device %s instance %d no device_type\n", irqno,
6896356Smrj 		    ddi_get_name(dip), ddi_get_instance(dip)));
6906356Smrj 		return (irqno);
6916356Smrj 	}
6926356Smrj 
6936356Smrj 	if ((strcmp(dev_type, "pci") == 0) ||
6946356Smrj 	    (strcmp(dev_type, "pciex") == 0)) {
6956356Smrj 
6966356Smrj 		/* pci device */
6976356Smrj 		if (acpica_get_bdf(dip, &busid, &devid, NULL) != 0)
6986356Smrj 			return (irqno);
6996356Smrj 
7006356Smrj 		if (pci_config_setup(dip, &cfg_handle) != DDI_SUCCESS)
7016356Smrj 			return (irqno);
7026356Smrj 
7036356Smrj 		ipin = pci_config_get8(cfg_handle, PCI_CONF_IPIN) - PCI_INTA;
7046356Smrj 		iline = pci_config_get8(cfg_handle, PCI_CONF_ILINE);
7056356Smrj 		if (xen_uppc_acpi_translate_pci_irq(dip, busid, devid,
7066356Smrj 		    ipin, &pci_irq, &intr_flag) == ACPI_PSM_SUCCESS) {
7076356Smrj 
7086356Smrj 			XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: [ACPI] "
7096356Smrj 			    "new irq %d old irq %d device %s, instance %d\n",
7106356Smrj 			    pci_irq, irqno, ddi_get_name(dip),
7116356Smrj 			    ddi_get_instance(dip)));
7126356Smrj 
7136356Smrj 			/*
7146356Smrj 			 * Make sure pci_irq is within range.
7156356Smrj 			 * Otherwise, fall through and return irqno.
7166356Smrj 			 */
7176356Smrj 			if (pci_irq <= MAX_ISA_IRQ) {
7186356Smrj 				if (iline != pci_irq) {
7196356Smrj 					/*
7206356Smrj 					 * Update the device's ILINE byte,
7216356Smrj 					 * in case uppc_acpi_translate_pci_irq
7226356Smrj 					 * has choosen a different pci_irq
7236356Smrj 					 * than the BIOS has configured.
7246356Smrj 					 * Some chipsets use the value in
7256356Smrj 					 * ILINE to control interrupt routing,
7266356Smrj 					 * in conflict with the PCI spec.
7276356Smrj 					 */
7286356Smrj 					pci_config_put8(cfg_handle,
7296356Smrj 					    PCI_CONF_ILINE, pci_irq);
7306356Smrj 				}
7316356Smrj 				pci_config_teardown(&cfg_handle);
7326356Smrj 				return (pci_irq);
7336356Smrj 			}
7346356Smrj 		}
7356356Smrj 		pci_config_teardown(&cfg_handle);
7366356Smrj 
7376356Smrj 		/* FALLTHRU to common case - returning irqno */
7386356Smrj 	} else {
7396356Smrj 		/* non-PCI; assumes ISA-style edge-triggered */
7406356Smrj 		psm_set_elcr(irqno, 0); 	/* set IRQ to ISA mode */
7416356Smrj 
7426356Smrj 		XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: non-pci,"
7436356Smrj 		    "irqno %d device %s instance %d\n", irqno,
7446356Smrj 		    ddi_get_name(dip), ddi_get_instance(dip)));
7456356Smrj 	}
7466356Smrj 
7476356Smrj 	return (irqno);
7486356Smrj }
7496356Smrj 
7506356Smrj /*
7516356Smrj  * xen_uppc_intr_enter() acks the event that triggered the interrupt and
7526356Smrj  * returns the new priority level,
7536356Smrj  */
7546356Smrj /*ARGSUSED*/
7556356Smrj static int
xen_uppc_intr_enter(int ipl,int * vector)7566356Smrj xen_uppc_intr_enter(int ipl, int *vector)
7576356Smrj {
7586356Smrj 	int newipl;
7596356Smrj 	uint_t intno;
7606356Smrj 	cpu_t *cpu = CPU;
7616356Smrj 
7626356Smrj 	intno = (*vector);
7636356Smrj 
7646356Smrj 	ASSERT(intno < NR_IRQS);
7656356Smrj 	ASSERT(cpu->cpu_m.mcpu_vcpu_info->evtchn_upcall_mask != 0);
7666356Smrj 
7676356Smrj 	ec_clear_irq(intno);
7686356Smrj 
7696356Smrj 	newipl = autovect[intno].avh_hi_pri;
7706356Smrj 	if (newipl == 0) {
7716356Smrj 		/*
7726356Smrj 		 * (newipl == 0) means we have no service routines for this
7736356Smrj 		 * vector.  We will treat this as a spurious interrupt.
7746356Smrj 		 * We have cleared the pending bit already, clear the event
7756356Smrj 		 * mask and return a spurious interrupt.  This case can happen
7766356Smrj 		 * when an interrupt delivery is racing with the removal of
7776356Smrj 		 * of the service routine for that interrupt.
7786356Smrj 		 */
7796356Smrj 		ec_unmask_irq(intno);
7806356Smrj 		newipl = -1;	/* flag spurious interrupt */
7816356Smrj 	} else if (newipl <= cpu->cpu_pri) {
7826356Smrj 		/*
7836356Smrj 		 * (newipl <= cpu->cpu_pri) means that we must be trying to
7846356Smrj 		 * service a vector that was shared with a higher priority
7856356Smrj 		 * isr.  The higher priority handler has been removed and
7866356Smrj 		 * we need to service this int.  We can't return a lower
7876356Smrj 		 * priority than current cpu priority.  Just synthesize a
7886356Smrj 		 * priority to return that should be acceptable.
7896356Smrj 		 */
7906356Smrj 		newipl = cpu->cpu_pri + 1;	/* synthetic priority */
7916356Smrj 	}
7926356Smrj 	return (newipl);
7936356Smrj }
7946356Smrj 
7956356Smrj 
7966356Smrj static void xen_uppc_setspl(int);
7976356Smrj 
7986356Smrj /*
7996356Smrj  * xen_uppc_intr_exit() restores the old interrupt
8006356Smrj  * priority level after processing an interrupt.
8016356Smrj  * It is called with interrupts disabled, and does not enable interrupts.
8026356Smrj  */
8036356Smrj /* ARGSUSED */
8046356Smrj static void
xen_uppc_intr_exit(int ipl,int vector)8056356Smrj xen_uppc_intr_exit(int ipl, int vector)
8066356Smrj {
8076356Smrj 	ec_try_unmask_irq(vector);
8086356Smrj 	xen_uppc_setspl(ipl);
8096356Smrj }
8106356Smrj 
8116356Smrj intr_exit_fn_t
psm_intr_exit_fn(void)8126356Smrj psm_intr_exit_fn(void)
8136356Smrj {
8146356Smrj 	return (xen_uppc_intr_exit);
8156356Smrj }
8166356Smrj 
8176356Smrj /*
8186356Smrj  * Check if new ipl level allows delivery of previously unserviced events
8196356Smrj  */
8206356Smrj static void
xen_uppc_setspl(int ipl)8216356Smrj xen_uppc_setspl(int ipl)
8226356Smrj {
8236356Smrj 	struct cpu *cpu = CPU;
8246356Smrj 	volatile vcpu_info_t *vci = cpu->cpu_m.mcpu_vcpu_info;
8256356Smrj 	uint16_t pending;
8266356Smrj 
8276356Smrj 	ASSERT(vci->evtchn_upcall_mask != 0);
8286356Smrj 
8296356Smrj 	/*
8306356Smrj 	 * If new ipl level will enable any pending interrupts, setup so the
8316356Smrj 	 * upcoming sti will cause us to get an upcall.
8326356Smrj 	 */
8336356Smrj 	pending = cpu->cpu_m.mcpu_intr_pending & ~((1 << (ipl + 1)) - 1);
8346356Smrj 	if (pending) {
8356356Smrj 		int i;
8366356Smrj 		ulong_t pending_sels = 0;
8376356Smrj 		volatile ulong_t *selp;
8386356Smrj 		struct xen_evt_data *cpe = cpu->cpu_m.mcpu_evt_pend;
8396356Smrj 
8406356Smrj 		for (i = bsrw_insn(pending); i > ipl; i--)
8416356Smrj 			pending_sels |= cpe->pending_sel[i];
8426356Smrj 		ASSERT(pending_sels);
8436356Smrj 		selp = (volatile ulong_t *)&vci->evtchn_pending_sel;
8446356Smrj 		atomic_or_ulong(selp, pending_sels);
8456356Smrj 		vci->evtchn_upcall_pending = 1;
8466356Smrj 	}
8476356Smrj }
8486356Smrj 
8496356Smrj /*
8506356Smrj  * The rest of the file is just generic psm module boilerplate
8516356Smrj  */
8526356Smrj 
8536356Smrj static struct psm_ops xen_uppc_ops = {
8546356Smrj 	xen_uppc_probe,				/* psm_probe		*/
8556356Smrj 
8566356Smrj 	xen_uppc_softinit,			/* psm_init		*/
8576356Smrj 	xen_uppc_picinit,			/* psm_picinit		*/
8586356Smrj 	xen_uppc_intr_enter,			/* psm_intr_enter	*/
8596356Smrj 	xen_uppc_intr_exit,			/* psm_intr_exit	*/
8606356Smrj 	xen_uppc_setspl,			/* psm_setspl		*/
8616356Smrj 	xen_uppc_addspl,			/* psm_addspl		*/
8626356Smrj 	xen_uppc_delspl,			/* psm_delspl		*/
8636356Smrj 	(int (*)(processorid_t))NULL,		/* psm_disable_intr	*/
8646356Smrj 	(void (*)(processorid_t))NULL,		/* psm_enable_intr	*/
8656356Smrj 	(int (*)(int))NULL,			/* psm_softlvl_to_irq	*/
8666356Smrj 	(void (*)(int))NULL,			/* psm_set_softintr	*/
8676356Smrj 	(void (*)(processorid_t))NULL,		/* psm_set_idlecpu	*/
8686356Smrj 	(void (*)(processorid_t))NULL,		/* psm_unset_idlecpu	*/
8696356Smrj 
8706356Smrj 	xen_uppc_clkinit,			/* psm_clkinit		*/
8716356Smrj 	xen_uppc_get_clockirq,			/* psm_get_clockirq	*/
8726356Smrj 	(void (*)(void))NULL,			/* psm_hrtimeinit	*/
8736356Smrj 	xpv_gethrtime,				/* psm_gethrtime	*/
8746356Smrj 
8756356Smrj 	xen_uppc_get_next_processorid,		/* psm_get_next_processorid */
8766356Smrj 	(int (*)(processorid_t, caddr_t))NULL,	/* psm_cpu_start	*/
8776356Smrj 	(int (*)(void))NULL,			/* psm_post_cpu_start	*/
8786356Smrj 	xen_uppc_shutdown,			/* psm_shutdown		*/
8796356Smrj 	(int (*)(int, int))NULL,		/* psm_get_ipivect	*/
8806356Smrj 	(void (*)(processorid_t, int))NULL,	/* psm_send_ipi		*/
8816356Smrj 
8826356Smrj 	xen_uppc_translate_irq,			/* psm_translate_irq	*/
8836356Smrj 
8846356Smrj 	(void (*)(int, char *))NULL,		/* psm_notify_error	*/
8856356Smrj 	(void (*)(int msg))NULL,		/* psm_notify_func	*/
8866356Smrj 	xen_uppc_timer_reprogram,		/* psm_timer_reprogram	*/
8876356Smrj 	xen_uppc_timer_enable,			/* psm_timer_enable	*/
8886356Smrj 	xen_uppc_timer_disable,			/* psm_timer_disable	*/
8896356Smrj 	(void (*)(void *arg))NULL,		/* psm_post_cyclic_setup */
8906356Smrj 	(void (*)(int, int))NULL,		/* psm_preshutdown	*/
8916356Smrj 
8926356Smrj 	(int (*)(dev_info_t *, ddi_intr_handle_impl_t *,
8936356Smrj 	    psm_intr_op_t, int *))NULL,		/* psm_intr_ops		*/
894*12004Sjiang.liu@intel.com 	(int (*)(psm_state_request_t *))NULL,	/* psm_state		*/
895*12004Sjiang.liu@intel.com 	(int (*)(psm_cpu_request_t *))NULL	/* psm_cpu_ops		*/
8966356Smrj };
8976356Smrj 
8986356Smrj static struct psm_info xen_uppc_info = {
8996356Smrj 	PSM_INFO_VER01_5,	/* version				*/
9006356Smrj 	PSM_OWN_SYS_DEFAULT,	/* ownership				*/
9016356Smrj 	&xen_uppc_ops,		/* operation				*/
9026356Smrj 	"xVM_uppc",		/* machine name				*/
9036356Smrj 	"UniProcessor PC"	/* machine descriptions			*/
9046356Smrj };
9056356Smrj 
9066356Smrj static void *xen_uppc_hdlp;
9076356Smrj 
9086356Smrj int
_init(void)9096356Smrj _init(void)
9106356Smrj {
9116356Smrj 	return (psm_mod_init(&xen_uppc_hdlp, &xen_uppc_info));
9126356Smrj }
9136356Smrj 
9146356Smrj int
_fini(void)9156356Smrj _fini(void)
9166356Smrj {
9176356Smrj 	return (psm_mod_fini(&xen_uppc_hdlp, &xen_uppc_info));
9186356Smrj }
9196356Smrj 
9206356Smrj int
_info(struct modinfo * modinfop)9216356Smrj _info(struct modinfo *modinfop)
9226356Smrj {
9236356Smrj 	return (psm_mod_info(&xen_uppc_hdlp, &xen_uppc_info, modinfop));
9246356Smrj }
925