Module Name: src Committed By: cherry Date: Sat Nov 4 10:26:14 UTC 2017
Modified Files: src/sys/arch/x86/include: pic.h src/sys/arch/xen/xen: evtchn.c Log Message: Add a PIC_XEN abstraction to evtchn.c This allows us to get XEN interrupt code closer to unification to x86/intr.c To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/sys/arch/x86/include/pic.h cvs rdiff -u -r1.73 -r1.74 src/sys/arch/xen/xen/evtchn.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/x86/include/pic.h diff -u src/sys/arch/x86/include/pic.h:1.8 src/sys/arch/x86/include/pic.h:1.9 --- src/sys/arch/x86/include/pic.h:1.8 Mon Apr 27 07:03:58 2015 +++ src/sys/arch/x86/include/pic.h Sat Nov 4 10:26:14 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: pic.h,v 1.8 2015/04/27 07:03:58 knakahara Exp $ */ +/* $NetBSD: pic.h,v 1.9 2017/11/04 10:26:14 cherry Exp $ */ #ifndef _X86_PIC_H #define _X86_PIC_H @@ -34,8 +34,10 @@ struct pic { #define PIC_MSI 3 #define PIC_MSIX 4 #define PIC_SOFT 5 +#define PIC_XEN 6 extern struct pic i8259_pic; extern struct pic local_pic; extern struct pic softintr_pic; +extern struct pic xen_pic; #endif Index: src/sys/arch/xen/xen/evtchn.c diff -u src/sys/arch/xen/xen/evtchn.c:1.73 src/sys/arch/xen/xen/evtchn.c:1.74 --- src/sys/arch/xen/xen/evtchn.c:1.73 Sun Jul 16 14:02:48 2017 +++ src/sys/arch/xen/xen/evtchn.c Sat Nov 4 10:26:14 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: evtchn.c,v 1.73 2017/07/16 14:02:48 cherry Exp $ */ +/* $NetBSD: evtchn.c,v 1.74 2017/11/04 10:26:14 cherry Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -54,7 +54,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.73 2017/07/16 14:02:48 cherry Exp $"); +__KERNEL_RCSID(0, "$NetBSD: evtchn.c,v 1.74 2017/11/04 10:26:14 cherry Exp $"); #include "opt_xen.h" #include "isa.h" @@ -115,6 +115,81 @@ physdev_op_t physdev_op_notify = { }; #endif +static void xen_evtchn_mask(struct pic *, int); +static void xen_evtchn_unmask(struct pic *, int); +static void xen_evtchn_addroute(struct pic *, struct cpu_info *, int, int, int); +static void xen_evtchn_delroute(struct pic *, struct cpu_info *, int, int, int); +static bool xen_evtchn_trymask(struct pic *, int); + + +struct pic xen_pic = { + .pic_name = "xenev0", + .pic_type = PIC_XEN, + .pic_vecbase = 0, + .pic_apicid = 0, + .pic_lock = __SIMPLELOCK_UNLOCKED, + .pic_hwmask = xen_evtchn_mask, + .pic_hwunmask = xen_evtchn_unmask, + .pic_addroute = xen_evtchn_addroute, + .pic_delroute = xen_evtchn_delroute, + .pic_trymask = xen_evtchn_trymask, + .pic_level_stubs = xenev_stubs, + .pic_edge_stubs = xenev_stubs, +}; + +/* + * We try to stick to the traditional x86 PIC semantics wrt Xen + * events. + * + * PIC pins exist in a global namespace which may be hierarchical, and + * are mapped to a cpu bus concept called 'IRQ' numbers, which are + * also global, but linear. Thus a PIC, pin tuple will always map to + * an IRQ number. These tuples can alias to the same IRQ number, thus + * causing IRQ "sharing". IRQ numbers can be bound to specific CPUs, + * and to specific callback vector indices on the CPU called idt_vec, + * which are aliases to handlers meant to run on destination + * CPUs. This binding can also happen at interrupt time and resolved + * 'round-robin' between all CPUs, depending on the lapic setup. In + * this case, all CPUs need to have identical idt_vec->handler + * mappings. + * + * The job of pic_addroute() is to setup the 'wiring' between the + * source pin, and the destination CPU handler, ideally on a specific + * CPU in MP systems (or 'round-robin'). + * + * On Xen, a global namespace of 'events' exist, which are initially + * bound to nothing. This is similar to the relationship between + * realworld realworld IRQ numbers wrt PIC pins, since before routing, + * IRQ numbers by themselves have no causal connection setup with the + * real world. (Except for the hardwired cases on the PC Architecture, + * which we ignore for the purpose of this description). However the + * really important routing is from pin to idt_vec. On PIC_XEN, all + * three (pic, irq, idt_vec) belong to the same namespace and are + * identical. Further, the mapping between idt_vec and the actual + * callback handler is setup via calls to the evtchn.h api - this + * last bit is analogous to x86/idt.c:idt_vec_set() on real h/w + * + * For now we handle two cases: + * - IPC style events - eg: timer, PV devices, etc. + * - dom0 physical irq bound events. + * + * In the case of IPC style events, we currently externalise the + * event binding by using evtchn.h functions. From the POV of + * PIC_XEN , 'pin' , 'irq' and 'idt_vec' are all identical to the + * port number of the event. + * + * In the case of dom0 physical irq bound events, we currently + * event binding by exporting evtchn.h functions. From the POV of + * PIC_LAPIC/PIC_IOAPIC, the 'pin' is the hardware pin, the 'irq' is + * the x86 global irq number - the port number is extracted out of a + * global array (this is currently kludgy and breaks API abstraction) + * and the binding happens during pic_addroute() of the ioapic. + * + * Later when we integrate more tightly with x86/intr.c, we will be + * able to conform better to (PIC_LAPIC/PIC_IOAPIC)->PIC_XEN + * cascading model. + */ + int debug_port = -1; // #define IRQ_DEBUG 4 @@ -359,6 +434,96 @@ splx: #define PRIuCPUID "lu" /* XXX: move this somewhere more appropriate */ +/* PIC callbacks */ +/* pic "pin"s are conceptually mapped to event port numbers */ +static void +xen_evtchn_mask(struct pic *pic, int pin) +{ + evtchn_port_t evtchn = pin; + + KASSERT(pic->pic_type == PIC_XEN); + KASSERT(evtchn < NR_EVENT_CHANNELS); + + hypervisor_mask_event(evtchn); + +} + +static void +xen_evtchn_unmask(struct pic *pic, int pin) +{ + evtchn_port_t evtchn = pin; + + KASSERT(pic->pic_type == PIC_XEN); + KASSERT(evtchn < NR_EVENT_CHANNELS); + + hypervisor_unmask_event(evtchn); + +} + + +static void +xen_evtchn_addroute(struct pic *pic, struct cpu_info *ci, int pin, int idt_vec, int type) +{ + + evtchn_port_t evtchn = pin; + + /* Events are simulated as level triggered interrupts */ + KASSERT(type == IST_LEVEL); + + KASSERT(evtchn < NR_EVENT_CHANNELS); +#if notyet + evtchn_port_t boundport = idt_vec; +#endif + + KASSERT(pic->pic_type == PIC_XEN); + + xen_atomic_set_bit(&ci->ci_evtmask[0], evtchn); + +} + +static void +xen_evtchn_delroute(struct pic *pic, struct cpu_info *ci, int pin, int idt_vec, int type) +{ + /* + * XXX: In the future, this is a great place to + * 'unbind' events to underlying events and cpus. + * For now, just disable interrupt servicing on this cpu for + * this pin aka cpu. + */ + evtchn_port_t evtchn = pin; + + /* Events are simulated as level triggered interrupts */ + KASSERT(type == IST_LEVEL); + + KASSERT(evtchn < NR_EVENT_CHANNELS); +#if notyet + evtchn_port_t boundport = idt_vec; +#endif + + KASSERT(pic->pic_type == PIC_XEN); + + xen_atomic_clear_bit(&ci->ci_evtmask[0], evtchn); +} + +static bool +xen_evtchn_trymask(struct pic *pic, int pin) +{ + volatile shared_info_t *s = HYPERVISOR_shared_info; + + /* Already masked! */ + if (xen_atomic_test_bit(&s->evtchn_mask[0], pin)) + return true; + + /* Pending - bail! */ + if (xen_atomic_test_bit(&s->evtchn_pending[0], pin)) + return false; + + /* XXX: There's a race here - anything we can do about this ? */ + /* Mask it */ + xen_atomic_set_bit(&s->evtchn_mask[0], pin); + return true; +} + evtchn_port_t bind_vcpu_to_evtch(cpuid_t vcpu) {