diff options
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/events.c | 184 |
1 files changed, 135 insertions, 49 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 2c8d710713f5..0541e07d4f67 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -52,18 +52,8 @@ static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1}; | |||
52 | /* IRQ <-> IPI mapping */ | 52 | /* IRQ <-> IPI mapping */ |
53 | static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ... XEN_NR_IPIS-1] = -1}; | 53 | static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ... XEN_NR_IPIS-1] = -1}; |
54 | 54 | ||
55 | /* Packed IRQ information: binding type, sub-type index, and event channel. */ | 55 | /* Interrupt types. */ |
56 | struct packed_irq | 56 | enum xen_irq_type { |
57 | { | ||
58 | unsigned short evtchn; | ||
59 | unsigned char index; | ||
60 | unsigned char type; | ||
61 | }; | ||
62 | |||
63 | static struct packed_irq irq_info[NR_IRQS]; | ||
64 | |||
65 | /* Binding types. */ | ||
66 | enum { | ||
67 | IRQT_UNBOUND, | 57 | IRQT_UNBOUND, |
68 | IRQT_PIRQ, | 58 | IRQT_PIRQ, |
69 | IRQT_VIRQ, | 59 | IRQT_VIRQ, |
@@ -71,8 +61,34 @@ enum { | |||
71 | IRQT_EVTCHN | 61 | IRQT_EVTCHN |
72 | }; | 62 | }; |
73 | 63 | ||
74 | /* Convenient shorthand for packed representation of an unbound IRQ. */ | 64 | /* |
75 | #define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0) | 65 | * Packed IRQ information: |
66 | * type - enum xen_irq_type | ||
67 | * event channel - irq->event channel mapping | ||
68 | * cpu - cpu this event channel is bound to | ||
69 | * index - type-specific information: | ||
70 | * PIRQ - vector, with MSB being "needs EIO" | ||
71 | * VIRQ - virq number | ||
72 | * IPI - IPI vector | ||
73 | * EVTCHN - | ||
74 | */ | ||
75 | struct irq_info | ||
76 | { | ||
77 | enum xen_irq_type type; /* type */ | ||
78 | unsigned short evtchn; /* event channel */ | ||
79 | unsigned short cpu; /* cpu bound */ | ||
80 | |||
81 | union { | ||
82 | unsigned short virq; | ||
83 | enum ipi_vector ipi; | ||
84 | struct { | ||
85 | unsigned short gsi; | ||
86 | unsigned short vector; | ||
87 | } pirq; | ||
88 | } u; | ||
89 | }; | ||
90 | |||
91 | static struct irq_info irq_info[NR_IRQS]; | ||
76 | 92 | ||
77 | static int evtchn_to_irq[NR_EVENT_CHANNELS] = { | 93 | static int evtchn_to_irq[NR_EVENT_CHANNELS] = { |
78 | [0 ... NR_EVENT_CHANNELS-1] = -1 | 94 | [0 ... NR_EVENT_CHANNELS-1] = -1 |
@@ -85,7 +101,6 @@ static inline unsigned long *cpu_evtchn_mask(int cpu) | |||
85 | { | 101 | { |
86 | return cpu_evtchn_mask_p[cpu].bits; | 102 | return cpu_evtchn_mask_p[cpu].bits; |
87 | } | 103 | } |
88 | static u8 cpu_evtchn[NR_EVENT_CHANNELS]; | ||
89 | 104 | ||
90 | /* Reference counts for bindings to IRQs. */ | 105 | /* Reference counts for bindings to IRQs. */ |
91 | static int irq_bindcount[NR_IRQS]; | 106 | static int irq_bindcount[NR_IRQS]; |
@@ -96,27 +111,107 @@ static int irq_bindcount[NR_IRQS]; | |||
96 | static struct irq_chip xen_dynamic_chip; | 111 | static struct irq_chip xen_dynamic_chip; |
97 | 112 | ||
98 | /* Constructor for packed IRQ information. */ | 113 | /* Constructor for packed IRQ information. */ |
99 | static inline struct packed_irq mk_irq_info(u32 type, u32 index, u32 evtchn) | 114 | static struct irq_info mk_unbound_info(void) |
115 | { | ||
116 | return (struct irq_info) { .type = IRQT_UNBOUND }; | ||
117 | } | ||
118 | |||
119 | static struct irq_info mk_evtchn_info(unsigned short evtchn) | ||
120 | { | ||
121 | return (struct irq_info) { .type = IRQT_EVTCHN, .evtchn = evtchn }; | ||
122 | } | ||
123 | |||
124 | static struct irq_info mk_ipi_info(unsigned short evtchn, enum ipi_vector ipi) | ||
100 | { | 125 | { |
101 | return (struct packed_irq) { evtchn, index, type }; | 126 | return (struct irq_info) { .type = IRQT_IPI, .evtchn = evtchn, |
127 | .u.ipi = ipi }; | ||
128 | } | ||
129 | |||
130 | static struct irq_info mk_virq_info(unsigned short evtchn, unsigned short virq) | ||
131 | { | ||
132 | return (struct irq_info) { .type = IRQT_VIRQ, .evtchn = evtchn, | ||
133 | .u.virq = virq }; | ||
134 | } | ||
135 | |||
136 | static struct irq_info mk_pirq_info(unsigned short evtchn, | ||
137 | unsigned short gsi, unsigned short vector) | ||
138 | { | ||
139 | return (struct irq_info) { .type = IRQT_PIRQ, .evtchn = evtchn, | ||
140 | .u.pirq = { .gsi = gsi, .vector = vector } }; | ||
102 | } | 141 | } |
103 | 142 | ||
104 | /* | 143 | /* |
105 | * Accessors for packed IRQ information. | 144 | * Accessors for packed IRQ information. |
106 | */ | 145 | */ |
107 | static inline unsigned int evtchn_from_irq(int irq) | 146 | static struct irq_info *info_for_irq(unsigned irq) |
108 | { | 147 | { |
109 | return irq_info[irq].evtchn; | 148 | return &irq_info[irq]; |
110 | } | 149 | } |
111 | 150 | ||
112 | static inline unsigned int index_from_irq(int irq) | 151 | static unsigned int evtchn_from_irq(unsigned irq) |
113 | { | 152 | { |
114 | return irq_info[irq].index; | 153 | return info_for_irq(irq)->evtchn; |
115 | } | 154 | } |
116 | 155 | ||
117 | static inline unsigned int type_from_irq(int irq) | 156 | static enum ipi_vector ipi_from_irq(unsigned irq) |
118 | { | 157 | { |
119 | return irq_info[irq].type; | 158 | struct irq_info *info = info_for_irq(irq); |
159 | |||
160 | BUG_ON(info == NULL); | ||
161 | BUG_ON(info->type != IRQT_IPI); | ||
162 | |||
163 | return info->u.ipi; | ||
164 | } | ||
165 | |||
166 | static unsigned virq_from_irq(unsigned irq) | ||
167 | { | ||
168 | struct irq_info *info = info_for_irq(irq); | ||
169 | |||
170 | BUG_ON(info == NULL); | ||
171 | BUG_ON(info->type != IRQT_VIRQ); | ||
172 | |||
173 | return info->u.virq; | ||
174 | } | ||
175 | |||
176 | static unsigned gsi_from_irq(unsigned irq) | ||
177 | { | ||
178 | struct irq_info *info = info_for_irq(irq); | ||
179 | |||
180 | BUG_ON(info == NULL); | ||
181 | BUG_ON(info->type != IRQT_PIRQ); | ||
182 | |||
183 | return info->u.pirq.gsi; | ||
184 | } | ||
185 | |||
186 | static unsigned vector_from_irq(unsigned irq) | ||
187 | { | ||
188 | struct irq_info *info = info_for_irq(irq); | ||
189 | |||
190 | BUG_ON(info == NULL); | ||
191 | BUG_ON(info->type != IRQT_PIRQ); | ||
192 | |||
193 | return info->u.pirq.vector; | ||
194 | } | ||
195 | |||
196 | static enum xen_irq_type type_from_irq(unsigned irq) | ||
197 | { | ||
198 | return info_for_irq(irq)->type; | ||
199 | } | ||
200 | |||
201 | static unsigned cpu_from_irq(unsigned irq) | ||
202 | { | ||
203 | return info_for_irq(irq)->cpu; | ||
204 | } | ||
205 | |||
206 | static unsigned int cpu_from_evtchn(unsigned int evtchn) | ||
207 | { | ||
208 | int irq = evtchn_to_irq[evtchn]; | ||
209 | unsigned ret = 0; | ||
210 | |||
211 | if (irq != -1) | ||
212 | ret = cpu_from_irq(irq); | ||
213 | |||
214 | return ret; | ||
120 | } | 215 | } |
121 | 216 | ||
122 | static inline unsigned long active_evtchns(unsigned int cpu, | 217 | 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) | |||
137 | cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu)); | 232 | cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu)); |
138 | #endif | 233 | #endif |
139 | 234 | ||
140 | __clear_bit(chn, cpu_evtchn_mask(cpu_evtchn[chn])); | 235 | __clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); |
141 | __set_bit(chn, cpu_evtchn_mask(cpu)); | 236 | __set_bit(chn, cpu_evtchn_mask(cpu)); |
142 | 237 | ||
143 | cpu_evtchn[chn] = cpu; | 238 | irq_info[irq].cpu = cpu; |
144 | } | 239 | } |
145 | 240 | ||
146 | static void init_evtchn_cpu_bindings(void) | 241 | static void init_evtchn_cpu_bindings(void) |
@@ -155,15 +250,9 @@ static void init_evtchn_cpu_bindings(void) | |||
155 | } | 250 | } |
156 | #endif | 251 | #endif |
157 | 252 | ||
158 | memset(cpu_evtchn, 0, sizeof(cpu_evtchn)); | ||
159 | memset(cpu_evtchn_mask(0), ~0, sizeof(cpu_evtchn_mask(0))); | 253 | memset(cpu_evtchn_mask(0), ~0, sizeof(cpu_evtchn_mask(0))); |
160 | } | 254 | } |
161 | 255 | ||
162 | static inline unsigned int cpu_from_evtchn(unsigned int evtchn) | ||
163 | { | ||
164 | return cpu_evtchn[evtchn]; | ||
165 | } | ||
166 | |||
167 | static inline void clear_evtchn(int port) | 256 | static inline void clear_evtchn(int port) |
168 | { | 257 | { |
169 | struct shared_info *s = HYPERVISOR_shared_info; | 258 | struct shared_info *s = HYPERVISOR_shared_info; |
@@ -253,6 +342,8 @@ static int find_unbound_irq(void) | |||
253 | if (WARN_ON(desc == NULL)) | 342 | if (WARN_ON(desc == NULL)) |
254 | return -1; | 343 | return -1; |
255 | 344 | ||
345 | dynamic_irq_init(irq); | ||
346 | |||
256 | return irq; | 347 | return irq; |
257 | } | 348 | } |
258 | 349 | ||
@@ -267,12 +358,11 @@ int bind_evtchn_to_irq(unsigned int evtchn) | |||
267 | if (irq == -1) { | 358 | if (irq == -1) { |
268 | irq = find_unbound_irq(); | 359 | irq = find_unbound_irq(); |
269 | 360 | ||
270 | dynamic_irq_init(irq); | ||
271 | set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, | 361 | set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, |
272 | handle_level_irq, "event"); | 362 | handle_level_irq, "event"); |
273 | 363 | ||
274 | evtchn_to_irq[evtchn] = irq; | 364 | evtchn_to_irq[evtchn] = irq; |
275 | irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn); | 365 | irq_info[irq] = mk_evtchn_info(evtchn); |
276 | } | 366 | } |
277 | 367 | ||
278 | irq_bindcount[irq]++; | 368 | irq_bindcount[irq]++; |
@@ -296,7 +386,6 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) | |||
296 | if (irq < 0) | 386 | if (irq < 0) |
297 | goto out; | 387 | goto out; |
298 | 388 | ||
299 | dynamic_irq_init(irq); | ||
300 | set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, | 389 | set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, |
301 | handle_level_irq, "ipi"); | 390 | handle_level_irq, "ipi"); |
302 | 391 | ||
@@ -307,7 +396,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) | |||
307 | evtchn = bind_ipi.port; | 396 | evtchn = bind_ipi.port; |
308 | 397 | ||
309 | evtchn_to_irq[evtchn] = irq; | 398 | evtchn_to_irq[evtchn] = irq; |
310 | irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); | 399 | irq_info[irq] = mk_ipi_info(evtchn, ipi); |
311 | 400 | ||
312 | per_cpu(ipi_to_irq, cpu)[ipi] = irq; | 401 | per_cpu(ipi_to_irq, cpu)[ipi] = irq; |
313 | 402 | ||
@@ -341,12 +430,11 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) | |||
341 | 430 | ||
342 | irq = find_unbound_irq(); | 431 | irq = find_unbound_irq(); |
343 | 432 | ||
344 | dynamic_irq_init(irq); | ||
345 | set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, | 433 | set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, |
346 | handle_level_irq, "virq"); | 434 | handle_level_irq, "virq"); |
347 | 435 | ||
348 | evtchn_to_irq[evtchn] = irq; | 436 | evtchn_to_irq[evtchn] = irq; |
349 | irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); | 437 | irq_info[irq] = mk_virq_info(evtchn, virq); |
350 | 438 | ||
351 | per_cpu(virq_to_irq, cpu)[virq] = irq; | 439 | per_cpu(virq_to_irq, cpu)[virq] = irq; |
352 | 440 | ||
@@ -375,11 +463,11 @@ static void unbind_from_irq(unsigned int irq) | |||
375 | switch (type_from_irq(irq)) { | 463 | switch (type_from_irq(irq)) { |
376 | case IRQT_VIRQ: | 464 | case IRQT_VIRQ: |
377 | per_cpu(virq_to_irq, cpu_from_evtchn(evtchn)) | 465 | per_cpu(virq_to_irq, cpu_from_evtchn(evtchn)) |
378 | [index_from_irq(irq)] = -1; | 466 | [virq_from_irq(irq)] = -1; |
379 | break; | 467 | break; |
380 | case IRQT_IPI: | 468 | case IRQT_IPI: |
381 | per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn)) | 469 | per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn)) |
382 | [index_from_irq(irq)] = -1; | 470 | [ipi_from_irq(irq)] = -1; |
383 | break; | 471 | break; |
384 | default: | 472 | default: |
385 | break; | 473 | break; |
@@ -389,7 +477,7 @@ static void unbind_from_irq(unsigned int irq) | |||
389 | bind_evtchn_to_cpu(evtchn, 0); | 477 | bind_evtchn_to_cpu(evtchn, 0); |
390 | 478 | ||
391 | evtchn_to_irq[evtchn] = -1; | 479 | evtchn_to_irq[evtchn] = -1; |
392 | irq_info[irq] = IRQ_UNBOUND; | 480 | irq_info[irq] = mk_unbound_info(); |
393 | 481 | ||
394 | dynamic_irq_cleanup(irq); | 482 | dynamic_irq_cleanup(irq); |
395 | } | 483 | } |
@@ -507,8 +595,8 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id) | |||
507 | for(i = 0; i < NR_EVENT_CHANNELS; i++) { | 595 | for(i = 0; i < NR_EVENT_CHANNELS; i++) { |
508 | if (sync_test_bit(i, sh->evtchn_pending)) { | 596 | if (sync_test_bit(i, sh->evtchn_pending)) { |
509 | printk(" %d: event %d -> irq %d\n", | 597 | printk(" %d: event %d -> irq %d\n", |
510 | cpu_evtchn[i], i, | 598 | cpu_from_evtchn(i), i, |
511 | evtchn_to_irq[i]); | 599 | evtchn_to_irq[i]); |
512 | } | 600 | } |
513 | } | 601 | } |
514 | 602 | ||
@@ -606,7 +694,7 @@ void rebind_evtchn_irq(int evtchn, int irq) | |||
606 | BUG_ON(irq_bindcount[irq] == 0); | 694 | BUG_ON(irq_bindcount[irq] == 0); |
607 | 695 | ||
608 | evtchn_to_irq[evtchn] = irq; | 696 | evtchn_to_irq[evtchn] = irq; |
609 | irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn); | 697 | irq_info[irq] = mk_evtchn_info(evtchn); |
610 | 698 | ||
611 | spin_unlock(&irq_mapping_update_lock); | 699 | spin_unlock(&irq_mapping_update_lock); |
612 | 700 | ||
@@ -716,8 +804,7 @@ static void restore_cpu_virqs(unsigned int cpu) | |||
716 | if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) | 804 | if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) |
717 | continue; | 805 | continue; |
718 | 806 | ||
719 | BUG_ON(irq_info[irq].type != IRQT_VIRQ); | 807 | BUG_ON(virq_from_irq(irq) != virq); |
720 | BUG_ON(irq_info[irq].index != virq); | ||
721 | 808 | ||
722 | /* Get a new binding from Xen. */ | 809 | /* Get a new binding from Xen. */ |
723 | bind_virq.virq = virq; | 810 | bind_virq.virq = virq; |
@@ -729,7 +816,7 @@ static void restore_cpu_virqs(unsigned int cpu) | |||
729 | 816 | ||
730 | /* Record the new mapping. */ | 817 | /* Record the new mapping. */ |
731 | evtchn_to_irq[evtchn] = irq; | 818 | evtchn_to_irq[evtchn] = irq; |
732 | irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); | 819 | irq_info[irq] = mk_virq_info(evtchn, virq); |
733 | bind_evtchn_to_cpu(evtchn, cpu); | 820 | bind_evtchn_to_cpu(evtchn, cpu); |
734 | 821 | ||
735 | /* Ready for use. */ | 822 | /* Ready for use. */ |
@@ -746,8 +833,7 @@ static void restore_cpu_ipis(unsigned int cpu) | |||
746 | if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) | 833 | if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) |
747 | continue; | 834 | continue; |
748 | 835 | ||
749 | BUG_ON(irq_info[irq].type != IRQT_IPI); | 836 | BUG_ON(ipi_from_irq(irq) != ipi); |
750 | BUG_ON(irq_info[irq].index != ipi); | ||
751 | 837 | ||
752 | /* Get a new binding from Xen. */ | 838 | /* Get a new binding from Xen. */ |
753 | bind_ipi.vcpu = cpu; | 839 | bind_ipi.vcpu = cpu; |
@@ -758,7 +844,7 @@ static void restore_cpu_ipis(unsigned int cpu) | |||
758 | 844 | ||
759 | /* Record the new mapping. */ | 845 | /* Record the new mapping. */ |
760 | evtchn_to_irq[evtchn] = irq; | 846 | evtchn_to_irq[evtchn] = irq; |
761 | irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); | 847 | irq_info[irq] = mk_ipi_info(evtchn, ipi); |
762 | bind_evtchn_to_cpu(evtchn, cpu); | 848 | bind_evtchn_to_cpu(evtchn, cpu); |
763 | 849 | ||
764 | /* Ready for use. */ | 850 | /* Ready for use. */ |