Home | History | Annotate | Line # | Download | only in x86
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