xen_intr.c revision 1.10 1 1.10 cherry /* $NetBSD: xen_intr.c,v 1.10 2018/12/24 14:55:42 cherry Exp $ */
2 1.2 bouyer
3 1.2 bouyer /*-
4 1.2 bouyer * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
5 1.2 bouyer * All rights reserved.
6 1.2 bouyer *
7 1.2 bouyer * This code is derived from software contributed to The NetBSD Foundation
8 1.2 bouyer * by Charles M. Hannum, and by Jason R. Thorpe.
9 1.2 bouyer *
10 1.2 bouyer * Redistribution and use in source and binary forms, with or without
11 1.2 bouyer * modification, are permitted provided that the following conditions
12 1.2 bouyer * are met:
13 1.2 bouyer * 1. Redistributions of source code must retain the above copyright
14 1.2 bouyer * notice, this list of conditions and the following disclaimer.
15 1.2 bouyer * 2. Redistributions in binary form must reproduce the above copyright
16 1.2 bouyer * notice, this list of conditions and the following disclaimer in the
17 1.2 bouyer * documentation and/or other materials provided with the distribution.
18 1.2 bouyer *
19 1.2 bouyer * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.2 bouyer * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.2 bouyer * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.2 bouyer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.2 bouyer * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.2 bouyer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.2 bouyer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.2 bouyer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.2 bouyer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.2 bouyer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.2 bouyer * POSSIBILITY OF SUCH DAMAGE.
30 1.2 bouyer */
31 1.2 bouyer
32 1.2 bouyer #include <sys/cdefs.h>
33 1.10 cherry __KERNEL_RCSID(0, "$NetBSD: xen_intr.c,v 1.10 2018/12/24 14:55:42 cherry Exp $");
34 1.2 bouyer
35 1.2 bouyer #include <sys/param.h>
36 1.10 cherry #include <sys/kernel.h>
37 1.10 cherry #include <sys/kmem.h>
38 1.10 cherry
39 1.10 cherry #include <xen/evtchn.h>
40 1.2 bouyer
41 1.2 bouyer #include <machine/cpu.h>
42 1.2 bouyer #include <machine/intr.h>
43 1.2 bouyer
44 1.2 bouyer /*
45 1.2 bouyer * Add a mask to cpl, and return the old value of cpl.
46 1.2 bouyer */
47 1.2 bouyer int
48 1.2 bouyer splraise(int nlevel)
49 1.2 bouyer {
50 1.2 bouyer int olevel;
51 1.2 bouyer struct cpu_info *ci = curcpu();
52 1.2 bouyer
53 1.2 bouyer olevel = ci->ci_ilevel;
54 1.2 bouyer if (nlevel > olevel)
55 1.2 bouyer ci->ci_ilevel = nlevel;
56 1.2 bouyer __insn_barrier();
57 1.2 bouyer return (olevel);
58 1.2 bouyer }
59 1.2 bouyer
60 1.2 bouyer /*
61 1.2 bouyer * Restore a value to cpl (unmasking interrupts). If any unmasked
62 1.2 bouyer * interrupts are pending, call Xspllower() to process them.
63 1.2 bouyer */
64 1.2 bouyer void
65 1.2 bouyer spllower(int nlevel)
66 1.2 bouyer {
67 1.2 bouyer struct cpu_info *ci = curcpu();
68 1.3 cegger uint32_t imask;
69 1.2 bouyer u_long psl;
70 1.2 bouyer
71 1.8 bouyer if (ci->ci_ilevel <= nlevel)
72 1.8 bouyer return;
73 1.8 bouyer
74 1.2 bouyer __insn_barrier();
75 1.2 bouyer
76 1.2 bouyer imask = IUNMASK(ci, nlevel);
77 1.2 bouyer psl = x86_read_psl();
78 1.2 bouyer x86_disable_intr();
79 1.2 bouyer if (ci->ci_ipending & imask) {
80 1.7 bouyer KASSERT(psl == 0);
81 1.2 bouyer Xspllower(nlevel);
82 1.2 bouyer /* Xspllower does enable_intr() */
83 1.2 bouyer } else {
84 1.2 bouyer ci->ci_ilevel = nlevel;
85 1.2 bouyer x86_write_psl(psl);
86 1.2 bouyer }
87 1.2 bouyer }
88 1.2 bouyer
89 1.2 bouyer void
90 1.2 bouyer x86_disable_intr(void)
91 1.2 bouyer {
92 1.2 bouyer __cli();
93 1.2 bouyer }
94 1.2 bouyer
95 1.2 bouyer void
96 1.2 bouyer x86_enable_intr(void)
97 1.2 bouyer {
98 1.2 bouyer __sti();
99 1.2 bouyer }
100 1.2 bouyer
101 1.2 bouyer u_long
102 1.2 bouyer x86_read_psl(void)
103 1.2 bouyer {
104 1.2 bouyer
105 1.4 cegger return (curcpu()->ci_vcpu->evtchn_upcall_mask);
106 1.2 bouyer }
107 1.2 bouyer
108 1.2 bouyer void
109 1.2 bouyer x86_write_psl(u_long psl)
110 1.2 bouyer {
111 1.4 cegger struct cpu_info *ci = curcpu();
112 1.2 bouyer
113 1.4 cegger ci->ci_vcpu->evtchn_upcall_mask = psl;
114 1.9 jym xen_rmb();
115 1.4 cegger if (ci->ci_vcpu->evtchn_upcall_pending && psl == 0) {
116 1.2 bouyer hypervisor_force_callback();
117 1.2 bouyer }
118 1.2 bouyer }
119 1.10 cherry
120 1.10 cherry void *
121 1.10 cherry xen_intr_establish(int legacy_irq, struct pic *pic, int pin,
122 1.10 cherry int type, int level, int (*handler)(void *), void *arg,
123 1.10 cherry bool known_mpsafe)
124 1.10 cherry {
125 1.10 cherry
126 1.10 cherry return xen_intr_establish_xname(legacy_irq, pic, pin, type, level,
127 1.10 cherry handler, arg, known_mpsafe, "XEN");
128 1.10 cherry }
129 1.10 cherry
130 1.10 cherry void *
131 1.10 cherry xen_intr_establish_xname(int legacy_irq, struct pic *pic, int pin,
132 1.10 cherry int type, int level, int (*handler)(void *), void *arg,
133 1.10 cherry bool known_mpsafe, const char *xname)
134 1.10 cherry {
135 1.10 cherry const char *intrstr;
136 1.10 cherry char intrstr_buf[INTRIDBUF];
137 1.10 cherry
138 1.10 cherry if (pic->pic_type == PIC_XEN) {
139 1.10 cherry struct intrhand *rih;
140 1.10 cherry
141 1.10 cherry /*
142 1.10 cherry * event_set_handler interprets `level != IPL_VM' to
143 1.10 cherry * mean MP-safe, so we require the caller to match that
144 1.10 cherry * for the moment.
145 1.10 cherry */
146 1.10 cherry KASSERT(known_mpsafe == (level != IPL_VM));
147 1.10 cherry
148 1.10 cherry intrstr = intr_create_intrid(legacy_irq, pic, pin, intrstr_buf,
149 1.10 cherry sizeof(intrstr_buf));
150 1.10 cherry
151 1.10 cherry event_set_handler(pin, handler, arg, level, intrstr, xname);
152 1.10 cherry
153 1.10 cherry rih = kmem_zalloc(sizeof(*rih), cold ? KM_NOSLEEP : KM_SLEEP);
154 1.10 cherry if (rih == NULL) {
155 1.10 cherry printf("%s: can't allocate handler info\n", __func__);
156 1.10 cherry return NULL;
157 1.10 cherry }
158 1.10 cherry
159 1.10 cherry /*
160 1.10 cherry * XXX:
161 1.10 cherry * This is just a copy for API conformance.
162 1.10 cherry * The real ih is lost in the innards of
163 1.10 cherry * event_set_handler(); where the details of
164 1.10 cherry * biglock_wrapper etc are taken care of.
165 1.10 cherry * All that goes away when we nuke event_set_handler()
166 1.10 cherry * et. al. and unify with x86/intr.c
167 1.10 cherry */
168 1.10 cherry rih->ih_pin = pin; /* port */
169 1.10 cherry rih->ih_fun = rih->ih_realfun = handler;
170 1.10 cherry rih->ih_arg = rih->ih_realarg = arg;
171 1.10 cherry rih->pic_type = pic->pic_type;
172 1.10 cherry return rih;
173 1.10 cherry } /* Else we assume pintr */
174 1.10 cherry
175 1.10 cherry #if NPCI > 0 || NISA > 0
176 1.10 cherry struct pintrhand *pih;
177 1.10 cherry int gsi;
178 1.10 cherry int vector, evtchn;
179 1.10 cherry
180 1.10 cherry KASSERTMSG(legacy_irq == -1 || (0 <= legacy_irq && legacy_irq < NUM_XEN_IRQS),
181 1.10 cherry "bad legacy IRQ value: %d", legacy_irq);
182 1.10 cherry KASSERTMSG(!(legacy_irq == -1 && pic == &i8259_pic),
183 1.10 cherry "non-legacy IRQon i8259 ");
184 1.10 cherry
185 1.10 cherry gsi = xen_pic_to_gsi(pic, pin);
186 1.10 cherry
187 1.10 cherry intrstr = intr_create_intrid(gsi, pic, pin, intrstr_buf,
188 1.10 cherry sizeof(intrstr_buf));
189 1.10 cherry
190 1.10 cherry vector = xen_vec_alloc(gsi);
191 1.10 cherry
192 1.10 cherry if (irq2port[gsi] == 0) {
193 1.10 cherry extern struct cpu_info phycpu_info_primary; /* XXX */
194 1.10 cherry struct cpu_info *ci = &phycpu_info_primary;
195 1.10 cherry
196 1.10 cherry pic->pic_addroute(pic, ci, pin, vector, type);
197 1.10 cherry
198 1.10 cherry evtchn = bind_pirq_to_evtch(gsi);
199 1.10 cherry KASSERT(evtchn > 0);
200 1.10 cherry KASSERT(evtchn < NR_EVENT_CHANNELS);
201 1.10 cherry irq2port[gsi] = evtchn + 1;
202 1.10 cherry xen_atomic_set_bit(&ci->ci_evtmask[0], evtchn);
203 1.10 cherry } else {
204 1.10 cherry /*
205 1.10 cherry * Shared interrupt - we can't rebind.
206 1.10 cherry * The port is shared instead.
207 1.10 cherry */
208 1.10 cherry evtchn = irq2port[gsi] - 1;
209 1.10 cherry }
210 1.10 cherry
211 1.10 cherry pih = pirq_establish(gsi, evtchn, handler, arg, level,
212 1.10 cherry intrstr, xname);
213 1.10 cherry pih->pic_type = pic->pic_type;
214 1.10 cherry return pih;
215 1.10 cherry #endif /* NPCI > 0 || NISA > 0 */
216 1.10 cherry
217 1.10 cherry /* FALLTHROUGH */
218 1.10 cherry return NULL;
219 1.10 cherry }
220 1.10 cherry
221 1.10 cherry /*
222 1.10 cherry * Deregister an interrupt handler.
223 1.10 cherry */
224 1.10 cherry void
225 1.10 cherry xen_intr_disestablish(struct intrhand *ih)
226 1.10 cherry {
227 1.10 cherry
228 1.10 cherry if (ih->pic_type == PIC_XEN) {
229 1.10 cherry event_remove_handler(ih->ih_pin, ih->ih_realfun,
230 1.10 cherry ih->ih_realarg);
231 1.10 cherry kmem_free(ih, sizeof(*ih));
232 1.10 cherry return;
233 1.10 cherry }
234 1.10 cherry #if defined(DOM0OPS)
235 1.10 cherry /*
236 1.10 cherry * Cache state, to prevent a use after free situation with
237 1.10 cherry * ih.
238 1.10 cherry */
239 1.10 cherry
240 1.10 cherry struct pintrhand *pih = (struct pintrhand *)ih;
241 1.10 cherry
242 1.10 cherry int pirq = pih->pirq;
243 1.10 cherry int port = pih->evtch;
244 1.10 cherry KASSERT(irq2port[pirq] != 0);
245 1.10 cherry
246 1.10 cherry pirq_disestablish(pih);
247 1.10 cherry
248 1.10 cherry if (evtsource[port] == NULL) {
249 1.10 cherry /*
250 1.10 cherry * Last handler was removed by
251 1.10 cherry * event_remove_handler().
252 1.10 cherry *
253 1.10 cherry * We can safely unbind the pirq now.
254 1.10 cherry */
255 1.10 cherry
256 1.10 cherry port = unbind_pirq_from_evtch(pirq);
257 1.10 cherry KASSERT(port == pih->evtch);
258 1.10 cherry irq2port[pirq] = 0;
259 1.10 cherry }
260 1.10 cherry #endif
261 1.10 cherry return;
262 1.10 cherry }
263 1.10 cherry
264 1.10 cherry __weak_alias(intr_establish, xen_intr_establish);
265 1.10 cherry __weak_alias(intr_establish_xname, xen_intr_establish_xname);
266 1.10 cherry __weak_alias(intr_disestablish, xen_intr_disestablish);
267