diff options
Diffstat (limited to 'sys/xen/evtchn/evtchn.c')
-rw-r--r-- | sys/xen/evtchn/evtchn.c | 93 |
1 files changed, 69 insertions, 24 deletions
diff --git a/sys/xen/evtchn/evtchn.c b/sys/xen/evtchn/evtchn.c index c296664..a782f24 100644 --- a/sys/xen/evtchn/evtchn.c +++ b/sys/xen/evtchn/evtchn.c @@ -18,6 +18,7 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/mutex.h> #include <sys/interrupt.h> +#include <sys/pcpu.h> #include <machine/cpufunc.h> #include <machine/intr_machdep.h> @@ -28,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include <machine/xen/synch_bitops.h> #include <machine/xen/evtchn.h> #include <machine/xen/hypervisor.h> +#include <sys/smp.h> @@ -101,27 +103,58 @@ enum { IRQT_VIRQ, IRQT_IPI, IRQT_LOCAL_PORT, - IRQT_CALLER_PORT + IRQT_CALLER_PORT, + _IRQT_COUNT + }; + +#define _IRQT_BITS 4 +#define _EVTCHN_BITS 12 +#define _INDEX_BITS (32 - _IRQT_BITS - _EVTCHN_BITS) + /* Constructor for packed IRQ information. */ -#define mk_irq_info(type, index, evtchn) \ - (((uint32_t)(type) << 24) | ((uint32_t)(index) << 16) | (uint32_t)(evtchn)) +static inline uint32_t +mk_irq_info(uint32_t type, uint32_t index, uint32_t evtchn) +{ + + return ((type << (32 - _IRQT_BITS)) | (index << _EVTCHN_BITS) | evtchn); +} + +/* Constructor for packed IRQ information. */ + /* Convenient shorthand for packed representation of an unbound IRQ. */ #define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0) -/* Accessor macros for packed IRQ information. */ -#define evtchn_from_irq(irq) ((uint16_t)(irq_info[irq])) -#define index_from_irq(irq) ((uint8_t)(irq_info[irq] >> 16)) -#define type_from_irq(irq) ((uint8_t)(irq_info[irq] >> 24)) + +/* + * Accessors for packed IRQ information. + */ + +static inline unsigned int evtchn_from_irq(int irq) +{ + return irq_info[irq] & ((1U << _EVTCHN_BITS) - 1); +} + +static inline unsigned int index_from_irq(int irq) +{ + return (irq_info[irq] >> _EVTCHN_BITS) & ((1U << _INDEX_BITS) - 1); +} + +static inline unsigned int type_from_irq(int irq) +{ + return irq_info[irq] >> (32 - _IRQT_BITS); +} + /* IRQ <-> VIRQ mapping. */ -DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1}; /* IRQ <-> IPI mapping. */ -#ifndef NR_IPIS +#ifndef NR_IPIS +#ifdef SMP +#error "NR_IPIS not defined" +#endif #define NR_IPIS 1 #endif -DEFINE_PER_CPU(int, ipi_to_irq[NR_IPIS]) = {[0 ... NR_IPIS-1] = -1}; /* Bitmap indicating which PIRQs require Xen to be notified on unmask. */ static unsigned long pirq_needs_unmask_notify[NR_PIRQS/sizeof(unsigned long)]; @@ -131,9 +164,9 @@ static int irq_bindcount[NR_IRQS]; #define VALID_EVTCHN(_chn) ((_chn) != 0) -#ifdef CONFIG_SMP +#ifdef SMP -static u8 cpu_evtchn[NR_EVENT_CHANNELS]; +static uint8_t cpu_evtchn[NR_EVENT_CHANNELS]; static unsigned long cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG]; #define active_evtchns(cpu,sh,idx) \ @@ -224,8 +257,10 @@ evtchn_do_upcall(struct intrframe *frame) void ipi_pcpu(unsigned int cpu, int vector) { - int irq = per_cpu(ipi_to_irq, cpu)[vector]; + int irq; + irq = per_cpu(ipi_to_irq, cpu)[vector]; + notify_remote_via_irq(irq); } @@ -333,6 +368,9 @@ bind_virq_to_irq(unsigned int virq, unsigned int cpu) mtx_lock_spin(&irq_mapping_update_lock); if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) { + if ((irq = find_unbound_irq()) < 0) + goto out; + bind_virq.virq = virq; bind_virq.vcpu = cpu; PANIC_IF(HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, @@ -340,7 +378,6 @@ bind_virq_to_irq(unsigned int virq, unsigned int cpu) evtchn = bind_virq.port; - irq = find_unbound_irq(); evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); @@ -350,13 +387,16 @@ bind_virq_to_irq(unsigned int virq, unsigned int cpu) } irq_bindcount[irq]++; - +out: mtx_unlock_spin(&irq_mapping_update_lock); return irq; } -static int + +extern int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu); + +int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) { struct evtchn_bind_ipi bind_ipi; @@ -372,7 +412,6 @@ bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) PANIC_IF(HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind_ipi) != 0); evtchn = bind_ipi.port; - irq = find_unbound_irq(); evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); @@ -380,7 +419,6 @@ bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) bind_evtchn_to_cpu(evtchn, cpu); } - irq_bindcount[irq]++; out: @@ -518,9 +556,8 @@ bind_ipi_to_irqhandler(unsigned int ipi, driver_intr_t handler, unsigned long irqflags) { - unsigned int irq; - int retval; - + int irq, retval; + irq = bind_ipi_to_irq(ipi, cpu); intr_register_source(&xp->xp_pins[irq].xp_intsrc); retval = intr_add_handler(devname, irq, handler, NULL, irqflags, NULL); @@ -742,6 +779,8 @@ notify_remote_via_irq(int irq) if (VALID_EVTCHN(evtchn)) notify_remote_via_evtchn(evtchn); + else + panic("invalid evtchn"); } /* required for support of physical devices */ @@ -792,6 +831,9 @@ xenpic_pirq_enable_intr(struct intsrc *isrc) bind_pirq.flags = probing_irq(irq) ? 0 : BIND_PIRQ__WILL_SHARE; if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq) != 0) { +#ifndef XEN_PRIVILEGED_GUEST + panic("unexpected pirq call"); +#endif if (!probing_irq(irq)) /* Some failures are expected when probing. */ printf("Failed to obtain physical IRQ %d\n", irq); mtx_unlock_spin(&irq_mapping_update_lock); @@ -992,8 +1034,11 @@ evtchn_init(void *dummy __unused) int i, cpu; struct xenpic_intsrc *pin, *tpin; - /* No VIRQ or IPI bindings. */ - for (cpu = 0; cpu < NR_CPUS; cpu++) { + + init_evtchn_cpu_bindings(); + + /* No VIRQ or IPI bindings. */ + for (cpu = 0; cpu < mp_ncpus; cpu++) { for (i = 0; i < NR_VIRQS; i++) per_cpu(virq_to_irq, cpu)[i] = -1; for (i = 0; i < NR_IPIS; i++) @@ -1060,7 +1105,7 @@ evtchn_init(void *dummy __unused) } } -SYSINIT(evtchn_init, SI_SUB_INTR, SI_ORDER_ANY, evtchn_init, NULL); +SYSINIT(evtchn_init, SI_SUB_INTR, SI_ORDER_MIDDLE, evtchn_init, NULL); /* * irq_mapping_update_lock: in order to allow an interrupt to occur in a critical * section, to set pcpu->ipending (etc...) properly, we |