]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/xen/xenpci/evtchn.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / xen / xenpci / evtchn.c
1 /******************************************************************************
2  * evtchn.c
3  *
4  * A simplified event channel for para-drivers in unmodified linux
5  *
6  * Copyright (c) 2002-2005, K A Fraser
7  * Copyright (c) 2005, Intel Corporation <xiaofeng.ling@intel.com>
8  *
9  * This file may be distributed separately from the Linux kernel, or
10  * incorporated into other software packages, subject to the following license:
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy
13  * of this source file (the "Software"), to deal in the Software without
14  * restriction, including without limitation the rights to use, copy, modify,
15  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16  * and to permit persons to whom the Software is furnished to do so, subject to
17  * the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in
20  * all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28  * IN THE SOFTWARE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37 #include <sys/malloc.h>
38 #include <sys/kernel.h>
39 #include <sys/limits.h>
40 #include <sys/lock.h>
41 #include <sys/mutex.h>
42 #include <sys/interrupt.h>
43 #include <sys/pcpu.h>
44
45 #include <machine/xen/xen-os.h>
46 #include <machine/xen/xenvar.h>
47 #include <xen/hypervisor.h>
48 #include <xen/xen_intr.h>
49 #include <xen/evtchn.h>
50 #include <sys/smp.h>
51
52 #include <dev/xen/xenpci/xenpcivar.h>
53
54 #if defined(__i386__)
55 #define __ffs(word)     (ffs(word) - 1)
56 #elif defined(__amd64__)
57 static inline unsigned long __ffs(unsigned long word)
58 {
59         __asm__("bsfq %1,%0"
60                 :"=r" (word)
61                 :"rm" (word));  /* XXXRW: why no "cc"? */
62         return word;
63 }
64 #else
65 #error "evtchn: unsupported architecture"
66 #endif
67
68 #define is_valid_evtchn(x)      ((x) != 0)
69 #define evtchn_from_irq(x)      (irq_evtchn[irq].evtchn)
70
71 static struct {
72         struct mtx lock;
73         driver_intr_t *handler;
74         void *arg;
75         int evtchn;
76         int close:1; /* close on unbind_from_irqhandler()? */
77         int inuse:1;
78         int in_handler:1;
79         int mpsafe:1;
80 } irq_evtchn[256];
81 static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
82         [0 ...  NR_EVENT_CHANNELS-1] = -1 };
83
84 static struct mtx irq_alloc_lock;
85 static device_t xenpci_device;
86
87 #define ARRAY_SIZE(a)   (sizeof(a) / sizeof(a[0]))
88
89 static unsigned int
90 alloc_xen_irq(void)
91 {
92         static int warned;
93         unsigned int irq;
94
95         mtx_lock(&irq_alloc_lock);
96
97         for (irq = 1; irq < ARRAY_SIZE(irq_evtchn); irq++) {
98                 if (irq_evtchn[irq].inuse) 
99                         continue;
100                 irq_evtchn[irq].inuse = 1;
101                 mtx_unlock(&irq_alloc_lock);
102                 return irq;
103         }
104
105         if (!warned) {
106                 warned = 1;
107                 printf("alloc_xen_irq: No available IRQ to bind to: "
108                        "increase irq_evtchn[] size in evtchn.c.\n");
109         }
110
111         mtx_unlock(&irq_alloc_lock);
112
113         return -ENOSPC;
114 }
115
116 static void
117 free_xen_irq(int irq)
118 {
119
120         mtx_lock(&irq_alloc_lock);
121         irq_evtchn[irq].inuse = 0;
122         mtx_unlock(&irq_alloc_lock);
123 }
124
125 int
126 irq_to_evtchn_port(int irq)
127 {
128
129         return irq_evtchn[irq].evtchn;
130 }
131
132 void
133 mask_evtchn(int port)
134 {
135         shared_info_t *s = HYPERVISOR_shared_info;
136
137         synch_set_bit(port, &s->evtchn_mask[0]);
138 }
139
140 void
141 unmask_evtchn(int port)
142 {
143         evtchn_unmask_t op = { .port = port };
144
145         HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &op);
146 }
147
148 int
149 bind_listening_port_to_irqhandler(unsigned int remote_domain,
150     const char *devname, driver_intr_t handler, void *arg,
151     unsigned long irqflags, unsigned int *irqp)
152 {
153         struct evtchn_alloc_unbound alloc_unbound;
154         unsigned int irq;
155         int error;
156
157         irq = alloc_xen_irq();
158         if (irq < 0)
159                 return irq;
160
161         mtx_lock(&irq_evtchn[irq].lock);
162
163         alloc_unbound.dom        = DOMID_SELF;
164         alloc_unbound.remote_dom = remote_domain;
165         error = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
166                                           &alloc_unbound);
167         if (error) {
168                 mtx_unlock(&irq_evtchn[irq].lock);
169                 free_xen_irq(irq);
170                 return (-error);
171         }
172
173         irq_evtchn[irq].handler = handler;
174         irq_evtchn[irq].arg     = arg;
175         irq_evtchn[irq].evtchn  = alloc_unbound.port;
176         irq_evtchn[irq].close   = 1;
177         irq_evtchn[irq].mpsafe  = (irqflags & INTR_MPSAFE) != 0;
178
179         evtchn_to_irq[alloc_unbound.port] = irq;
180
181         unmask_evtchn(alloc_unbound.port);
182
183         mtx_unlock(&irq_evtchn[irq].lock);
184
185         if (irqp)
186                 *irqp = irq;
187         return (0);
188 }
189
190 int 
191 bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
192     unsigned int remote_port, const char *devname, driver_intr_t handler,
193     void *arg, unsigned long irqflags, unsigned int *irqp)
194 {
195         struct evtchn_bind_interdomain bind_interdomain;
196         unsigned int irq;
197         int error;
198
199         irq = alloc_xen_irq();
200         if (irq < 0)
201                 return irq;
202
203         mtx_lock(&irq_evtchn[irq].lock);
204
205         bind_interdomain.remote_dom  = remote_domain;
206         bind_interdomain.remote_port = remote_port;
207         error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
208                                             &bind_interdomain);
209         if (error) {
210                 mtx_unlock(&irq_evtchn[irq].lock);
211                 free_xen_irq(irq);
212                 return (-error);
213         }
214
215         irq_evtchn[irq].handler = handler;
216         irq_evtchn[irq].arg     = arg;
217         irq_evtchn[irq].evtchn  = bind_interdomain.local_port;
218         irq_evtchn[irq].close   = 1;
219         irq_evtchn[irq].mpsafe  = (irqflags & INTR_MPSAFE) != 0;
220
221         evtchn_to_irq[bind_interdomain.local_port] = irq;
222
223         unmask_evtchn(bind_interdomain.local_port);
224
225         mtx_unlock(&irq_evtchn[irq].lock);
226
227         if (irqp)
228                 *irqp = irq;
229         return (0);
230 }
231
232
233 int
234 bind_caller_port_to_irqhandler(unsigned int caller_port,
235     const char *devname, driver_intr_t handler, void *arg,
236     unsigned long irqflags, unsigned int *irqp)
237 {
238         unsigned int irq;
239
240         irq = alloc_xen_irq();
241         if (irq < 0)
242                 return irq;
243
244         mtx_lock(&irq_evtchn[irq].lock);
245
246         irq_evtchn[irq].handler = handler;
247         irq_evtchn[irq].arg     = arg;
248         irq_evtchn[irq].evtchn  = caller_port;
249         irq_evtchn[irq].close   = 0;
250         irq_evtchn[irq].mpsafe  = (irqflags & INTR_MPSAFE) != 0;
251
252         evtchn_to_irq[caller_port] = irq;
253
254         unmask_evtchn(caller_port);
255
256         mtx_unlock(&irq_evtchn[irq].lock);
257
258         if (irqp)
259                 *irqp = irq;
260         return (0);
261 }
262
263 void
264 unbind_from_irqhandler(unsigned int irq)
265 {
266         int evtchn;
267
268         mtx_lock(&irq_evtchn[irq].lock);
269
270         evtchn = evtchn_from_irq(irq);
271
272         if (is_valid_evtchn(evtchn)) {
273                 evtchn_to_irq[evtchn] = -1;
274                 mask_evtchn(evtchn);
275                 if (irq_evtchn[irq].close) {
276                         struct evtchn_close close = { .port = evtchn };
277                         if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
278                                 panic("EVTCHNOP_close failed");
279                 }
280         }
281
282         irq_evtchn[irq].handler = NULL;
283         irq_evtchn[irq].evtchn  = 0;
284
285         mtx_unlock(&irq_evtchn[irq].lock);
286
287         while (irq_evtchn[irq].in_handler)
288                 cpu_relax();
289
290         free_xen_irq(irq);
291 }
292
293 void notify_remote_via_irq(int irq)
294 {
295         int evtchn;
296
297         evtchn = evtchn_from_irq(irq);
298         if (is_valid_evtchn(evtchn))
299                 notify_remote_via_evtchn(evtchn);
300 }
301
302 static inline unsigned long active_evtchns(unsigned int cpu, shared_info_t *sh,
303                                                 unsigned int idx)
304 {
305         return (sh->evtchn_pending[idx] & ~sh->evtchn_mask[idx]);
306 }
307
308 static void
309 evtchn_interrupt(void *arg)
310 {
311         unsigned int l1i, l2i, port;
312         unsigned long masked_l1, masked_l2;
313         /* XXX: All events are bound to vcpu0 but irq may be redirected. */
314         int cpu = 0; /*smp_processor_id();*/
315         driver_intr_t *handler;
316         void *handler_arg;
317         int irq, handler_mpsafe;
318         shared_info_t *s = HYPERVISOR_shared_info;
319         vcpu_info_t *v = &s->vcpu_info[cpu];
320         struct pcpu *pc = pcpu_find(cpu);
321         unsigned long l1, l2;
322
323         v->evtchn_upcall_pending = 0;
324
325 #if 0
326 #ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
327         /* Clear master flag /before/ clearing selector flag. */
328         wmb();
329 #endif
330 #endif
331
332         l1 = atomic_readandclear_long(&v->evtchn_pending_sel);
333
334         l1i = pc->pc_last_processed_l1i;
335         l2i = pc->pc_last_processed_l2i;
336
337         while (l1 != 0) {
338
339                 l1i = (l1i + 1) % LONG_BIT;
340                 masked_l1 = l1 & ((~0UL) << l1i);
341
342                 if (masked_l1 == 0) { /* if we masked out all events, wrap around to the beginning */
343                         l1i = LONG_BIT - 1;
344                         l2i = LONG_BIT - 1;
345                         continue;
346                 }
347                 l1i = __ffs(masked_l1);
348
349                 do {
350                         l2 = active_evtchns(cpu, s, l1i);
351
352                         l2i = (l2i + 1) % LONG_BIT;
353                         masked_l2 = l2 & ((~0UL) << l2i);
354
355                         if (masked_l2 == 0) { /* if we masked out all events, move on */
356                                 l2i = LONG_BIT - 1;
357                                 break;
358                         }
359                         l2i = __ffs(masked_l2);
360
361                         /* process port */
362                         port = (l1i * LONG_BIT) + l2i;
363                         synch_clear_bit(port, &s->evtchn_pending[0]);
364
365                         irq = evtchn_to_irq[port];
366                         if (irq < 0)
367                                 continue;
368
369                         mtx_lock(&irq_evtchn[irq].lock);
370                         handler = irq_evtchn[irq].handler;
371                         handler_arg = irq_evtchn[irq].arg;
372                         handler_mpsafe = irq_evtchn[irq].mpsafe;
373                         if (unlikely(handler == NULL)) {
374                                 printf("Xen IRQ%d (port %d) has no handler!\n",
375                                        irq, port);
376                                 mtx_unlock(&irq_evtchn[irq].lock);
377                                 continue;
378                         }
379                         irq_evtchn[irq].in_handler = 1;
380                         mtx_unlock(&irq_evtchn[irq].lock);
381
382                         //local_irq_enable();
383                         if (!handler_mpsafe)
384                                 mtx_lock(&Giant);
385                         handler(handler_arg);
386                         if (!handler_mpsafe)
387                                 mtx_unlock(&Giant);
388                         //local_irq_disable();
389
390                         mtx_lock(&irq_evtchn[irq].lock);
391                         irq_evtchn[irq].in_handler = 0;
392                         mtx_unlock(&irq_evtchn[irq].lock);
393
394                         /* if this is the final port processed, we'll pick up here+1 next time */
395                         pc->pc_last_processed_l1i = l1i;
396                         pc->pc_last_processed_l2i = l2i;
397
398                 } while (l2i != LONG_BIT - 1);
399
400                 l2 = active_evtchns(cpu, s, l1i);
401                 if (l2 == 0) /* we handled all ports, so we can clear the selector bit */
402                         l1 &= ~(1UL << l1i);
403         }
404 }
405
406 void
407 irq_suspend(void)
408 {
409         struct xenpci_softc *scp = device_get_softc(xenpci_device);
410
411         /*
412          * Take our interrupt handler out of the list of handlers
413          * that can handle this irq.
414          */
415         if (scp->intr_cookie != NULL) {
416                 if (BUS_TEARDOWN_INTR(device_get_parent(xenpci_device),
417                         xenpci_device, scp->res_irq, scp->intr_cookie) != 0)
418                         printf("intr teardown failed.. continuing\n");
419                 scp->intr_cookie = NULL;
420         }
421 }
422
423 void
424 irq_resume(void)
425 {
426         struct xenpci_softc *scp = device_get_softc(xenpci_device);
427         int evtchn, irq;
428
429         for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) {
430                 mask_evtchn(evtchn);
431                 evtchn_to_irq[evtchn] = -1;
432         }
433
434         for (irq = 0; irq < ARRAY_SIZE(irq_evtchn); irq++)
435                 irq_evtchn[irq].evtchn = 0;
436
437         BUS_SETUP_INTR(device_get_parent(xenpci_device),
438             xenpci_device, scp->res_irq, INTR_TYPE_MISC,
439             NULL, evtchn_interrupt, NULL, &scp->intr_cookie);
440 }
441
442 int
443 xenpci_irq_init(device_t device, struct xenpci_softc *scp)
444 {
445         int irq, cpu;
446         int error;
447
448         mtx_init(&irq_alloc_lock, "xen-irq-lock", NULL, MTX_DEF);
449
450         for (irq = 0; irq < ARRAY_SIZE(irq_evtchn); irq++)
451                 mtx_init(&irq_evtchn[irq].lock, "irq-evtchn", NULL, MTX_DEF);
452
453         for (cpu = 0; cpu < mp_ncpus; cpu++) {
454                 pcpu_find(cpu)->pc_last_processed_l1i = LONG_BIT - 1;
455                 pcpu_find(cpu)->pc_last_processed_l2i = LONG_BIT - 1;
456         }
457
458         error = BUS_SETUP_INTR(device_get_parent(device), device,
459             scp->res_irq, INTR_MPSAFE|INTR_TYPE_MISC, NULL, evtchn_interrupt,
460             NULL, &scp->intr_cookie);
461         if (error)
462                 return (error);
463
464         xenpci_device = device;
465
466         return (0);
467 }