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