xref: /illumos-gate/usr/src/uts/i86xpv/os/evtchn.c (revision db830ba5)
1843e1988Sjohnlev /*
2843e1988Sjohnlev  * CDDL HEADER START
3843e1988Sjohnlev  *
4843e1988Sjohnlev  * The contents of this file are subject to the terms of the
5843e1988Sjohnlev  * Common Development and Distribution License (the "License").
6843e1988Sjohnlev  * You may not use this file except in compliance with the License.
7843e1988Sjohnlev  *
8843e1988Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9843e1988Sjohnlev  * or http://www.opensolaris.org/os/licensing.
10843e1988Sjohnlev  * See the License for the specific language governing permissions
11843e1988Sjohnlev  * and limitations under the License.
12843e1988Sjohnlev  *
13843e1988Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
14843e1988Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15843e1988Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
16843e1988Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
17843e1988Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
18843e1988Sjohnlev  *
19843e1988Sjohnlev  * CDDL HEADER END
20843e1988Sjohnlev  */
21843e1988Sjohnlev 
22843e1988Sjohnlev /*
23349b53ddSStuart Maybee  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24843e1988Sjohnlev  * Use is subject to license terms.
25843e1988Sjohnlev  */
26843e1988Sjohnlev 
27843e1988Sjohnlev /*
28843e1988Sjohnlev  * evtchn.c
29843e1988Sjohnlev  *
30843e1988Sjohnlev  * Communication via hypervisor event channels.
31843e1988Sjohnlev  *
32843e1988Sjohnlev  * Copyright (c) 2002-2005, K A Fraser
33843e1988Sjohnlev  *
34843e1988Sjohnlev  * This file may be distributed separately from the Linux kernel, or
35843e1988Sjohnlev  * incorporated into other software packages, subject to the following license:
36843e1988Sjohnlev  *
37843e1988Sjohnlev  * Permission is hereby granted, free of charge, to any person obtaining a copy
38843e1988Sjohnlev  * of this source file (the "Software"), to deal in the Software without
39843e1988Sjohnlev  * restriction, including without limitation the rights to use, copy, modify,
40843e1988Sjohnlev  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
41843e1988Sjohnlev  * and to permit persons to whom the Software is furnished to do so, subject to
42843e1988Sjohnlev  * the following conditions:
43843e1988Sjohnlev  *
44843e1988Sjohnlev  * The above copyright notice and this permission notice shall be included in
45843e1988Sjohnlev  * all copies or substantial portions of the Software.
46843e1988Sjohnlev  *
47843e1988Sjohnlev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48843e1988Sjohnlev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
49843e1988Sjohnlev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50843e1988Sjohnlev  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
51843e1988Sjohnlev  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
52843e1988Sjohnlev  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
53843e1988Sjohnlev  * IN THE SOFTWARE.
54843e1988Sjohnlev  */
55843e1988Sjohnlev 
56843e1988Sjohnlev /* some parts derived from netbsd's hypervisor_machdep.c 1.2.2.2 */
57843e1988Sjohnlev 
58843e1988Sjohnlev /*
59843e1988Sjohnlev  *
60843e1988Sjohnlev  * Copyright (c) 2004 Christian Limpach.
61843e1988Sjohnlev  * All rights reserved.
62843e1988Sjohnlev  *
63843e1988Sjohnlev  * Redistribution and use in source and binary forms, with or without
64843e1988Sjohnlev  * modification, are permitted provided that the following conditions
65843e1988Sjohnlev  * are met:
66843e1988Sjohnlev  * 1. Redistributions of source code must retain the above copyright
67843e1988Sjohnlev  *    notice, this list of conditions and the following disclaimer.
68843e1988Sjohnlev  * 2. Redistributions in binary form must reproduce the above copyright
69843e1988Sjohnlev  *    notice, this list of conditions and the following disclaimer in the
70843e1988Sjohnlev  *    documentation and/or other materials provided with the distribution.
71843e1988Sjohnlev  * 3. This section intentionally left blank.
72843e1988Sjohnlev  * 4. The name of the author may not be used to endorse or promote products
73843e1988Sjohnlev  *    derived from this software without specific prior written permission.
74843e1988Sjohnlev  *
75843e1988Sjohnlev  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
76843e1988Sjohnlev  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
77843e1988Sjohnlev  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
78843e1988Sjohnlev  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
79843e1988Sjohnlev  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
80843e1988Sjohnlev  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
81843e1988Sjohnlev  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
82843e1988Sjohnlev  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
83843e1988Sjohnlev  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
84843e1988Sjohnlev  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
85843e1988Sjohnlev  */
86843e1988Sjohnlev /*
87843e1988Sjohnlev  * Section 3 of the above license was updated in response to bug 6379571.
88843e1988Sjohnlev  */
89843e1988Sjohnlev 
90843e1988Sjohnlev #include <sys/types.h>
91843e1988Sjohnlev #include <sys/hypervisor.h>
92843e1988Sjohnlev #include <sys/machsystm.h>
93843e1988Sjohnlev #include <sys/mutex.h>
94843e1988Sjohnlev #include <sys/evtchn_impl.h>
95843e1988Sjohnlev #include <sys/ddi_impldefs.h>
96843e1988Sjohnlev #include <sys/avintr.h>
97843e1988Sjohnlev #include <sys/cpuvar.h>
98843e1988Sjohnlev #include <sys/smp_impldefs.h>
99843e1988Sjohnlev #include <sys/archsystm.h>
100843e1988Sjohnlev #include <sys/sysmacros.h>
101843e1988Sjohnlev #include <sys/cmn_err.h>
102843e1988Sjohnlev #include <sys/promif.h>
103843e1988Sjohnlev #include <sys/debug.h>
104843e1988Sjohnlev #include <sys/psm.h>
105843e1988Sjohnlev #include <sys/privregs.h>
106843e1988Sjohnlev #include <sys/trap.h>
107843e1988Sjohnlev #include <sys/atomic.h>
108843e1988Sjohnlev #include <sys/cpu.h>
109843e1988Sjohnlev #include <sys/psw.h>
110843e1988Sjohnlev #include <sys/traptrace.h>
111843e1988Sjohnlev #include <sys/stack.h>
112843e1988Sjohnlev #include <sys/x_call.h>
113843e1988Sjohnlev #include <xen/public/physdev.h>
114843e1988Sjohnlev 
115843e1988Sjohnlev /*
116843e1988Sjohnlev  * This file manages our association between hypervisor event channels and
117843e1988Sjohnlev  * Solaris's IRQs.  This is a one-to-one mapping, with the exception of
118843e1988Sjohnlev  * IPI IRQs, for which there is one event channel per CPU participating
119843e1988Sjohnlev  * in the IPI, and the clock VIRQ which also has an event channel per cpu
120843e1988Sjohnlev  * and the IRQ for /dev/xen/evtchn. The IRQ types are:
121843e1988Sjohnlev  *
122843e1988Sjohnlev  * IRQT_VIRQ:
123843e1988Sjohnlev  *	The hypervisor's standard virtual IRQ, used for the clock timer, for
124843e1988Sjohnlev  *	example.  This code allows any cpu to bind to one of these, although
125843e1988Sjohnlev  *	some are treated specially (i.e. VIRQ_DEBUG).
126843e1988Sjohnlev  *	Event channel binding is done via EVTCHNOP_bind_virq.
127843e1988Sjohnlev  *
128843e1988Sjohnlev  * IRQT_PIRQ:
129843e1988Sjohnlev  *	These associate a physical IRQ with an event channel via
130843e1988Sjohnlev  *	EVTCHNOP_bind_pirq.
131843e1988Sjohnlev  *
132843e1988Sjohnlev  * IRQT_IPI:
133843e1988Sjohnlev  *	A cross-call IRQ. Maps to "ncpus" event channels, each of which is
134843e1988Sjohnlev  *	bound to exactly one of the vcpus.  We do not currently support
135843e1988Sjohnlev  *	unbinding of IPIs (since Solaris doesn't need it). Uses
136843e1988Sjohnlev  *	EVTCHNOP_bind_ipi.
137843e1988Sjohnlev  *
138843e1988Sjohnlev  * IRQT_EVTCHN:
139843e1988Sjohnlev  *	A "normal" binding to an event channel, typically used by the frontend
140843e1988Sjohnlev  *      drivers to bind to the their backend event channel.
141843e1988Sjohnlev  *
142843e1988Sjohnlev  * IRQT_DEV_EVTCHN:
143843e1988Sjohnlev  *	This is a one-time IRQ used by /dev/xen/evtchn. Unlike other IRQs, we
144843e1988Sjohnlev  *	have a one-IRQ to many-evtchn mapping. We only track evtchn->irq for
145843e1988Sjohnlev  *	these event channels, which are managed via ec_irq_add/rm_evtchn().
146843e1988Sjohnlev  *	We enforce that IRQT_DEV_EVTCHN's representative evtchn (->ii_evtchn)
147843e1988Sjohnlev  *	is zero, and make any calls to irq_evtchn() an error, to prevent
148843e1988Sjohnlev  *	accidentally attempting to use the illegal evtchn 0.
149843e1988Sjohnlev  *
150843e1988Sjohnlev  * Suspend/resume
151843e1988Sjohnlev  *
152843e1988Sjohnlev  *	During a suspend/resume cycle, we need to tear down the event channels.
153843e1988Sjohnlev  *	All other mapping data is kept. The drivers will remove their own event
154843e1988Sjohnlev  *	channels via xendev on receiving a DDI_SUSPEND.  This leaves us with
155843e1988Sjohnlev  *	the IPIs and VIRQs, which we handle in ec_suspend() and ec_resume()
156843e1988Sjohnlev  *	below.
157843e1988Sjohnlev  *
158843e1988Sjohnlev  * CPU binding
159843e1988Sjohnlev  *
160843e1988Sjohnlev  *	When an event channel is bound to a CPU, we set a bit in a mask present
161843e1988Sjohnlev  *	in the machcpu (evt_affinity) to indicate that this CPU can accept this
162843e1988Sjohnlev  *	event channel.  For both IPIs and VIRQs, this binding is fixed at
163843e1988Sjohnlev  *	allocation time and we never modify it.  All other event channels are
164843e1988Sjohnlev  *	bound via the PSM either as part of add_avintr(), or interrupt
165843e1988Sjohnlev  *	redistribution (xen_psm_dis/enable_intr()) as a result of CPU
166843e1988Sjohnlev  *	offline/online.
167843e1988Sjohnlev  *
168843e1988Sjohnlev  * Locking
169843e1988Sjohnlev  *
170843e1988Sjohnlev  *	Updates are done holding the ec_lock.  The xen_callback_handler()
171843e1988Sjohnlev  *	routine reads the mapping data in a lockless fashion.  Additionally
172843e1988Sjohnlev  *	suspend takes ec_lock to prevent update races during a suspend/resume
173843e1988Sjohnlev  *	cycle.  The IPI info is also examined without the lock; this is OK
174843e1988Sjohnlev  *	since we only ever change IPI info during initial setup and resume.
175843e1988Sjohnlev  */
176843e1988Sjohnlev 
177843e1988Sjohnlev #define	IRQ_IS_CPUPOKE(irq) (ipi_info[XC_CPUPOKE_PIL].mi_irq == (irq))
178843e1988Sjohnlev 
179843e1988Sjohnlev #define	EVTCHN_MASKED(ev) \
180843e1988Sjohnlev 	(HYPERVISOR_shared_info->evtchn_mask[(ev) >> EVTCHN_SHIFT] & \
181843e1988Sjohnlev 	(1ul << ((ev) & ((1ul << EVTCHN_SHIFT) - 1))))
182843e1988Sjohnlev 
183843e1988Sjohnlev static short evtchn_to_irq[NR_EVENT_CHANNELS];
184843e1988Sjohnlev static cpuset_t evtchn_cpus[NR_EVENT_CHANNELS];
185843e1988Sjohnlev static int	evtchn_owner[NR_EVENT_CHANNELS];
186843e1988Sjohnlev #ifdef DEBUG
187843e1988Sjohnlev static kthread_t *evtchn_owner_thread[NR_EVENT_CHANNELS];
188843e1988Sjohnlev #endif
189843e1988Sjohnlev 
190843e1988Sjohnlev static irq_info_t irq_info[NR_IRQS];
191843e1988Sjohnlev static mec_info_t ipi_info[MAXIPL];
192843e1988Sjohnlev static mec_info_t virq_info[NR_VIRQS];
193843e1988Sjohnlev 
194843e1988Sjohnlev /*
195843e1988Sjohnlev  * See the locking description above.
196843e1988Sjohnlev  */
197843e1988Sjohnlev kmutex_t ec_lock;
198843e1988Sjohnlev 
199843e1988Sjohnlev /*
200843e1988Sjohnlev  * Bitmap indicating which PIRQs require the hypervisor to be notified
201843e1988Sjohnlev  * on unmask.
202843e1988Sjohnlev  */
203843e1988Sjohnlev static unsigned long pirq_needs_eoi[NR_PIRQS / (sizeof (unsigned long) * NBBY)];
204843e1988Sjohnlev 
205843e1988Sjohnlev static int ec_debug_irq = INVALID_IRQ;
206843e1988Sjohnlev int ec_dev_irq = INVALID_IRQ;
207843e1988Sjohnlev 
208843e1988Sjohnlev int
xen_bind_virq(unsigned int virq,processorid_t cpu,int * port)209843e1988Sjohnlev xen_bind_virq(unsigned int virq, processorid_t cpu, int *port)
210843e1988Sjohnlev {
211843e1988Sjohnlev 	evtchn_bind_virq_t bind;
212843e1988Sjohnlev 	int err;
213843e1988Sjohnlev 
214843e1988Sjohnlev 	bind.virq = virq;
215843e1988Sjohnlev 	bind.vcpu = cpu;
216843e1988Sjohnlev 	if ((err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &bind)) == 0)
217843e1988Sjohnlev 		*port = bind.port;
218843e1988Sjohnlev 	else
219843e1988Sjohnlev 		err = xen_xlate_errcode(err);
220843e1988Sjohnlev 	return (err);
221843e1988Sjohnlev }
222843e1988Sjohnlev 
223843e1988Sjohnlev int
xen_bind_interdomain(int domid,int remote_port,int * port)224843e1988Sjohnlev xen_bind_interdomain(int domid, int remote_port, int *port)
225843e1988Sjohnlev {
226843e1988Sjohnlev 	evtchn_bind_interdomain_t bind;
227843e1988Sjohnlev 	int err;
228843e1988Sjohnlev 
229843e1988Sjohnlev 	bind.remote_dom  = domid;
230843e1988Sjohnlev 	bind.remote_port = remote_port;
231843e1988Sjohnlev 	if ((err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
232843e1988Sjohnlev 	    &bind)) == 0)
233843e1988Sjohnlev 		*port = bind.local_port;
234843e1988Sjohnlev 	else
235843e1988Sjohnlev 		err = xen_xlate_errcode(err);
236843e1988Sjohnlev 	return (err);
237843e1988Sjohnlev }
238843e1988Sjohnlev 
239843e1988Sjohnlev int
xen_alloc_unbound_evtchn(int domid,int * evtchnp)240843e1988Sjohnlev xen_alloc_unbound_evtchn(int domid, int *evtchnp)
241843e1988Sjohnlev {
242843e1988Sjohnlev 	evtchn_alloc_unbound_t alloc;
243843e1988Sjohnlev 	int err;
244843e1988Sjohnlev 
245843e1988Sjohnlev 	alloc.dom = DOMID_SELF;
246843e1988Sjohnlev 	alloc.remote_dom = domid;
247843e1988Sjohnlev 
248843e1988Sjohnlev 	if ((err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
249843e1988Sjohnlev 	    &alloc)) == 0) {
250843e1988Sjohnlev 		*evtchnp = alloc.port;
251843e1988Sjohnlev 		/* ensure evtchn is masked till we're ready to use it */
252843e1988Sjohnlev 		(void) ec_mask_evtchn(*evtchnp);
253843e1988Sjohnlev 	} else {
254843e1988Sjohnlev 		err = xen_xlate_errcode(err);
255843e1988Sjohnlev 	}
256843e1988Sjohnlev 
257843e1988Sjohnlev 	return (err);
258843e1988Sjohnlev }
259843e1988Sjohnlev 
260843e1988Sjohnlev static int
xen_close_evtchn(int evtchn)261843e1988Sjohnlev xen_close_evtchn(int evtchn)
262843e1988Sjohnlev {
263843e1988Sjohnlev 	evtchn_close_t close;
264843e1988Sjohnlev 	int err;
265843e1988Sjohnlev 
266843e1988Sjohnlev 	close.port = evtchn;
267843e1988Sjohnlev 	err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
268843e1988Sjohnlev 	if (err)
269843e1988Sjohnlev 		err = xen_xlate_errcode(err);
270843e1988Sjohnlev 	return (err);
271843e1988Sjohnlev }
272843e1988Sjohnlev 
273843e1988Sjohnlev static int
xen_bind_ipi(processorid_t cpu)274843e1988Sjohnlev xen_bind_ipi(processorid_t cpu)
275843e1988Sjohnlev {
276843e1988Sjohnlev 	evtchn_bind_ipi_t bind;
277843e1988Sjohnlev 
278843e1988Sjohnlev 	ASSERT(MUTEX_HELD(&ec_lock));
279843e1988Sjohnlev 
280843e1988Sjohnlev 	bind.vcpu = cpu;
281843e1988Sjohnlev 	if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind) != 0)
282843e1988Sjohnlev 		panic("xen_bind_ipi() failed");
283843e1988Sjohnlev 	return (bind.port);
284843e1988Sjohnlev }
285843e1988Sjohnlev 
286843e1988Sjohnlev /* Send future instances of this interrupt to other vcpu. */
287843e1988Sjohnlev static void
xen_bind_vcpu(int evtchn,int cpu)288843e1988Sjohnlev xen_bind_vcpu(int evtchn, int cpu)
289843e1988Sjohnlev {
290843e1988Sjohnlev 	evtchn_bind_vcpu_t bind;
291843e1988Sjohnlev 
292843e1988Sjohnlev 	ASSERT(MUTEX_HELD(&ec_lock));
293843e1988Sjohnlev 
294843e1988Sjohnlev 	bind.port = evtchn;
295843e1988Sjohnlev 	bind.vcpu = cpu;
296843e1988Sjohnlev 	if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind) != 0)
297843e1988Sjohnlev 		panic("xen_bind_vcpu() failed");
298843e1988Sjohnlev }
299843e1988Sjohnlev 
300843e1988Sjohnlev static int
xen_bind_pirq(int pirq)301843e1988Sjohnlev xen_bind_pirq(int pirq)
302843e1988Sjohnlev {
303843e1988Sjohnlev 	evtchn_bind_pirq_t bind;
304843e1988Sjohnlev 	int ret;
305843e1988Sjohnlev 
306843e1988Sjohnlev 	bind.pirq = pirq;
307843e1988Sjohnlev 	bind.flags = BIND_PIRQ__WILL_SHARE;
308843e1988Sjohnlev 	if ((ret = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind)) != 0)
309843e1988Sjohnlev 		panic("xen_bind_pirq() failed (err %d)", ret);
310843e1988Sjohnlev 	return (bind.port);
311843e1988Sjohnlev }
312843e1988Sjohnlev 
313843e1988Sjohnlev /* unmask an evtchn and send upcall to appropriate vcpu if pending bit is set */
314843e1988Sjohnlev static void
xen_evtchn_unmask(int evtchn)315843e1988Sjohnlev xen_evtchn_unmask(int evtchn)
316843e1988Sjohnlev {
317843e1988Sjohnlev 	evtchn_unmask_t unmask;
318843e1988Sjohnlev 
319843e1988Sjohnlev 	unmask.port = evtchn;
320843e1988Sjohnlev 	if (HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask) != 0)
321843e1988Sjohnlev 		panic("xen_evtchn_unmask() failed");
322843e1988Sjohnlev }
323843e1988Sjohnlev 
324843e1988Sjohnlev static void
update_evtchn_affinity(int evtchn)325843e1988Sjohnlev update_evtchn_affinity(int evtchn)
326843e1988Sjohnlev {
327843e1988Sjohnlev 	cpu_t *cp;
328843e1988Sjohnlev 	struct xen_evt_data *cpe;
329843e1988Sjohnlev 
330843e1988Sjohnlev 	ASSERT(evtchn_to_irq[evtchn] != INVALID_IRQ);
331843e1988Sjohnlev 	ASSERT(MUTEX_HELD(&ec_lock));
332843e1988Sjohnlev 
333843e1988Sjohnlev 	/*
334843e1988Sjohnlev 	 * Use lockless search of cpu_list, similar to mutex_vector_enter().
335843e1988Sjohnlev 	 */
336843e1988Sjohnlev 	kpreempt_disable();
337843e1988Sjohnlev 	cp = cpu_list;
338843e1988Sjohnlev 	do {
339843e1988Sjohnlev 		cpe = cp->cpu_m.mcpu_evt_pend;
340843e1988Sjohnlev 		if (CPU_IN_SET(evtchn_cpus[evtchn], cp->cpu_id))
341843e1988Sjohnlev 			SET_EVTCHN_BIT(evtchn, cpe->evt_affinity);
342843e1988Sjohnlev 		else
343843e1988Sjohnlev 			CLEAR_EVTCHN_BIT(evtchn, cpe->evt_affinity);
344843e1988Sjohnlev 	} while ((cp = cp->cpu_next) != cpu_list);
345843e1988Sjohnlev 	kpreempt_enable();
346843e1988Sjohnlev }
347843e1988Sjohnlev 
348843e1988Sjohnlev static void
bind_evtchn_to_cpuset(int evtchn,cpuset_t cpus)349843e1988Sjohnlev bind_evtchn_to_cpuset(int evtchn, cpuset_t cpus)
350843e1988Sjohnlev {
351843e1988Sjohnlev 	ASSERT(evtchn_to_irq[evtchn] != INVALID_IRQ);
352843e1988Sjohnlev 
353843e1988Sjohnlev 	CPUSET_ZERO(evtchn_cpus[evtchn]);
354843e1988Sjohnlev 	CPUSET_OR(evtchn_cpus[evtchn], cpus);
355843e1988Sjohnlev 	update_evtchn_affinity(evtchn);
356843e1988Sjohnlev }
357843e1988Sjohnlev 
358843e1988Sjohnlev static void
clear_evtchn_affinity(int evtchn)359843e1988Sjohnlev clear_evtchn_affinity(int evtchn)
360843e1988Sjohnlev {
361843e1988Sjohnlev 	CPUSET_ZERO(evtchn_cpus[evtchn]);
362843e1988Sjohnlev 	update_evtchn_affinity(evtchn);
363843e1988Sjohnlev }
364843e1988Sjohnlev 
365843e1988Sjohnlev static void
alloc_irq_evtchn(int irq,int index,int evtchn,int cpu)366843e1988Sjohnlev alloc_irq_evtchn(int irq, int index, int evtchn, int cpu)
367843e1988Sjohnlev {
368843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
369843e1988Sjohnlev 
370843e1988Sjohnlev 	switch (irqp->ii_type) {
371843e1988Sjohnlev 	case IRQT_IPI:
372843e1988Sjohnlev 		ipi_info[index].mi_evtchns[cpu] = evtchn;
373843e1988Sjohnlev 		irqp->ii_u.index = index;
374843e1988Sjohnlev 		break;
375843e1988Sjohnlev 	case IRQT_VIRQ:
376843e1988Sjohnlev 		virq_info[index].mi_evtchns[cpu] = evtchn;
377843e1988Sjohnlev 		irqp->ii_u.index = index;
378843e1988Sjohnlev 		break;
379843e1988Sjohnlev 	default:
380843e1988Sjohnlev 		irqp->ii_u.evtchn = evtchn;
381843e1988Sjohnlev 		break;
382843e1988Sjohnlev 	}
383843e1988Sjohnlev 
384843e1988Sjohnlev 	evtchn_to_irq[evtchn] = irq;
385843e1988Sjohnlev 
386843e1988Sjohnlev 	/*
387843e1988Sjohnlev 	 * If a CPU is not specified, we expect to bind it to a CPU later via
388843e1988Sjohnlev 	 * the PSM.
389843e1988Sjohnlev 	 */
390843e1988Sjohnlev 	if (cpu != -1) {
391843e1988Sjohnlev 		cpuset_t tcpus;
392843e1988Sjohnlev 		CPUSET_ONLY(tcpus, cpu);
393843e1988Sjohnlev 		bind_evtchn_to_cpuset(evtchn, tcpus);
394843e1988Sjohnlev 	}
395843e1988Sjohnlev }
396843e1988Sjohnlev 
397843e1988Sjohnlev static int
alloc_irq(int type,int index,int evtchn,int cpu)398843e1988Sjohnlev alloc_irq(int type, int index, int evtchn, int cpu)
399843e1988Sjohnlev {
400843e1988Sjohnlev 	int irq;
401843e1988Sjohnlev 	irq_info_t *irqp;
402843e1988Sjohnlev 
403843e1988Sjohnlev 	ASSERT(MUTEX_HELD(&ec_lock));
404843e1988Sjohnlev 	ASSERT(type != IRQT_IPI || cpu != -1);
405843e1988Sjohnlev 
406843e1988Sjohnlev 	for (irq = 0; irq < NR_IRQS; irq++) {
407843e1988Sjohnlev 		if (irq_info[irq].ii_type == IRQT_UNBOUND)
408843e1988Sjohnlev 			break;
409843e1988Sjohnlev 	}
410843e1988Sjohnlev 
411843e1988Sjohnlev 	if (irq == NR_IRQS)
412843e1988Sjohnlev 		panic("No available IRQ to bind to: increase NR_IRQS!\n");
413843e1988Sjohnlev 
414843e1988Sjohnlev 	irqp = &irq_info[irq];
415843e1988Sjohnlev 
416843e1988Sjohnlev 	irqp->ii_type = type;
417843e1988Sjohnlev 	/*
418843e1988Sjohnlev 	 * Set irq/has_handler field to zero which means handler not installed
419843e1988Sjohnlev 	 */
420843e1988Sjohnlev 	irqp->ii_u2.has_handler = 0;
421843e1988Sjohnlev 
422843e1988Sjohnlev 	alloc_irq_evtchn(irq, index, evtchn, cpu);
423843e1988Sjohnlev 	return (irq);
424843e1988Sjohnlev }
425843e1988Sjohnlev 
426843e1988Sjohnlev static int
irq_evtchn(irq_info_t * irqp)427843e1988Sjohnlev irq_evtchn(irq_info_t *irqp)
428843e1988Sjohnlev {
429843e1988Sjohnlev 	int evtchn;
430843e1988Sjohnlev 
431843e1988Sjohnlev 	ASSERT(irqp->ii_type != IRQT_DEV_EVTCHN);
432843e1988Sjohnlev 
433843e1988Sjohnlev 	switch (irqp->ii_type) {
434843e1988Sjohnlev 	case IRQT_IPI:
435843e1988Sjohnlev 		ASSERT(irqp->ii_u.index != 0);
436843e1988Sjohnlev 		evtchn = ipi_info[irqp->ii_u.index].mi_evtchns[CPU->cpu_id];
437843e1988Sjohnlev 		break;
438843e1988Sjohnlev 	case IRQT_VIRQ:
439843e1988Sjohnlev 		evtchn = virq_info[irqp->ii_u.index].mi_evtchns[CPU->cpu_id];
440843e1988Sjohnlev 		break;
441843e1988Sjohnlev 	default:
442843e1988Sjohnlev 		evtchn = irqp->ii_u.evtchn;
443843e1988Sjohnlev 		break;
444843e1988Sjohnlev 	}
445843e1988Sjohnlev 
446843e1988Sjohnlev 	return (evtchn);
447843e1988Sjohnlev }
448843e1988Sjohnlev 
449349b53ddSStuart Maybee int
ec_is_edge_pirq(int irq)450349b53ddSStuart Maybee ec_is_edge_pirq(int irq)
451349b53ddSStuart Maybee {
452349b53ddSStuart Maybee 	return (irq_info[irq].ii_type == IRQT_PIRQ &&
453349b53ddSStuart Maybee 	    !TEST_EVTCHN_BIT(irq, &pirq_needs_eoi[0]));
454349b53ddSStuart Maybee }
455349b53ddSStuart Maybee 
456843e1988Sjohnlev static void
unbind_evtchn(ushort_t * evtchnp)457843e1988Sjohnlev unbind_evtchn(ushort_t *evtchnp)
458843e1988Sjohnlev {
459843e1988Sjohnlev 	int err;
460843e1988Sjohnlev 
461843e1988Sjohnlev 	ASSERT(MUTEX_HELD(&ec_lock));
462843e1988Sjohnlev 
463843e1988Sjohnlev 	ASSERT(*evtchnp != 0);
464843e1988Sjohnlev 
465843e1988Sjohnlev 	err = xen_close_evtchn(*evtchnp);
466843e1988Sjohnlev 	ASSERT(err == 0);
467843e1988Sjohnlev 	clear_evtchn_affinity(*evtchnp);
468843e1988Sjohnlev 	evtchn_to_irq[*evtchnp] = INVALID_IRQ;
469843e1988Sjohnlev 	*evtchnp = 0;
470843e1988Sjohnlev }
471843e1988Sjohnlev 
472843e1988Sjohnlev static void
pirq_unmask_notify(int pirq)473843e1988Sjohnlev pirq_unmask_notify(int pirq)
474843e1988Sjohnlev {
475843e1988Sjohnlev 	struct physdev_eoi eoi;
476843e1988Sjohnlev 
477843e1988Sjohnlev 	if (TEST_EVTCHN_BIT(pirq, &pirq_needs_eoi[0])) {
478843e1988Sjohnlev 		eoi.irq = pirq;
479843e1988Sjohnlev 		(void) HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
480843e1988Sjohnlev 	}
481843e1988Sjohnlev }
482843e1988Sjohnlev 
483843e1988Sjohnlev static void
pirq_query_unmask(int pirq)484843e1988Sjohnlev pirq_query_unmask(int pirq)
485843e1988Sjohnlev {
486843e1988Sjohnlev 	struct physdev_irq_status_query irq_status;
487843e1988Sjohnlev 
488843e1988Sjohnlev 	irq_status.irq = pirq;
489843e1988Sjohnlev 	(void) HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status);
490843e1988Sjohnlev 	CLEAR_EVTCHN_BIT(pirq, &pirq_needs_eoi[0]);
491843e1988Sjohnlev 	if (irq_status.flags & XENIRQSTAT_needs_eoi)
492843e1988Sjohnlev 		SET_EVTCHN_BIT(pirq, &pirq_needs_eoi[0]);
493843e1988Sjohnlev }
494843e1988Sjohnlev 
495843e1988Sjohnlev static void
end_pirq(int irq)496843e1988Sjohnlev end_pirq(int irq)
497843e1988Sjohnlev {
498843e1988Sjohnlev 	int evtchn = irq_evtchn(&irq_info[irq]);
499843e1988Sjohnlev 
500349b53ddSStuart Maybee 	/*
501349b53ddSStuart Maybee 	 * If it is an edge-triggered interrupt we have already unmasked
502349b53ddSStuart Maybee 	 */
503349b53ddSStuart Maybee 	if (TEST_EVTCHN_BIT(irq, &pirq_needs_eoi[0])) {
504349b53ddSStuart Maybee 		ec_unmask_evtchn(evtchn);
505349b53ddSStuart Maybee 		pirq_unmask_notify(IRQ_TO_PIRQ(irq));
506843e1988Sjohnlev 	}
507843e1988Sjohnlev }
508843e1988Sjohnlev 
509843e1988Sjohnlev /*
510843e1988Sjohnlev  * Bind an event channel to a vcpu
511843e1988Sjohnlev  */
512843e1988Sjohnlev void
ec_bind_vcpu(int evtchn,int cpu)513843e1988Sjohnlev ec_bind_vcpu(int evtchn, int cpu)
514843e1988Sjohnlev {
515843e1988Sjohnlev 	mutex_enter(&ec_lock);
516843e1988Sjohnlev 	xen_bind_vcpu(evtchn, cpu);
517843e1988Sjohnlev 	mutex_exit(&ec_lock);
518843e1988Sjohnlev }
519843e1988Sjohnlev 
520843e1988Sjohnlev /*
521843e1988Sjohnlev  * Set up a physical device irq to be associated with an event channel.
522843e1988Sjohnlev  */
523843e1988Sjohnlev void
ec_setup_pirq(int irq,int ipl,cpuset_t * cpusp)524b9bc7f78Ssmaybe ec_setup_pirq(int irq, int ipl, cpuset_t *cpusp)
525843e1988Sjohnlev {
526843e1988Sjohnlev 	int evtchn;
527843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
528843e1988Sjohnlev 
529843e1988Sjohnlev 	/*
530843e1988Sjohnlev 	 * Test if this PIRQ is already bound to an evtchn,
531843e1988Sjohnlev 	 * which means it is a shared IRQ and we don't want to
532843e1988Sjohnlev 	 * bind and do some initial setup that has already been
533843e1988Sjohnlev 	 * done for this irq on a previous trip through this code.
534843e1988Sjohnlev 	 */
535843e1988Sjohnlev 	if (irqp->ii_u.evtchn == INVALID_EVTCHN) {
536843e1988Sjohnlev 		evtchn = xen_bind_pirq(irq);
537843e1988Sjohnlev 
538843e1988Sjohnlev 		pirq_query_unmask(IRQ_TO_PIRQ(irq));
539843e1988Sjohnlev 
540843e1988Sjohnlev 		irqp->ii_type = IRQT_PIRQ;
541843e1988Sjohnlev 		irqp->ii_u.evtchn = evtchn;
542843e1988Sjohnlev 
543843e1988Sjohnlev 		evtchn_to_irq[evtchn] = irq;
544843e1988Sjohnlev 		irqp->ii_u2.ipl = ipl;
545b9bc7f78Ssmaybe 		ec_set_irq_affinity(irq, *cpusp);
546843e1988Sjohnlev 		ec_enable_irq(irq);
547843e1988Sjohnlev 		pirq_unmask_notify(IRQ_TO_PIRQ(irq));
548843e1988Sjohnlev 	} else {
549843e1988Sjohnlev 		ASSERT(irqp->ii_u2.ipl != 0);
550711f1c24Smrj 		cmn_err(CE_NOTE, "!IRQ%d is shared", irq);
551843e1988Sjohnlev 		if (ipl > irqp->ii_u2.ipl)
552843e1988Sjohnlev 			irqp->ii_u2.ipl = ipl;
553b9bc7f78Ssmaybe 		*cpusp = evtchn_cpus[irqp->ii_u.evtchn];
554843e1988Sjohnlev 	}
555843e1988Sjohnlev }
556843e1988Sjohnlev 
557843e1988Sjohnlev void
ec_unbind_irq(int irq)558843e1988Sjohnlev ec_unbind_irq(int irq)
559843e1988Sjohnlev {
560843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
561843e1988Sjohnlev 	mec_info_t *virqp;
562843e1988Sjohnlev 	int drop_lock = 0;
563843e1988Sjohnlev 	int type, i;
564843e1988Sjohnlev 
565843e1988Sjohnlev 	/*
566843e1988Sjohnlev 	 * Nasty, but we need this during suspend.
567843e1988Sjohnlev 	 */
568843e1988Sjohnlev 	if (mutex_owner(&ec_lock) != curthread) {
569843e1988Sjohnlev 		mutex_enter(&ec_lock);
570843e1988Sjohnlev 		drop_lock = 1;
571843e1988Sjohnlev 	}
572843e1988Sjohnlev 
573843e1988Sjohnlev 	type = irqp->ii_type;
574843e1988Sjohnlev 
575843e1988Sjohnlev 	ASSERT((type == IRQT_EVTCHN) || (type == IRQT_PIRQ) ||
576843e1988Sjohnlev 	    (type == IRQT_VIRQ));
577843e1988Sjohnlev 
578843e1988Sjohnlev 	if ((type == IRQT_EVTCHN) || (type == IRQT_PIRQ)) {
579843e1988Sjohnlev 		/* There's only one event channel associated with this irq */
580843e1988Sjohnlev 		unbind_evtchn(&irqp->ii_u.evtchn);
581843e1988Sjohnlev 	} else if (type == IRQT_VIRQ) {
582843e1988Sjohnlev 		/*
583843e1988Sjohnlev 		 * Each cpu on the system can have it's own event channel
584843e1988Sjohnlev 		 * associated with a virq.  Unbind them all.
585843e1988Sjohnlev 		 */
586843e1988Sjohnlev 		virqp = &virq_info[irqp->ii_u.index];
587843e1988Sjohnlev 		for (i = 0; i < NCPU; i++) {
588843e1988Sjohnlev 			if (virqp->mi_evtchns[i] != 0)
589843e1988Sjohnlev 				unbind_evtchn(&virqp->mi_evtchns[i]);
590843e1988Sjohnlev 		}
591843e1988Sjohnlev 		/* Mark the virq structure as invalid. */
592843e1988Sjohnlev 		virqp->mi_irq = INVALID_IRQ;
593843e1988Sjohnlev 	}
594843e1988Sjohnlev 
595843e1988Sjohnlev 	bzero(irqp, sizeof (*irqp));
596843e1988Sjohnlev 	/* Re-reserve PIRQ. */
597843e1988Sjohnlev 	if (type == IRQT_PIRQ)
598843e1988Sjohnlev 		irqp->ii_type = IRQT_PIRQ;
599843e1988Sjohnlev 
600843e1988Sjohnlev 	if (drop_lock)
601843e1988Sjohnlev 		mutex_exit(&ec_lock);
602843e1988Sjohnlev }
603843e1988Sjohnlev 
604843e1988Sjohnlev /*
605843e1988Sjohnlev  * Rebind an event channel for delivery to a CPU.
606843e1988Sjohnlev  */
607843e1988Sjohnlev void
ec_set_irq_affinity(int irq,cpuset_t dest)608843e1988Sjohnlev ec_set_irq_affinity(int irq, cpuset_t dest)
609843e1988Sjohnlev {
610843e1988Sjohnlev 	int evtchn, tcpu;
611843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
612843e1988Sjohnlev 
613843e1988Sjohnlev 	mutex_enter(&ec_lock);
614843e1988Sjohnlev 
615843e1988Sjohnlev 	ASSERT(irq < NR_IRQS);
616843e1988Sjohnlev 	ASSERT(irqp->ii_type != IRQT_UNBOUND);
617843e1988Sjohnlev 
618843e1988Sjohnlev 	/*
619843e1988Sjohnlev 	 * Binding is done at allocation time for these types, so we should
620843e1988Sjohnlev 	 * never modify them.
621843e1988Sjohnlev 	 */
622843e1988Sjohnlev 	if (irqp->ii_type == IRQT_IPI || irqp->ii_type == IRQT_VIRQ ||
623843e1988Sjohnlev 	    irqp->ii_type == IRQT_DEV_EVTCHN) {
624843e1988Sjohnlev 		mutex_exit(&ec_lock);
625843e1988Sjohnlev 		return;
626843e1988Sjohnlev 	}
627843e1988Sjohnlev 
628843e1988Sjohnlev 	CPUSET_FIND(dest, tcpu);
629843e1988Sjohnlev 	ASSERT(tcpu != CPUSET_NOTINSET);
630843e1988Sjohnlev 
631843e1988Sjohnlev 	evtchn = irq_evtchn(irqp);
632843e1988Sjohnlev 
633843e1988Sjohnlev 	xen_bind_vcpu(evtchn, tcpu);
634843e1988Sjohnlev 
635843e1988Sjohnlev 	bind_evtchn_to_cpuset(evtchn, dest);
636843e1988Sjohnlev 
637843e1988Sjohnlev 	mutex_exit(&ec_lock);
638843e1988Sjohnlev 
639843e1988Sjohnlev 	/*
640b9bc7f78Ssmaybe 	 * Now send the new target processor a NOP IPI.
641b9bc7f78Ssmaybe 	 * It will check for any pending interrupts, and so service any that
642843e1988Sjohnlev 	 * got delivered to the wrong processor by mistake.
643843e1988Sjohnlev 	 */
644a43153bfSsmaybe 	if (ncpus > 1)
645a43153bfSsmaybe 		poke_cpu(tcpu);
646843e1988Sjohnlev }
647843e1988Sjohnlev 
648843e1988Sjohnlev int
ec_set_irq_priority(int irq,int pri)649843e1988Sjohnlev ec_set_irq_priority(int irq, int pri)
650843e1988Sjohnlev {
651843e1988Sjohnlev 	irq_info_t *irqp;
652843e1988Sjohnlev 
653843e1988Sjohnlev 	if (irq >= NR_IRQS)
654843e1988Sjohnlev 		return (-1);
655843e1988Sjohnlev 
656843e1988Sjohnlev 	irqp = &irq_info[irq];
657843e1988Sjohnlev 
658843e1988Sjohnlev 	if (irqp->ii_type == IRQT_UNBOUND)
659843e1988Sjohnlev 		return (-1);
660843e1988Sjohnlev 
661843e1988Sjohnlev 	irqp->ii_u2.ipl = pri;
662843e1988Sjohnlev 
663843e1988Sjohnlev 	return (0);
664843e1988Sjohnlev }
665843e1988Sjohnlev 
666843e1988Sjohnlev void
ec_clear_irq_priority(int irq)667843e1988Sjohnlev ec_clear_irq_priority(int irq)
668843e1988Sjohnlev {
669843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
670843e1988Sjohnlev 
671843e1988Sjohnlev 	ASSERT(irq < NR_IRQS);
672843e1988Sjohnlev 	ASSERT(irqp->ii_type != IRQT_UNBOUND);
673843e1988Sjohnlev 
674843e1988Sjohnlev 	irqp->ii_u2.ipl = 0;
675843e1988Sjohnlev }
676843e1988Sjohnlev 
677843e1988Sjohnlev int
ec_bind_evtchn_to_irq(int evtchn)678843e1988Sjohnlev ec_bind_evtchn_to_irq(int evtchn)
679843e1988Sjohnlev {
680843e1988Sjohnlev 	mutex_enter(&ec_lock);
681843e1988Sjohnlev 
682843e1988Sjohnlev 	ASSERT(evtchn_to_irq[evtchn] == INVALID_IRQ);
683843e1988Sjohnlev 
684843e1988Sjohnlev 	(void) alloc_irq(IRQT_EVTCHN, 0, evtchn, -1);
685843e1988Sjohnlev 
686843e1988Sjohnlev 	mutex_exit(&ec_lock);
687843e1988Sjohnlev 	return (evtchn_to_irq[evtchn]);
688843e1988Sjohnlev }
689843e1988Sjohnlev 
690843e1988Sjohnlev int
ec_bind_virq_to_irq(int virq,int cpu)691843e1988Sjohnlev ec_bind_virq_to_irq(int virq, int cpu)
692843e1988Sjohnlev {
693843e1988Sjohnlev 	int err;
694843e1988Sjohnlev 	int evtchn;
695843e1988Sjohnlev 	mec_info_t *virqp;
696843e1988Sjohnlev 
697843e1988Sjohnlev 	virqp = &virq_info[virq];
698843e1988Sjohnlev 	mutex_enter(&ec_lock);
699843e1988Sjohnlev 
700843e1988Sjohnlev 	err = xen_bind_virq(virq, cpu, &evtchn);
701843e1988Sjohnlev 	ASSERT(err == 0);
702843e1988Sjohnlev 
703843e1988Sjohnlev 	ASSERT(evtchn_to_irq[evtchn] == INVALID_IRQ);
704843e1988Sjohnlev 
705843e1988Sjohnlev 	if (virqp->mi_irq == INVALID_IRQ) {
706843e1988Sjohnlev 		virqp->mi_irq = alloc_irq(IRQT_VIRQ, virq, evtchn, cpu);
707843e1988Sjohnlev 	} else {
708843e1988Sjohnlev 		alloc_irq_evtchn(virqp->mi_irq, virq, evtchn, cpu);
709843e1988Sjohnlev 	}
710843e1988Sjohnlev 
711843e1988Sjohnlev 	mutex_exit(&ec_lock);
712843e1988Sjohnlev 
713843e1988Sjohnlev 	return (virqp->mi_irq);
714843e1988Sjohnlev }
715843e1988Sjohnlev 
716843e1988Sjohnlev int
ec_bind_ipi_to_irq(int ipl,int cpu)717843e1988Sjohnlev ec_bind_ipi_to_irq(int ipl, int cpu)
718843e1988Sjohnlev {
719843e1988Sjohnlev 	int evtchn;
720843e1988Sjohnlev 	ulong_t flags;
721843e1988Sjohnlev 	mec_info_t *ipip;
722843e1988Sjohnlev 
723843e1988Sjohnlev 	mutex_enter(&ec_lock);
724843e1988Sjohnlev 
725843e1988Sjohnlev 	ipip = &ipi_info[ipl];
726843e1988Sjohnlev 
727843e1988Sjohnlev 	evtchn = xen_bind_ipi(cpu);
728843e1988Sjohnlev 
729843e1988Sjohnlev 	ASSERT(evtchn_to_irq[evtchn] == INVALID_IRQ);
730843e1988Sjohnlev 
731843e1988Sjohnlev 	if (ipip->mi_irq == INVALID_IRQ) {
732843e1988Sjohnlev 		ipip->mi_irq = alloc_irq(IRQT_IPI, ipl, evtchn, cpu);
733843e1988Sjohnlev 	} else {
734843e1988Sjohnlev 		alloc_irq_evtchn(ipip->mi_irq, ipl, evtchn, cpu);
735843e1988Sjohnlev 	}
736843e1988Sjohnlev 
737843e1988Sjohnlev 	/*
738843e1988Sjohnlev 	 * Unmask the new evtchn so that it can be seen by the target cpu
739843e1988Sjohnlev 	 */
740843e1988Sjohnlev 	flags = intr_clear();
741843e1988Sjohnlev 	ec_unmask_evtchn(evtchn);
742843e1988Sjohnlev 	intr_restore(flags);
743843e1988Sjohnlev 
744843e1988Sjohnlev 	mutex_exit(&ec_lock);
745843e1988Sjohnlev 	return (ipip->mi_irq);
746843e1988Sjohnlev }
747843e1988Sjohnlev 
748843e1988Sjohnlev /*
749843e1988Sjohnlev  * When bringing up a CPU, bind to all the IPIs that CPU0 bound.
750843e1988Sjohnlev  */
751843e1988Sjohnlev void
ec_bind_cpu_ipis(int cpu)752843e1988Sjohnlev ec_bind_cpu_ipis(int cpu)
753843e1988Sjohnlev {
754843e1988Sjohnlev 	int i;
755843e1988Sjohnlev 
756843e1988Sjohnlev 	for (i = 0; i < MAXIPL; i++) {
757843e1988Sjohnlev 		mec_info_t *ipip = &ipi_info[i];
758843e1988Sjohnlev 		if (ipip->mi_irq == INVALID_IRQ)
759843e1988Sjohnlev 			continue;
760843e1988Sjohnlev 
761843e1988Sjohnlev 		(void) ec_bind_ipi_to_irq(i, cpu);
762843e1988Sjohnlev 	}
763843e1988Sjohnlev }
764843e1988Sjohnlev 
765843e1988Sjohnlev /*
766843e1988Sjohnlev  * Can this IRQ be rebound to another CPU?
767843e1988Sjohnlev  */
768843e1988Sjohnlev int
ec_irq_rebindable(int irq)769843e1988Sjohnlev ec_irq_rebindable(int irq)
770843e1988Sjohnlev {
771843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
772843e1988Sjohnlev 
773843e1988Sjohnlev 	if (irqp->ii_u.evtchn == 0)
774843e1988Sjohnlev 		return (0);
775843e1988Sjohnlev 
776843e1988Sjohnlev 	return (irqp->ii_type == IRQT_EVTCHN || irqp->ii_type == IRQT_PIRQ);
777843e1988Sjohnlev }
778843e1988Sjohnlev 
779843e1988Sjohnlev /*
780843e1988Sjohnlev  * Should this IRQ be unbound from this CPU (which is being offlined) to
781843e1988Sjohnlev  * another?
782843e1988Sjohnlev  */
783843e1988Sjohnlev int
ec_irq_needs_rebind(int irq,int cpu)784843e1988Sjohnlev ec_irq_needs_rebind(int irq, int cpu)
785843e1988Sjohnlev {
786843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
787843e1988Sjohnlev 
788843e1988Sjohnlev 	return (ec_irq_rebindable(irq) &&
789843e1988Sjohnlev 	    CPU_IN_SET(evtchn_cpus[irqp->ii_u.evtchn], cpu));
790843e1988Sjohnlev }
791843e1988Sjohnlev 
792843e1988Sjohnlev void
ec_send_ipi(int ipl,int cpu)793843e1988Sjohnlev ec_send_ipi(int ipl, int cpu)
794843e1988Sjohnlev {
795843e1988Sjohnlev 	mec_info_t *ipip = &ipi_info[ipl];
796843e1988Sjohnlev 
797843e1988Sjohnlev 	ASSERT(ipip->mi_irq != INVALID_IRQ);
798843e1988Sjohnlev 
799843e1988Sjohnlev 	ec_notify_via_evtchn(ipip->mi_evtchns[cpu]);
800843e1988Sjohnlev }
801843e1988Sjohnlev 
802843e1988Sjohnlev void
ec_try_ipi(int ipl,int cpu)803843e1988Sjohnlev ec_try_ipi(int ipl, int cpu)
804843e1988Sjohnlev {
805843e1988Sjohnlev 	mec_info_t *ipip = &ipi_info[ipl];
806843e1988Sjohnlev 
807843e1988Sjohnlev 	if (ipip->mi_irq == INVALID_IRQ || ipip->mi_irq == 0)
808843e1988Sjohnlev 		return;
809843e1988Sjohnlev 
810843e1988Sjohnlev 	ec_notify_via_evtchn(ipip->mi_evtchns[cpu]);
811843e1988Sjohnlev }
812843e1988Sjohnlev 
813843e1988Sjohnlev void
ec_irq_add_evtchn(int irq,int evtchn)814843e1988Sjohnlev ec_irq_add_evtchn(int irq, int evtchn)
815843e1988Sjohnlev {
816843e1988Sjohnlev 	mutex_enter(&ec_lock);
817843e1988Sjohnlev 
818843e1988Sjohnlev 	/*
819843e1988Sjohnlev 	 * See description of IRQT_DEV_EVTCHN above.
820843e1988Sjohnlev 	 */
821843e1988Sjohnlev 	ASSERT(irq == ec_dev_irq);
822843e1988Sjohnlev 
823843e1988Sjohnlev 	alloc_irq_evtchn(irq, 0, evtchn, 0);
824843e1988Sjohnlev 	/*
825843e1988Sjohnlev 	 * We enforce that the representative event channel for IRQT_DEV_EVTCHN
826843e1988Sjohnlev 	 * is zero, so PSM operations on it have no effect.
827843e1988Sjohnlev 	 */
828843e1988Sjohnlev 	irq_info[irq].ii_u.evtchn = 0;
829843e1988Sjohnlev 	mutex_exit(&ec_lock);
830843e1988Sjohnlev }
831843e1988Sjohnlev 
832843e1988Sjohnlev void
ec_irq_rm_evtchn(int irq,int evtchn)833843e1988Sjohnlev ec_irq_rm_evtchn(int irq, int evtchn)
834843e1988Sjohnlev {
835843e1988Sjohnlev 	ushort_t ec = evtchn;
836843e1988Sjohnlev 
837843e1988Sjohnlev 	mutex_enter(&ec_lock);
838843e1988Sjohnlev 	ASSERT(irq == ec_dev_irq);
839843e1988Sjohnlev 	unbind_evtchn(&ec);
840843e1988Sjohnlev 	mutex_exit(&ec_lock);
841843e1988Sjohnlev }
842843e1988Sjohnlev 
843843e1988Sjohnlev /*
844843e1988Sjohnlev  * Allocate an /dev/xen/evtchn IRQ.  See the big comment at the top
845843e1988Sjohnlev  * for an explanation.
846843e1988Sjohnlev  */
847843e1988Sjohnlev int
ec_dev_alloc_irq(void)848843e1988Sjohnlev ec_dev_alloc_irq(void)
849843e1988Sjohnlev {
850843e1988Sjohnlev 	int i;
851843e1988Sjohnlev 	irq_info_t *irqp;
852843e1988Sjohnlev 
853843e1988Sjohnlev 	for (i = 0; i < NR_IRQS; i++) {
854843e1988Sjohnlev 		if (irq_info[i].ii_type == IRQT_UNBOUND)
855843e1988Sjohnlev 			break;
856843e1988Sjohnlev 	}
857843e1988Sjohnlev 
858843e1988Sjohnlev 	ASSERT(i != NR_IRQS);
859843e1988Sjohnlev 
860843e1988Sjohnlev 	irqp = &irq_info[i];
861843e1988Sjohnlev 	irqp->ii_type = IRQT_DEV_EVTCHN;
862843e1988Sjohnlev 	irqp->ii_u2.ipl = IPL_EVTCHN;
863843e1988Sjohnlev 	/*
864843e1988Sjohnlev 	 * Force the evtchn to zero for the special evtchn device irq
865843e1988Sjohnlev 	 */
866843e1988Sjohnlev 	irqp->ii_u.evtchn = 0;
867843e1988Sjohnlev 	return (i);
868843e1988Sjohnlev }
869843e1988Sjohnlev 
870843e1988Sjohnlev void
ec_enable_irq(unsigned int irq)871843e1988Sjohnlev ec_enable_irq(unsigned int irq)
872843e1988Sjohnlev {
873843e1988Sjohnlev 	ulong_t flag;
874843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
875843e1988Sjohnlev 
876843e1988Sjohnlev 	if (irqp->ii_type == IRQT_DEV_EVTCHN)
877843e1988Sjohnlev 		return;
878843e1988Sjohnlev 
879843e1988Sjohnlev 	flag = intr_clear();
880843e1988Sjohnlev 	ec_unmask_evtchn(irq_evtchn(irqp));
881843e1988Sjohnlev 	intr_restore(flag);
882843e1988Sjohnlev }
883843e1988Sjohnlev 
884843e1988Sjohnlev void
ec_disable_irq(unsigned int irq)885843e1988Sjohnlev ec_disable_irq(unsigned int irq)
886843e1988Sjohnlev {
887843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
888843e1988Sjohnlev 
889843e1988Sjohnlev 	if (irqp->ii_type == IRQT_DEV_EVTCHN)
890843e1988Sjohnlev 		return;
891843e1988Sjohnlev 
892843e1988Sjohnlev 	/*
893843e1988Sjohnlev 	 * Spin till we are the one to mask the evtchn
894843e1988Sjohnlev 	 * Ensures no one else can be servicing this evtchn.
895843e1988Sjohnlev 	 */
896843e1988Sjohnlev 	while (!ec_mask_evtchn(irq_evtchn(irqp)))
897843e1988Sjohnlev 		SMT_PAUSE();
898843e1988Sjohnlev }
899843e1988Sjohnlev 
900843e1988Sjohnlev static int
ec_evtchn_pending(uint_t ev)901843e1988Sjohnlev ec_evtchn_pending(uint_t ev)
902843e1988Sjohnlev {
903843e1988Sjohnlev 	uint_t evi;
904843e1988Sjohnlev 	shared_info_t *si = HYPERVISOR_shared_info;
905843e1988Sjohnlev 
906843e1988Sjohnlev 	evi = ev >> EVTCHN_SHIFT;
907843e1988Sjohnlev 	ev &= (1ul << EVTCHN_SHIFT) - 1;
908843e1988Sjohnlev 	return ((si->evtchn_pending[evi] & (1ul << ev)) != 0);
909843e1988Sjohnlev }
910843e1988Sjohnlev 
911843e1988Sjohnlev int
ec_pending_irq(unsigned int irq)912843e1988Sjohnlev ec_pending_irq(unsigned int irq)
913843e1988Sjohnlev {
914843e1988Sjohnlev 	int evtchn = irq_evtchn(&irq_info[irq]);
915843e1988Sjohnlev 
916843e1988Sjohnlev 	return (ec_evtchn_pending(evtchn));
917843e1988Sjohnlev }
918843e1988Sjohnlev 
919843e1988Sjohnlev void
ec_clear_irq(int irq)920843e1988Sjohnlev ec_clear_irq(int irq)
921843e1988Sjohnlev {
922843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
923843e1988Sjohnlev 	int evtchn;
924843e1988Sjohnlev 
925843e1988Sjohnlev 	if (irqp->ii_type == IRQT_DEV_EVTCHN)
926843e1988Sjohnlev 		return;
927843e1988Sjohnlev 
928843e1988Sjohnlev 	ASSERT(irqp->ii_type != IRQT_UNBOUND);
929843e1988Sjohnlev 
930843e1988Sjohnlev 	evtchn = irq_evtchn(irqp);
931843e1988Sjohnlev 
932843e1988Sjohnlev 	ASSERT(EVTCHN_MASKED(evtchn));
933843e1988Sjohnlev 	ec_clear_evtchn(evtchn);
934843e1988Sjohnlev }
935843e1988Sjohnlev 
936843e1988Sjohnlev void
ec_unmask_irq(int irq)937843e1988Sjohnlev ec_unmask_irq(int irq)
938843e1988Sjohnlev {
939843e1988Sjohnlev 	ulong_t flags;
940843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
941843e1988Sjohnlev 
942843e1988Sjohnlev 	flags = intr_clear();
943843e1988Sjohnlev 	switch (irqp->ii_type) {
944843e1988Sjohnlev 	case IRQT_PIRQ:
945843e1988Sjohnlev 		end_pirq(irq);
946843e1988Sjohnlev 		break;
947843e1988Sjohnlev 	case IRQT_DEV_EVTCHN:
948843e1988Sjohnlev 		break;
949843e1988Sjohnlev 	default:
950843e1988Sjohnlev 		ec_unmask_evtchn(irq_evtchn(irqp));
951843e1988Sjohnlev 		break;
952843e1988Sjohnlev 	}
953843e1988Sjohnlev 	intr_restore(flags);
954843e1988Sjohnlev }
955843e1988Sjohnlev 
956843e1988Sjohnlev void
ec_try_unmask_irq(int irq)957843e1988Sjohnlev ec_try_unmask_irq(int irq)
958843e1988Sjohnlev {
959843e1988Sjohnlev 	ulong_t flags;
960843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
961843e1988Sjohnlev 	int evtchn;
962843e1988Sjohnlev 
963843e1988Sjohnlev 	flags = intr_clear();
964843e1988Sjohnlev 	switch (irqp->ii_type) {
965843e1988Sjohnlev 	case IRQT_PIRQ:
966843e1988Sjohnlev 		end_pirq(irq);
967843e1988Sjohnlev 		break;
968843e1988Sjohnlev 	case IRQT_DEV_EVTCHN:
969843e1988Sjohnlev 		break;
970843e1988Sjohnlev 	default:
971843e1988Sjohnlev 		if ((evtchn = irq_evtchn(irqp)) != 0)
972843e1988Sjohnlev 			ec_unmask_evtchn(evtchn);
973843e1988Sjohnlev 		break;
974843e1988Sjohnlev 	}
975843e1988Sjohnlev 	intr_restore(flags);
976843e1988Sjohnlev }
977843e1988Sjohnlev 
978843e1988Sjohnlev /*
979843e1988Sjohnlev  * Poll until an event channel is ready or 'check_func' returns true.  This can
980843e1988Sjohnlev  * only be used in a situation where interrupts are masked, otherwise we have a
981843e1988Sjohnlev  * classic time-of-check vs. time-of-use race.
982843e1988Sjohnlev  */
983843e1988Sjohnlev void
ec_wait_on_evtchn(int evtchn,int (* check_func)(void *),void * arg)984843e1988Sjohnlev ec_wait_on_evtchn(int evtchn, int (*check_func)(void *), void *arg)
985843e1988Sjohnlev {
986843e1988Sjohnlev 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
987843e1988Sjohnlev 		while (!check_func(arg))
988843e1988Sjohnlev 			(void) HYPERVISOR_yield();
989843e1988Sjohnlev 		return;
990843e1988Sjohnlev 	}
991843e1988Sjohnlev 
992843e1988Sjohnlev 	ASSERT(CPU->cpu_m.mcpu_vcpu_info->evtchn_upcall_mask != 0);
993843e1988Sjohnlev 
994843e1988Sjohnlev 	for (;;) {
995843e1988Sjohnlev 		evtchn_port_t ports[1];
996843e1988Sjohnlev 
997843e1988Sjohnlev 		ports[0] = evtchn;
998843e1988Sjohnlev 
999843e1988Sjohnlev 		ec_clear_evtchn(evtchn);
1000843e1988Sjohnlev 
1001843e1988Sjohnlev 		if (check_func(arg))
1002843e1988Sjohnlev 			return;
1003843e1988Sjohnlev 
1004843e1988Sjohnlev 		(void) HYPERVISOR_poll(ports, 1, 0);
1005843e1988Sjohnlev 	}
1006843e1988Sjohnlev }
1007843e1988Sjohnlev 
1008843e1988Sjohnlev void
ec_wait_on_ipi(int ipl,int (* check_func)(void *),void * arg)1009843e1988Sjohnlev ec_wait_on_ipi(int ipl, int (*check_func)(void *), void *arg)
1010843e1988Sjohnlev {
1011843e1988Sjohnlev 	mec_info_t *ipip = &ipi_info[ipl];
1012843e1988Sjohnlev 
1013843e1988Sjohnlev 	if (ipip->mi_irq == INVALID_IRQ || ipip->mi_irq == 0)
1014843e1988Sjohnlev 		return;
1015843e1988Sjohnlev 
1016843e1988Sjohnlev 	ec_wait_on_evtchn(ipip->mi_evtchns[CPU->cpu_id], check_func, arg);
1017843e1988Sjohnlev }
1018843e1988Sjohnlev 
1019843e1988Sjohnlev void
ec_suspend(void)1020843e1988Sjohnlev ec_suspend(void)
1021843e1988Sjohnlev {
1022843e1988Sjohnlev 	irq_info_t *irqp;
1023843e1988Sjohnlev 	ushort_t *evtchnp;
1024843e1988Sjohnlev 	int i;
1025843e1988Sjohnlev 	int c;
1026843e1988Sjohnlev 
1027843e1988Sjohnlev 	ASSERT(MUTEX_HELD(&ec_lock));
1028843e1988Sjohnlev 
1029843e1988Sjohnlev 	for (i = 0; i < MAXIPL; i++) {
1030843e1988Sjohnlev 		if (ipi_info[i].mi_irq == INVALID_IRQ)
1031843e1988Sjohnlev 			continue;
1032843e1988Sjohnlev 
1033843e1988Sjohnlev 		for (c = 0; c < NCPU; c++) {
1034843e1988Sjohnlev 			if (cpu[c] == NULL)
1035843e1988Sjohnlev 				continue;
1036843e1988Sjohnlev 
1037843e1988Sjohnlev 			if (CPU_IN_SET(cpu_suspend_lost_set, c))
1038843e1988Sjohnlev 				continue;
1039843e1988Sjohnlev 
1040843e1988Sjohnlev 			evtchnp = &ipi_info[i].mi_evtchns[c];
1041843e1988Sjohnlev 			ASSERT(*evtchnp != 0);
1042843e1988Sjohnlev 			unbind_evtchn(evtchnp);
1043843e1988Sjohnlev 		}
1044843e1988Sjohnlev 	}
1045843e1988Sjohnlev 
1046843e1988Sjohnlev 	for (i = 0; i < NR_VIRQS; i++) {
1047843e1988Sjohnlev 		if (virq_info[i].mi_irq == INVALID_IRQ)
1048843e1988Sjohnlev 			continue;
1049843e1988Sjohnlev 
1050843e1988Sjohnlev 		/*
1051843e1988Sjohnlev 		 * If we're sharing a single event channel across all CPUs, we
1052843e1988Sjohnlev 		 * should only unbind once.
1053843e1988Sjohnlev 		 */
1054843e1988Sjohnlev 		if (virq_info[i].mi_shared) {
1055843e1988Sjohnlev 			evtchnp = &virq_info[i].mi_evtchns[0];
1056843e1988Sjohnlev 			unbind_evtchn(evtchnp);
1057843e1988Sjohnlev 			for (c = 1; c < NCPU; c++)
1058843e1988Sjohnlev 				virq_info[i].mi_evtchns[c] = 0;
1059843e1988Sjohnlev 		} else {
1060843e1988Sjohnlev 			for (c = 0; c < NCPU; c++) {
1061843e1988Sjohnlev 				if (cpu[c] == NULL)
1062843e1988Sjohnlev 					continue;
1063843e1988Sjohnlev 
1064843e1988Sjohnlev 				evtchnp = &virq_info[i].mi_evtchns[c];
1065843e1988Sjohnlev 				if (*evtchnp != 0)
1066843e1988Sjohnlev 					unbind_evtchn(evtchnp);
1067843e1988Sjohnlev 			}
1068843e1988Sjohnlev 		}
1069843e1988Sjohnlev 	}
1070843e1988Sjohnlev 
1071843e1988Sjohnlev 	for (i = 0; i < NR_IRQS; i++) {
1072843e1988Sjohnlev 		irqp = &irq_info[i];
1073843e1988Sjohnlev 
1074843e1988Sjohnlev 		switch (irqp->ii_type) {
1075843e1988Sjohnlev 		case IRQT_EVTCHN:
1076843e1988Sjohnlev 		case IRQT_DEV_EVTCHN:
1077843e1988Sjohnlev 			(void) HYPERVISOR_shutdown(SHUTDOWN_crash);
1078843e1988Sjohnlev 			break;
1079843e1988Sjohnlev 		case IRQT_PIRQ:
1080843e1988Sjohnlev 			if (irqp->ii_u.evtchn != 0)
1081843e1988Sjohnlev 				(void) HYPERVISOR_shutdown(SHUTDOWN_crash);
1082843e1988Sjohnlev 			break;
1083843e1988Sjohnlev 		default:
1084843e1988Sjohnlev 			break;
1085843e1988Sjohnlev 		}
1086843e1988Sjohnlev 	}
1087843e1988Sjohnlev }
1088843e1988Sjohnlev 
1089843e1988Sjohnlev /*
1090843e1988Sjohnlev  * The debug irq is special, we only have one evtchn and irq but we allow all
1091843e1988Sjohnlev  * cpus to service it.  It's marked as shared and we propogate the event
1092843e1988Sjohnlev  * channel into all CPUs by hand.
1093843e1988Sjohnlev  */
1094843e1988Sjohnlev static void
share_virq(mec_info_t * virqp)1095843e1988Sjohnlev share_virq(mec_info_t *virqp)
1096843e1988Sjohnlev {
1097843e1988Sjohnlev 	int evtchn = virqp->mi_evtchns[0];
1098843e1988Sjohnlev 	cpuset_t tset;
1099843e1988Sjohnlev 	int i;
1100843e1988Sjohnlev 
1101843e1988Sjohnlev 	ASSERT(evtchn != 0);
1102843e1988Sjohnlev 
1103843e1988Sjohnlev 	virqp->mi_shared = 1;
1104843e1988Sjohnlev 
1105843e1988Sjohnlev 	for (i = 1; i < NCPU; i++)
1106843e1988Sjohnlev 		virqp->mi_evtchns[i] = evtchn;
1107843e1988Sjohnlev 	CPUSET_ALL(tset);
1108843e1988Sjohnlev 	bind_evtchn_to_cpuset(evtchn, tset);
1109843e1988Sjohnlev }
1110843e1988Sjohnlev 
1111843e1988Sjohnlev static void
virq_resume(int virq)1112843e1988Sjohnlev virq_resume(int virq)
1113843e1988Sjohnlev {
1114843e1988Sjohnlev 	mec_info_t *virqp = &virq_info[virq];
1115843e1988Sjohnlev 	int evtchn;
1116843e1988Sjohnlev 	int i, err;
1117843e1988Sjohnlev 
1118843e1988Sjohnlev 	for (i = 0; i < NCPU; i++) {
1119843e1988Sjohnlev 		cpuset_t tcpus;
1120843e1988Sjohnlev 
1121843e1988Sjohnlev 		if (cpu[i] == NULL || CPU_IN_SET(cpu_suspend_lost_set, i))
1122843e1988Sjohnlev 			continue;
1123843e1988Sjohnlev 
1124843e1988Sjohnlev 		err = xen_bind_virq(virq, i, &evtchn);
1125843e1988Sjohnlev 		ASSERT(err == 0);
1126843e1988Sjohnlev 
1127843e1988Sjohnlev 		virqp->mi_evtchns[i] = evtchn;
1128843e1988Sjohnlev 		evtchn_to_irq[evtchn] = virqp->mi_irq;
1129843e1988Sjohnlev 		CPUSET_ONLY(tcpus, i);
1130843e1988Sjohnlev 		bind_evtchn_to_cpuset(evtchn, tcpus);
1131843e1988Sjohnlev 		ec_unmask_evtchn(evtchn);
1132843e1988Sjohnlev 		/*
1133843e1988Sjohnlev 		 * only timer VIRQ is bound to all cpus
1134843e1988Sjohnlev 		 */
1135843e1988Sjohnlev 		if (virq != VIRQ_TIMER)
1136843e1988Sjohnlev 			break;
1137843e1988Sjohnlev 	}
1138843e1988Sjohnlev 
1139843e1988Sjohnlev 	if (virqp->mi_shared)
1140843e1988Sjohnlev 		share_virq(virqp);
1141843e1988Sjohnlev }
1142843e1988Sjohnlev 
1143843e1988Sjohnlev static void
ipi_resume(int ipl)1144843e1988Sjohnlev ipi_resume(int ipl)
1145843e1988Sjohnlev {
1146843e1988Sjohnlev 	mec_info_t *ipip = &ipi_info[ipl];
1147843e1988Sjohnlev 	int i;
1148843e1988Sjohnlev 
1149843e1988Sjohnlev 	for (i = 0; i < NCPU; i++) {
1150843e1988Sjohnlev 		cpuset_t tcpus;
1151843e1988Sjohnlev 		int evtchn;
1152843e1988Sjohnlev 
1153843e1988Sjohnlev 		if (cpu[i] == NULL || CPU_IN_SET(cpu_suspend_lost_set, i))
1154843e1988Sjohnlev 			continue;
1155843e1988Sjohnlev 
1156843e1988Sjohnlev 		evtchn = xen_bind_ipi(i);
1157843e1988Sjohnlev 		ipip->mi_evtchns[i] = evtchn;
1158843e1988Sjohnlev 		evtchn_to_irq[evtchn] = ipip->mi_irq;
1159843e1988Sjohnlev 		CPUSET_ONLY(tcpus, i);
1160843e1988Sjohnlev 		bind_evtchn_to_cpuset(evtchn, tcpus);
1161843e1988Sjohnlev 		ec_unmask_evtchn(evtchn);
1162843e1988Sjohnlev 	}
1163843e1988Sjohnlev }
1164843e1988Sjohnlev 
1165843e1988Sjohnlev void
ec_resume(void)1166843e1988Sjohnlev ec_resume(void)
1167843e1988Sjohnlev {
1168843e1988Sjohnlev 	int i;
1169843e1988Sjohnlev 
1170843e1988Sjohnlev 	/* New event-channel space is not 'live' yet. */
1171843e1988Sjohnlev 	for (i = 0; i < NR_EVENT_CHANNELS; i++)
1172843e1988Sjohnlev 		(void) ec_mask_evtchn(i);
1173843e1988Sjohnlev 
1174843e1988Sjohnlev 	for (i = 0; i < MAXIPL; i++) {
1175843e1988Sjohnlev 		if (ipi_info[i].mi_irq == INVALID_IRQ)
1176843e1988Sjohnlev 			continue;
1177843e1988Sjohnlev 		ipi_resume(i);
1178843e1988Sjohnlev 	}
1179843e1988Sjohnlev 
1180843e1988Sjohnlev 	for (i = 0; i < NR_VIRQS; i++) {
1181843e1988Sjohnlev 		if (virq_info[i].mi_irq == INVALID_IRQ)
1182843e1988Sjohnlev 			continue;
1183843e1988Sjohnlev 		virq_resume(i);
1184843e1988Sjohnlev 	}
1185843e1988Sjohnlev }
1186843e1988Sjohnlev 
1187349b53ddSStuart Maybee int
ec_init(void)1188843e1988Sjohnlev ec_init(void)
1189843e1988Sjohnlev {
1190843e1988Sjohnlev 	int i;
1191843e1988Sjohnlev 	mutex_init(&ec_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7));
1192843e1988Sjohnlev 
1193843e1988Sjohnlev 	for (i = 0; i < NR_EVENT_CHANNELS; i++) {
1194843e1988Sjohnlev 		CPUSET_ZERO(evtchn_cpus[i]);
1195843e1988Sjohnlev 		evtchn_to_irq[i] = INVALID_IRQ;
1196843e1988Sjohnlev 		(void) ec_mask_evtchn(i);
1197843e1988Sjohnlev 	}
1198843e1988Sjohnlev 
1199843e1988Sjohnlev 	for (i = 0; i < MAXIPL; i++)
1200843e1988Sjohnlev 		ipi_info[i].mi_irq = INVALID_IRQ;
1201843e1988Sjohnlev 
1202843e1988Sjohnlev 	for (i = 0; i < NR_VIRQS; i++)
1203843e1988Sjohnlev 		virq_info[i].mi_irq = INVALID_IRQ;
1204843e1988Sjohnlev 
1205843e1988Sjohnlev 	/*
1206843e1988Sjohnlev 	 * Phys IRQ space is statically bound (1:1 mapping), grab the IRQs
1207843e1988Sjohnlev 	 * now.
1208843e1988Sjohnlev 	 */
1209843e1988Sjohnlev 	for (i = PIRQ_BASE; i < NR_PIRQS; i++) {
1210843e1988Sjohnlev 		irq_info[PIRQ_TO_IRQ(i)].ii_type = IRQT_PIRQ;
1211843e1988Sjohnlev 	}
1212349b53ddSStuart Maybee 
1213349b53ddSStuart Maybee 	return (0);
1214843e1988Sjohnlev }
1215843e1988Sjohnlev 
1216843e1988Sjohnlev void
ec_init_debug_irq()1217843e1988Sjohnlev ec_init_debug_irq()
1218843e1988Sjohnlev {
1219843e1988Sjohnlev 	int irq;
1220843e1988Sjohnlev 
1221843e1988Sjohnlev 	irq = ec_bind_virq_to_irq(VIRQ_DEBUG, 0);
1222*db830ba5SToomas Soome 	(void) add_avintr(NULL, IPL_DEBUG, xen_debug_handler,
1223843e1988Sjohnlev 	    "debug", irq, NULL, NULL, NULL, NULL);
1224843e1988Sjohnlev 
1225843e1988Sjohnlev 	mutex_enter(&ec_lock);
1226843e1988Sjohnlev 	share_virq(&virq_info[irq_info[irq].ii_u.index]);
1227843e1988Sjohnlev 	mutex_exit(&ec_lock);
1228843e1988Sjohnlev 	ec_debug_irq = irq;
1229843e1988Sjohnlev }
1230843e1988Sjohnlev 
1231843e1988Sjohnlev #define	UNBLOCKED_EVENTS(si, ix, cpe, cpu_id) \
1232843e1988Sjohnlev 	((si)->evtchn_pending[ix] & ~(si)->evtchn_mask[ix] & \
1233843e1988Sjohnlev 		(cpe)->evt_affinity[ix])
1234843e1988Sjohnlev 
1235349b53ddSStuart Maybee 
1236843e1988Sjohnlev /*
1237843e1988Sjohnlev  * This is the entry point for processing events from xen
1238843e1988Sjohnlev  *
1239843e1988Sjohnlev  * (See the commentary associated with the shared_info_st structure
1240843e1988Sjohnlev  * in hypervisor-if.h)
1241843e1988Sjohnlev  *
1242843e1988Sjohnlev  * Since the event channel mechanism doesn't really implement the
1243843e1988Sjohnlev  * concept of priority like hardware interrupt controllers, we simulate
1244843e1988Sjohnlev  * that in software here using the cpu priority field and the pending
1245843e1988Sjohnlev  * interrupts field.  Events/interrupts that are not able to be serviced
1246843e1988Sjohnlev  * now because they are at a lower priority than the current cpu priority
1247843e1988Sjohnlev  * cause a level bit to be recorded in the pending interrupts word.  When
1248843e1988Sjohnlev  * the priority is lowered (either by spl or interrupt exit code) the pending
1249843e1988Sjohnlev  * levels are checked and an upcall is scheduled if there are events/interrupts
1250843e1988Sjohnlev  * that have become deliverable.
1251843e1988Sjohnlev  */
1252843e1988Sjohnlev void
xen_callback_handler(struct regs * rp,trap_trace_rec_t * ttp)1253843e1988Sjohnlev xen_callback_handler(struct regs *rp, trap_trace_rec_t *ttp)
1254843e1988Sjohnlev {
1255843e1988Sjohnlev 	ulong_t pending_sels, pe, selbit;
1256349b53ddSStuart Maybee 	int i, j, port, pri, curpri, irq, sipri;
1257349b53ddSStuart Maybee 	uint16_t pending_ints, sip;
1258843e1988Sjohnlev 	struct cpu *cpu = CPU;
1259843e1988Sjohnlev 	volatile shared_info_t *si = HYPERVISOR_shared_info;
1260843e1988Sjohnlev 	volatile vcpu_info_t *vci = cpu->cpu_m.mcpu_vcpu_info;
1261843e1988Sjohnlev 	volatile struct xen_evt_data *cpe = cpu->cpu_m.mcpu_evt_pend;
1262843e1988Sjohnlev 	volatile uint16_t *cpu_ipp = &cpu->cpu_m.mcpu_intr_pending;
1263349b53ddSStuart Maybee 	extern void dosoftint(struct regs *);
1264843e1988Sjohnlev 
1265843e1988Sjohnlev 	ASSERT(rp->r_trapno == T_AST && rp->r_err == 0);
1266843e1988Sjohnlev 	ASSERT(&si->vcpu_info[cpu->cpu_id] == vci);
1267843e1988Sjohnlev 	ASSERT_STACK_ALIGNED();
1268843e1988Sjohnlev 
1269843e1988Sjohnlev 	vci->evtchn_upcall_pending = 0;
1270843e1988Sjohnlev 
1271843e1988Sjohnlev 	/*
1272843e1988Sjohnlev 	 * To expedite scanning of pending notifications, any 0->1
1273843e1988Sjohnlev 	 * pending transition on an unmasked channel causes a
1274843e1988Sjohnlev 	 * corresponding bit in evtchn_pending_sel to be set.
1275843e1988Sjohnlev 	 * Each bit in the selector covers a 32-bit word in
1276843e1988Sjohnlev 	 * the evtchn_pending[] array.
1277843e1988Sjohnlev 	 */
1278843e1988Sjohnlev 	membar_enter();
1279843e1988Sjohnlev 	do {
1280843e1988Sjohnlev 		pending_sels = vci->evtchn_pending_sel;
1281843e1988Sjohnlev 	} while (atomic_cas_ulong((volatile ulong_t *)&vci->evtchn_pending_sel,
1282843e1988Sjohnlev 	    pending_sels, 0) != pending_sels);
1283843e1988Sjohnlev 
1284843e1988Sjohnlev 	pending_ints = *cpu_ipp;
1285843e1988Sjohnlev 	while ((i = ffs(pending_sels)) != 0) {
1286843e1988Sjohnlev 		i--;
1287843e1988Sjohnlev 		selbit = 1ul << i;
1288843e1988Sjohnlev 		pending_sels &= ~selbit;
1289843e1988Sjohnlev 
1290843e1988Sjohnlev 		membar_enter();
1291843e1988Sjohnlev 		while ((pe = UNBLOCKED_EVENTS(si, i, cpe, cpu->cpu_id)) != 0) {
1292843e1988Sjohnlev 			j = ffs(pe) - 1;
1293843e1988Sjohnlev 			pe &= ~(1ul << j);
1294843e1988Sjohnlev 
1295843e1988Sjohnlev 			port = (i << EVTCHN_SHIFT) + j;
1296843e1988Sjohnlev 
1297843e1988Sjohnlev 			irq = evtchn_to_irq[port];
1298843e1988Sjohnlev 
1299843e1988Sjohnlev 			/*
1300843e1988Sjohnlev 			 * If no irq set, just ignore the event.
1301843e1988Sjohnlev 			 * On e.g. netbsd they call evtchn_device_upcall(port)
1302843e1988Sjohnlev 			 * We require the evtchn driver to install a handler
1303843e1988Sjohnlev 			 * so there will be an irq associated with user mode
1304843e1988Sjohnlev 			 * evtchns.
1305843e1988Sjohnlev 			 */
1306843e1988Sjohnlev 			if (irq == INVALID_IRQ) {
1307843e1988Sjohnlev 				ec_clear_evtchn(port);
1308843e1988Sjohnlev 				continue;
1309843e1988Sjohnlev 			}
1310843e1988Sjohnlev 
1311843e1988Sjohnlev 			/*
1312843e1988Sjohnlev 			 * If there's no handler, it could be a poke, so just
1313843e1988Sjohnlev 			 * accept the event and continue.
1314843e1988Sjohnlev 			 */
1315843e1988Sjohnlev 			if (!irq_info[irq].ii_u2.has_handler) {
1316843e1988Sjohnlev #ifdef TRAPTRACE
1317843e1988Sjohnlev 				ttp->ttr_ipl = 0xff;
1318843e1988Sjohnlev 				if (IRQ_IS_CPUPOKE(irq)) {
1319843e1988Sjohnlev 					ttp->ttr_ipl = XC_CPUPOKE_PIL;
1320843e1988Sjohnlev 					ttp->ttr_marker = TT_INTERRUPT;
1321843e1988Sjohnlev 				}
1322843e1988Sjohnlev 				ttp->ttr_pri = cpu->cpu_pri;
1323843e1988Sjohnlev 				ttp->ttr_spl = cpu->cpu_base_spl;
1324843e1988Sjohnlev 				ttp->ttr_vector = 0xff;
1325843e1988Sjohnlev #endif /* TRAPTRACE */
1326843e1988Sjohnlev 				if (ec_mask_evtchn(port)) {
1327843e1988Sjohnlev 					ec_clear_evtchn(port);
1328843e1988Sjohnlev 					ec_unmask_evtchn(port);
1329843e1988Sjohnlev 					continue;
1330843e1988Sjohnlev 				}
1331843e1988Sjohnlev 			}
1332843e1988Sjohnlev 
1333843e1988Sjohnlev 			pri = irq_info[irq].ii_u2.ipl;
1334843e1988Sjohnlev 
1335843e1988Sjohnlev 			/*
1336843e1988Sjohnlev 			 * If we are the cpu that successfully masks
1337843e1988Sjohnlev 			 * the event, then record it as a pending event
1338843e1988Sjohnlev 			 * for this cpu to service
1339843e1988Sjohnlev 			 */
1340843e1988Sjohnlev 			if (ec_mask_evtchn(port)) {
1341843e1988Sjohnlev 				if (ec_evtchn_pending(port)) {
1342843e1988Sjohnlev 					cpe->pending_sel[pri] |= selbit;
1343843e1988Sjohnlev 					cpe->pending_evts[pri][i] |= (1ul << j);
1344843e1988Sjohnlev 					pending_ints |= 1 << pri;
1345349b53ddSStuart Maybee 					/*
1346349b53ddSStuart Maybee 					 * We have recorded a pending interrupt
1347349b53ddSStuart Maybee 					 * for this cpu.  If it is an edge
1348349b53ddSStuart Maybee 					 * triggered interrupt then we go ahead
1349349b53ddSStuart Maybee 					 * and clear the pending and mask bits
1350349b53ddSStuart Maybee 					 * from the shared info to avoid having
1351349b53ddSStuart Maybee 					 * the hypervisor see the pending event
1352349b53ddSStuart Maybee 					 * again and possibly disabling the
1353349b53ddSStuart Maybee 					 * interrupt.  This should also help
1354349b53ddSStuart Maybee 					 * keep us from missing an interrupt.
1355349b53ddSStuart Maybee 					 */
1356349b53ddSStuart Maybee 					if (ec_is_edge_pirq(irq)) {
1357349b53ddSStuart Maybee 						ec_clear_evtchn(port);
1358349b53ddSStuart Maybee 						ec_unmask_evtchn(port);
1359349b53ddSStuart Maybee 					}
1360843e1988Sjohnlev 				} else {
1361843e1988Sjohnlev 					/*
1362843e1988Sjohnlev 					 * another cpu serviced this event
1363843e1988Sjohnlev 					 * before us, clear the mask.
1364843e1988Sjohnlev 					 */
1365843e1988Sjohnlev 					ec_unmask_evtchn(port);
1366843e1988Sjohnlev 				}
1367843e1988Sjohnlev 			}
1368843e1988Sjohnlev 		}
1369843e1988Sjohnlev 	}
1370843e1988Sjohnlev 	*cpu_ipp = pending_ints;
1371843e1988Sjohnlev 	if (pending_ints == 0)
1372843e1988Sjohnlev 		return;
1373843e1988Sjohnlev 	/*
1374843e1988Sjohnlev 	 * We have gathered all the pending events/interrupts,
1375843e1988Sjohnlev 	 * go service all the ones we can from highest priority to lowest.
1376843e1988Sjohnlev 	 * Note: This loop may not actually complete and service all
1377843e1988Sjohnlev 	 * pending interrupts since one of the interrupt threads may
1378843e1988Sjohnlev 	 * block and the pinned thread runs.  In that case, when we
1379843e1988Sjohnlev 	 * exit the interrupt thread that blocked we will check for
1380843e1988Sjohnlev 	 * any unserviced interrupts and re-post an upcall to process
1381843e1988Sjohnlev 	 * any unserviced pending events.
1382843e1988Sjohnlev 	 */
1383349b53ddSStuart Maybee restart:
1384843e1988Sjohnlev 	curpri = cpu->cpu_pri;
1385349b53ddSStuart Maybee 	pri = bsrw_insn(*cpu_ipp);
1386349b53ddSStuart Maybee 	while (pri > curpri) {
1387843e1988Sjohnlev 		while ((pending_sels = cpe->pending_sel[pri]) != 0) {
1388843e1988Sjohnlev 			i = ffs(pending_sels) - 1;
1389843e1988Sjohnlev 			while ((pe = cpe->pending_evts[pri][i]) != 0) {
1390843e1988Sjohnlev 				j = ffs(pe) - 1;
1391349b53ddSStuart Maybee 				port = (i << EVTCHN_SHIFT) + j;
1392843e1988Sjohnlev 				pe &= ~(1ul << j);
1393843e1988Sjohnlev 				cpe->pending_evts[pri][i] = pe;
1394843e1988Sjohnlev 				if (pe == 0) {
1395843e1988Sjohnlev 					/*
1396843e1988Sjohnlev 					 * Must reload pending selector bits
1397843e1988Sjohnlev 					 * here as they could have changed on
1398843e1988Sjohnlev 					 * a previous trip around the inner loop
1399843e1988Sjohnlev 					 * while we were interrupt enabled
1400843e1988Sjohnlev 					 * in a interrupt service routine.
1401843e1988Sjohnlev 					 */
1402843e1988Sjohnlev 					pending_sels = cpe->pending_sel[pri];
1403843e1988Sjohnlev 					pending_sels &= ~(1ul << i);
1404843e1988Sjohnlev 					cpe->pending_sel[pri] = pending_sels;
1405843e1988Sjohnlev 					if (pending_sels == 0)
1406843e1988Sjohnlev 						*cpu_ipp &= ~(1 << pri);
1407843e1988Sjohnlev 				}
1408843e1988Sjohnlev 				irq = evtchn_to_irq[port];
1409843e1988Sjohnlev 				if (irq == INVALID_IRQ) {
1410843e1988Sjohnlev 					/*
1411843e1988Sjohnlev 					 * No longer a handler for this event
1412843e1988Sjohnlev 					 * channel.  Clear the event and
1413843e1988Sjohnlev 					 * ignore it, unmask the event.
1414843e1988Sjohnlev 					 */
1415843e1988Sjohnlev 					ec_clear_evtchn(port);
1416843e1988Sjohnlev 					ec_unmask_evtchn(port);
1417843e1988Sjohnlev 					continue;
1418843e1988Sjohnlev 				}
1419843e1988Sjohnlev 				if (irq == ec_dev_irq) {
1420349b53ddSStuart Maybee 					ASSERT(cpu->cpu_m.mcpu_ec_mbox == 0);
1421349b53ddSStuart Maybee 					cpu->cpu_m.mcpu_ec_mbox = port;
1422843e1988Sjohnlev 				}
1423843e1988Sjohnlev 				/*
1424843e1988Sjohnlev 				 * Set up the regs struct to
1425843e1988Sjohnlev 				 * look like a normal hardware int
1426843e1988Sjohnlev 				 * and do normal interrupt handling.
1427843e1988Sjohnlev 				 */
1428843e1988Sjohnlev 				rp->r_trapno = irq;
1429843e1988Sjohnlev 				do_interrupt(rp, ttp);
1430843e1988Sjohnlev 				/*
1431843e1988Sjohnlev 				 * Check for cpu priority change
1432843e1988Sjohnlev 				 * Can happen if int thread blocks
1433843e1988Sjohnlev 				 */
1434349b53ddSStuart Maybee 				if (cpu->cpu_pri != curpri)
1435349b53ddSStuart Maybee 					goto restart;
1436843e1988Sjohnlev 			}
1437843e1988Sjohnlev 		}
1438349b53ddSStuart Maybee 		/*
1439349b53ddSStuart Maybee 		 * Dispatch any soft interrupts that are
1440349b53ddSStuart Maybee 		 * higher priority than any hard ones remaining.
1441349b53ddSStuart Maybee 		 */
1442349b53ddSStuart Maybee 		pri = bsrw_insn(*cpu_ipp);
1443349b53ddSStuart Maybee 		sip = (uint16_t)cpu->cpu_softinfo.st_pending;
1444349b53ddSStuart Maybee 		if (sip != 0) {
1445349b53ddSStuart Maybee 			sipri = bsrw_insn(sip);
14460bc46f0dSStuart Maybee 			if (sipri > pri && sipri > cpu->cpu_pri) {
1447349b53ddSStuart Maybee 				dosoftint(rp);
14480bc46f0dSStuart Maybee 				/*
14490bc46f0dSStuart Maybee 				 * Check for cpu priority change
14500bc46f0dSStuart Maybee 				 * Can happen if softint thread blocks
14510bc46f0dSStuart Maybee 				 */
14520bc46f0dSStuart Maybee 				if (cpu->cpu_pri != curpri)
14530bc46f0dSStuart Maybee 					goto restart;
14540bc46f0dSStuart Maybee 			}
1455349b53ddSStuart Maybee 		}
1456843e1988Sjohnlev 	}
1457349b53ddSStuart Maybee 	/*
1458349b53ddSStuart Maybee 	 * Deliver any pending soft interrupts.
1459349b53ddSStuart Maybee 	 */
1460349b53ddSStuart Maybee 	if (cpu->cpu_softinfo.st_pending)
1461349b53ddSStuart Maybee 		dosoftint(rp);
1462843e1988Sjohnlev }
1463843e1988Sjohnlev 
1464349b53ddSStuart Maybee 
1465843e1988Sjohnlev void
ec_unmask_evtchn(unsigned int ev)1466843e1988Sjohnlev ec_unmask_evtchn(unsigned int ev)
1467843e1988Sjohnlev {
1468349b53ddSStuart Maybee 	uint_t evi, evb;
1469843e1988Sjohnlev 	volatile shared_info_t *si = HYPERVISOR_shared_info;
1470843e1988Sjohnlev 	volatile vcpu_info_t *vci = CPU->cpu_m.mcpu_vcpu_info;
1471843e1988Sjohnlev 	volatile ulong_t *ulp;
1472843e1988Sjohnlev 
1473843e1988Sjohnlev 	ASSERT(!interrupts_enabled());
1474843e1988Sjohnlev 	/*
1475843e1988Sjohnlev 	 * Check if we need to take slow path
1476843e1988Sjohnlev 	 */
1477843e1988Sjohnlev 	if (!CPU_IN_SET(evtchn_cpus[ev], CPU->cpu_id)) {
1478843e1988Sjohnlev 		xen_evtchn_unmask(ev);
1479843e1988Sjohnlev 		return;
1480843e1988Sjohnlev 	}
1481843e1988Sjohnlev 	evi = ev >> EVTCHN_SHIFT;
1482349b53ddSStuart Maybee 	evb = ev & ((1ul << EVTCHN_SHIFT) - 1);
1483843e1988Sjohnlev 	ulp = (volatile ulong_t *)&si->evtchn_mask[evi];
1484349b53ddSStuart Maybee 	atomic_and_ulong(ulp, ~(1ul << evb));
1485843e1988Sjohnlev 	/*
1486843e1988Sjohnlev 	 * The following is basically the equivalent of
1487843e1988Sjohnlev 	 * 'hw_resend_irq'. Just like a real IO-APIC we 'lose the
1488843e1988Sjohnlev 	 * interrupt edge' if the channel is masked.
1489843e1988Sjohnlev 	 * XXPV - slight race if upcall was about to be set, we may get
1490843e1988Sjohnlev 	 * an extra upcall.
1491843e1988Sjohnlev 	 */
1492843e1988Sjohnlev 	membar_enter();
1493349b53ddSStuart Maybee 	if (si->evtchn_pending[evi] & (1ul << evb)) {
1494843e1988Sjohnlev 		membar_consumer();
1495843e1988Sjohnlev 		ulp = (volatile ulong_t *)&vci->evtchn_pending_sel;
1496843e1988Sjohnlev 		if (!(*ulp & (1ul << evi))) {
1497843e1988Sjohnlev 			atomic_or_ulong(ulp, (1ul << evi));
1498843e1988Sjohnlev 		}
1499843e1988Sjohnlev 		vci->evtchn_upcall_pending = 1;
1500843e1988Sjohnlev 	}
1501843e1988Sjohnlev }
1502843e1988Sjohnlev 
1503843e1988Sjohnlev /*
1504843e1988Sjohnlev  * Set a bit in an evtchan mask word, return true if we are the cpu that
1505843e1988Sjohnlev  * set the bit.
1506843e1988Sjohnlev  */
1507843e1988Sjohnlev int
ec_mask_evtchn(unsigned int ev)1508843e1988Sjohnlev ec_mask_evtchn(unsigned int ev)
1509843e1988Sjohnlev {
1510843e1988Sjohnlev 	uint_t evi, evb;
1511843e1988Sjohnlev 	ulong_t new, old, bit;
1512843e1988Sjohnlev 	volatile shared_info_t *si = HYPERVISOR_shared_info;
1513843e1988Sjohnlev 	volatile ulong_t *maskp;
1514843e1988Sjohnlev 	int masked;
1515843e1988Sjohnlev 
1516843e1988Sjohnlev 	kpreempt_disable();
1517843e1988Sjohnlev 	evi = ev >> EVTCHN_SHIFT;
1518843e1988Sjohnlev 	evb = ev & ((1ul << EVTCHN_SHIFT) - 1);
1519843e1988Sjohnlev 	bit = 1ul << evb;
1520843e1988Sjohnlev 	maskp = (volatile ulong_t *)&si->evtchn_mask[evi];
1521843e1988Sjohnlev 	do {
1522843e1988Sjohnlev 		old = si->evtchn_mask[evi];
1523843e1988Sjohnlev 		new = old | bit;
1524843e1988Sjohnlev 	} while (atomic_cas_ulong(maskp, old, new) != old);
1525843e1988Sjohnlev 	masked = (old & bit) == 0;
1526843e1988Sjohnlev 	if (masked) {
1527843e1988Sjohnlev 		evtchn_owner[ev] = CPU->cpu_id;
1528843e1988Sjohnlev #ifdef DEBUG
1529843e1988Sjohnlev 		evtchn_owner_thread[ev] = curthread;
1530843e1988Sjohnlev #endif
1531843e1988Sjohnlev 	}
1532843e1988Sjohnlev 	kpreempt_enable();
1533843e1988Sjohnlev 	return (masked);
1534843e1988Sjohnlev }
1535843e1988Sjohnlev 
1536843e1988Sjohnlev void
ec_clear_evtchn(unsigned int ev)1537843e1988Sjohnlev ec_clear_evtchn(unsigned int ev)
1538843e1988Sjohnlev {
1539843e1988Sjohnlev 	uint_t evi;
1540843e1988Sjohnlev 	shared_info_t *si = HYPERVISOR_shared_info;
1541843e1988Sjohnlev 	volatile ulong_t *pendp;
1542843e1988Sjohnlev 
1543843e1988Sjohnlev 	evi = ev >> EVTCHN_SHIFT;
1544843e1988Sjohnlev 	ev &= (1ul << EVTCHN_SHIFT) - 1;
1545843e1988Sjohnlev 	pendp = (volatile ulong_t *)&si->evtchn_pending[evi];
1546843e1988Sjohnlev 	atomic_and_ulong(pendp, ~(1ul << ev));
1547843e1988Sjohnlev }
1548843e1988Sjohnlev 
1549843e1988Sjohnlev void
ec_notify_via_evtchn(unsigned int port)1550843e1988Sjohnlev ec_notify_via_evtchn(unsigned int port)
1551843e1988Sjohnlev {
1552843e1988Sjohnlev 	evtchn_send_t send;
1553843e1988Sjohnlev 
1554843e1988Sjohnlev 	ASSERT(port != INVALID_EVTCHN);
1555843e1988Sjohnlev 
1556843e1988Sjohnlev 	send.port = port;
1557843e1988Sjohnlev 	(void) HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
1558843e1988Sjohnlev }
1559843e1988Sjohnlev 
1560843e1988Sjohnlev int
ec_block_irq(int irq)1561843e1988Sjohnlev ec_block_irq(int irq)
1562843e1988Sjohnlev {
1563843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
1564843e1988Sjohnlev 	int evtchn;
1565843e1988Sjohnlev 
1566843e1988Sjohnlev 
1567843e1988Sjohnlev 	evtchn = irq_evtchn(irqp);
1568843e1988Sjohnlev 	(void) ec_mask_evtchn(evtchn);
1569843e1988Sjohnlev 	return (evtchn_owner[evtchn]);
1570843e1988Sjohnlev }
1571843e1988Sjohnlev 
1572843e1988Sjohnlev /*
1573843e1988Sjohnlev  * Make a event that is pending for delivery on the current cpu  "go away"
1574843e1988Sjohnlev  * without servicing the interrupt.
1575843e1988Sjohnlev  */
1576843e1988Sjohnlev void
ec_unpend_irq(int irq)1577843e1988Sjohnlev ec_unpend_irq(int irq)
1578843e1988Sjohnlev {
1579843e1988Sjohnlev 	irq_info_t *irqp = &irq_info[irq];
1580843e1988Sjohnlev 	int pri = irqp->ii_u2.ipl;
1581843e1988Sjohnlev 	ulong_t flags;
1582843e1988Sjohnlev 	uint_t evtchn, evi, bit;
1583843e1988Sjohnlev 	unsigned long pe, pending_sels;
1584843e1988Sjohnlev 	struct xen_evt_data *cpe;
1585843e1988Sjohnlev 
1586843e1988Sjohnlev 	/*
1587843e1988Sjohnlev 	 * The evtchn must be masked
1588843e1988Sjohnlev 	 */
1589843e1988Sjohnlev 	evtchn = irq_evtchn(irqp);
1590843e1988Sjohnlev 	ASSERT(EVTCHN_MASKED(evtchn));
1591843e1988Sjohnlev 	evi = evtchn >> EVTCHN_SHIFT;
1592843e1988Sjohnlev 	bit = evtchn & (1ul << EVTCHN_SHIFT) - 1;
1593843e1988Sjohnlev 	flags = intr_clear();
1594843e1988Sjohnlev 	cpe = CPU->cpu_m.mcpu_evt_pend;
1595843e1988Sjohnlev 	pe = cpe->pending_evts[pri][evi] & ~(1ul << bit);
1596843e1988Sjohnlev 	cpe->pending_evts[pri][evi] = pe;
1597843e1988Sjohnlev 	if (pe == 0) {
1598843e1988Sjohnlev 		pending_sels = cpe->pending_sel[pri];
1599843e1988Sjohnlev 		pending_sels &= ~(1ul << evi);
1600843e1988Sjohnlev 		cpe->pending_sel[pri] = pending_sels;
1601843e1988Sjohnlev 		if (pending_sels == 0)
1602843e1988Sjohnlev 			CPU->cpu_m.mcpu_intr_pending &= ~(1 << pri);
1603843e1988Sjohnlev 	}
1604843e1988Sjohnlev 	intr_restore(flags);
1605843e1988Sjohnlev }
1606