|
@@ -52,18 +52,8 @@ static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1};
|
|
|
/* IRQ <-> IPI mapping */
|
|
|
static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ... XEN_NR_IPIS-1] = -1};
|
|
|
|
|
|
-/* Packed IRQ information: binding type, sub-type index, and event channel. */
|
|
|
-struct packed_irq
|
|
|
-{
|
|
|
- unsigned short evtchn;
|
|
|
- unsigned char index;
|
|
|
- unsigned char type;
|
|
|
-};
|
|
|
-
|
|
|
-static struct packed_irq irq_info[NR_IRQS];
|
|
|
-
|
|
|
-/* Binding types. */
|
|
|
-enum {
|
|
|
+/* Interrupt types. */
|
|
|
+enum xen_irq_type {
|
|
|
IRQT_UNBOUND,
|
|
|
IRQT_PIRQ,
|
|
|
IRQT_VIRQ,
|
|
@@ -71,8 +61,34 @@ enum {
|
|
|
IRQT_EVTCHN
|
|
|
};
|
|
|
|
|
|
-/* Convenient shorthand for packed representation of an unbound IRQ. */
|
|
|
-#define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0)
|
|
|
+/*
|
|
|
+ * Packed IRQ information:
|
|
|
+ * type - enum xen_irq_type
|
|
|
+ * event channel - irq->event channel mapping
|
|
|
+ * cpu - cpu this event channel is bound to
|
|
|
+ * index - type-specific information:
|
|
|
+ * PIRQ - vector, with MSB being "needs EIO"
|
|
|
+ * VIRQ - virq number
|
|
|
+ * IPI - IPI vector
|
|
|
+ * EVTCHN -
|
|
|
+ */
|
|
|
+struct irq_info
|
|
|
+{
|
|
|
+ enum xen_irq_type type; /* type */
|
|
|
+ unsigned short evtchn; /* event channel */
|
|
|
+ unsigned short cpu; /* cpu bound */
|
|
|
+
|
|
|
+ union {
|
|
|
+ unsigned short virq;
|
|
|
+ enum ipi_vector ipi;
|
|
|
+ struct {
|
|
|
+ unsigned short gsi;
|
|
|
+ unsigned short vector;
|
|
|
+ } pirq;
|
|
|
+ } u;
|
|
|
+};
|
|
|
+
|
|
|
+static struct irq_info irq_info[NR_IRQS];
|
|
|
|
|
|
static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
|
|
|
[0 ... NR_EVENT_CHANNELS-1] = -1
|
|
@@ -85,7 +101,6 @@ static inline unsigned long *cpu_evtchn_mask(int cpu)
|
|
|
{
|
|
|
return cpu_evtchn_mask_p[cpu].bits;
|
|
|
}
|
|
|
-static u8 cpu_evtchn[NR_EVENT_CHANNELS];
|
|
|
|
|
|
/* Reference counts for bindings to IRQs. */
|
|
|
static int irq_bindcount[NR_IRQS];
|
|
@@ -96,27 +111,107 @@ static int irq_bindcount[NR_IRQS];
|
|
|
static struct irq_chip xen_dynamic_chip;
|
|
|
|
|
|
/* Constructor for packed IRQ information. */
|
|
|
-static inline struct packed_irq mk_irq_info(u32 type, u32 index, u32 evtchn)
|
|
|
+static struct irq_info mk_unbound_info(void)
|
|
|
+{
|
|
|
+ return (struct irq_info) { .type = IRQT_UNBOUND };
|
|
|
+}
|
|
|
+
|
|
|
+static struct irq_info mk_evtchn_info(unsigned short evtchn)
|
|
|
+{
|
|
|
+ return (struct irq_info) { .type = IRQT_EVTCHN, .evtchn = evtchn };
|
|
|
+}
|
|
|
+
|
|
|
+static struct irq_info mk_ipi_info(unsigned short evtchn, enum ipi_vector ipi)
|
|
|
{
|
|
|
- return (struct packed_irq) { evtchn, index, type };
|
|
|
+ return (struct irq_info) { .type = IRQT_IPI, .evtchn = evtchn,
|
|
|
+ .u.ipi = ipi };
|
|
|
+}
|
|
|
+
|
|
|
+static struct irq_info mk_virq_info(unsigned short evtchn, unsigned short virq)
|
|
|
+{
|
|
|
+ return (struct irq_info) { .type = IRQT_VIRQ, .evtchn = evtchn,
|
|
|
+ .u.virq = virq };
|
|
|
+}
|
|
|
+
|
|
|
+static struct irq_info mk_pirq_info(unsigned short evtchn,
|
|
|
+ unsigned short gsi, unsigned short vector)
|
|
|
+{
|
|
|
+ return (struct irq_info) { .type = IRQT_PIRQ, .evtchn = evtchn,
|
|
|
+ .u.pirq = { .gsi = gsi, .vector = vector } };
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* Accessors for packed IRQ information.
|
|
|
*/
|
|
|
-static inline unsigned int evtchn_from_irq(int irq)
|
|
|
+static struct irq_info *info_for_irq(unsigned irq)
|
|
|
{
|
|
|
- return irq_info[irq].evtchn;
|
|
|
+ return &irq_info[irq];
|
|
|
}
|
|
|
|
|
|
-static inline unsigned int index_from_irq(int irq)
|
|
|
+static unsigned int evtchn_from_irq(unsigned irq)
|
|
|
{
|
|
|
- return irq_info[irq].index;
|
|
|
+ return info_for_irq(irq)->evtchn;
|
|
|
}
|
|
|
|
|
|
-static inline unsigned int type_from_irq(int irq)
|
|
|
+static enum ipi_vector ipi_from_irq(unsigned irq)
|
|
|
{
|
|
|
- return irq_info[irq].type;
|
|
|
+ struct irq_info *info = info_for_irq(irq);
|
|
|
+
|
|
|
+ BUG_ON(info == NULL);
|
|
|
+ BUG_ON(info->type != IRQT_IPI);
|
|
|
+
|
|
|
+ return info->u.ipi;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned virq_from_irq(unsigned irq)
|
|
|
+{
|
|
|
+ struct irq_info *info = info_for_irq(irq);
|
|
|
+
|
|
|
+ BUG_ON(info == NULL);
|
|
|
+ BUG_ON(info->type != IRQT_VIRQ);
|
|
|
+
|
|
|
+ return info->u.virq;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned gsi_from_irq(unsigned irq)
|
|
|
+{
|
|
|
+ struct irq_info *info = info_for_irq(irq);
|
|
|
+
|
|
|
+ BUG_ON(info == NULL);
|
|
|
+ BUG_ON(info->type != IRQT_PIRQ);
|
|
|
+
|
|
|
+ return info->u.pirq.gsi;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned vector_from_irq(unsigned irq)
|
|
|
+{
|
|
|
+ struct irq_info *info = info_for_irq(irq);
|
|
|
+
|
|
|
+ BUG_ON(info == NULL);
|
|
|
+ BUG_ON(info->type != IRQT_PIRQ);
|
|
|
+
|
|
|
+ return info->u.pirq.vector;
|
|
|
+}
|
|
|
+
|
|
|
+static enum xen_irq_type type_from_irq(unsigned irq)
|
|
|
+{
|
|
|
+ return info_for_irq(irq)->type;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned cpu_from_irq(unsigned irq)
|
|
|
+{
|
|
|
+ return info_for_irq(irq)->cpu;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int cpu_from_evtchn(unsigned int evtchn)
|
|
|
+{
|
|
|
+ int irq = evtchn_to_irq[evtchn];
|
|
|
+ unsigned ret = 0;
|
|
|
+
|
|
|
+ if (irq != -1)
|
|
|
+ ret = cpu_from_irq(irq);
|
|
|
+
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static inline unsigned long active_evtchns(unsigned int cpu,
|
|
@@ -137,10 +232,10 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
|
|
|
cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu));
|
|
|
#endif
|
|
|
|
|
|
- __clear_bit(chn, cpu_evtchn_mask(cpu_evtchn[chn]));
|
|
|
+ __clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
|
|
|
__set_bit(chn, cpu_evtchn_mask(cpu));
|
|
|
|
|
|
- cpu_evtchn[chn] = cpu;
|
|
|
+ irq_info[irq].cpu = cpu;
|
|
|
}
|
|
|
|
|
|
static void init_evtchn_cpu_bindings(void)
|
|
@@ -155,15 +250,9 @@ static void init_evtchn_cpu_bindings(void)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
- memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
|
|
|
memset(cpu_evtchn_mask(0), ~0, sizeof(cpu_evtchn_mask(0)));
|
|
|
}
|
|
|
|
|
|
-static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
|
|
|
-{
|
|
|
- return cpu_evtchn[evtchn];
|
|
|
-}
|
|
|
-
|
|
|
static inline void clear_evtchn(int port)
|
|
|
{
|
|
|
struct shared_info *s = HYPERVISOR_shared_info;
|
|
@@ -253,6 +342,8 @@ static int find_unbound_irq(void)
|
|
|
if (WARN_ON(desc == NULL))
|
|
|
return -1;
|
|
|
|
|
|
+ dynamic_irq_init(irq);
|
|
|
+
|
|
|
return irq;
|
|
|
}
|
|
|
|
|
@@ -267,12 +358,11 @@ int bind_evtchn_to_irq(unsigned int evtchn)
|
|
|
if (irq == -1) {
|
|
|
irq = find_unbound_irq();
|
|
|
|
|
|
- dynamic_irq_init(irq);
|
|
|
set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
|
|
|
handle_level_irq, "event");
|
|
|
|
|
|
evtchn_to_irq[evtchn] = irq;
|
|
|
- irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
|
|
|
+ irq_info[irq] = mk_evtchn_info(evtchn);
|
|
|
}
|
|
|
|
|
|
irq_bindcount[irq]++;
|
|
@@ -296,7 +386,6 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
|
|
|
if (irq < 0)
|
|
|
goto out;
|
|
|
|
|
|
- dynamic_irq_init(irq);
|
|
|
set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
|
|
|
handle_level_irq, "ipi");
|
|
|
|
|
@@ -307,7 +396,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
|
|
|
evtchn = bind_ipi.port;
|
|
|
|
|
|
evtchn_to_irq[evtchn] = irq;
|
|
|
- irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
|
|
|
+ irq_info[irq] = mk_ipi_info(evtchn, ipi);
|
|
|
|
|
|
per_cpu(ipi_to_irq, cpu)[ipi] = irq;
|
|
|
|
|
@@ -341,12 +430,11 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
|
|
|
|
|
|
irq = find_unbound_irq();
|
|
|
|
|
|
- dynamic_irq_init(irq);
|
|
|
set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
|
|
|
handle_level_irq, "virq");
|
|
|
|
|
|
evtchn_to_irq[evtchn] = irq;
|
|
|
- irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
|
|
|
+ irq_info[irq] = mk_virq_info(evtchn, virq);
|
|
|
|
|
|
per_cpu(virq_to_irq, cpu)[virq] = irq;
|
|
|
|
|
@@ -375,11 +463,11 @@ static void unbind_from_irq(unsigned int irq)
|
|
|
switch (type_from_irq(irq)) {
|
|
|
case IRQT_VIRQ:
|
|
|
per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
|
|
|
- [index_from_irq(irq)] = -1;
|
|
|
+ [virq_from_irq(irq)] = -1;
|
|
|
break;
|
|
|
case IRQT_IPI:
|
|
|
per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
|
|
|
- [index_from_irq(irq)] = -1;
|
|
|
+ [ipi_from_irq(irq)] = -1;
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
@@ -389,7 +477,7 @@ static void unbind_from_irq(unsigned int irq)
|
|
|
bind_evtchn_to_cpu(evtchn, 0);
|
|
|
|
|
|
evtchn_to_irq[evtchn] = -1;
|
|
|
- irq_info[irq] = IRQ_UNBOUND;
|
|
|
+ irq_info[irq] = mk_unbound_info();
|
|
|
|
|
|
dynamic_irq_cleanup(irq);
|
|
|
}
|
|
@@ -507,8 +595,8 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
|
|
|
for(i = 0; i < NR_EVENT_CHANNELS; i++) {
|
|
|
if (sync_test_bit(i, sh->evtchn_pending)) {
|
|
|
printk(" %d: event %d -> irq %d\n",
|
|
|
- cpu_evtchn[i], i,
|
|
|
- evtchn_to_irq[i]);
|
|
|
+ cpu_from_evtchn(i), i,
|
|
|
+ evtchn_to_irq[i]);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -606,7 +694,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
|
|
|
BUG_ON(irq_bindcount[irq] == 0);
|
|
|
|
|
|
evtchn_to_irq[evtchn] = irq;
|
|
|
- irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
|
|
|
+ irq_info[irq] = mk_evtchn_info(evtchn);
|
|
|
|
|
|
spin_unlock(&irq_mapping_update_lock);
|
|
|
|
|
@@ -716,8 +804,7 @@ static void restore_cpu_virqs(unsigned int cpu)
|
|
|
if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1)
|
|
|
continue;
|
|
|
|
|
|
- BUG_ON(irq_info[irq].type != IRQT_VIRQ);
|
|
|
- BUG_ON(irq_info[irq].index != virq);
|
|
|
+ BUG_ON(virq_from_irq(irq) != virq);
|
|
|
|
|
|
/* Get a new binding from Xen. */
|
|
|
bind_virq.virq = virq;
|
|
@@ -729,7 +816,7 @@ static void restore_cpu_virqs(unsigned int cpu)
|
|
|
|
|
|
/* Record the new mapping. */
|
|
|
evtchn_to_irq[evtchn] = irq;
|
|
|
- irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
|
|
|
+ irq_info[irq] = mk_virq_info(evtchn, virq);
|
|
|
bind_evtchn_to_cpu(evtchn, cpu);
|
|
|
|
|
|
/* Ready for use. */
|
|
@@ -746,8 +833,7 @@ static void restore_cpu_ipis(unsigned int cpu)
|
|
|
if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1)
|
|
|
continue;
|
|
|
|
|
|
- BUG_ON(irq_info[irq].type != IRQT_IPI);
|
|
|
- BUG_ON(irq_info[irq].index != ipi);
|
|
|
+ BUG_ON(ipi_from_irq(irq) != ipi);
|
|
|
|
|
|
/* Get a new binding from Xen. */
|
|
|
bind_ipi.vcpu = cpu;
|
|
@@ -758,7 +844,7 @@ static void restore_cpu_ipis(unsigned int cpu)
|
|
|
|
|
|
/* Record the new mapping. */
|
|
|
evtchn_to_irq[evtchn] = irq;
|
|
|
- irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
|
|
|
+ irq_info[irq] = mk_ipi_info(evtchn, ipi);
|
|
|
bind_evtchn_to_cpu(evtchn, cpu);
|
|
|
|
|
|
/* Ready for use. */
|