diff options
| author | David Vrabel <david.vrabel@citrix.com> | 2013-03-13 11:29:25 -0400 |
|---|---|---|
| committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2014-01-06 10:07:41 -0500 |
| commit | 9a489f45a155fe96b9b55fbbef2b757ef7737cfc (patch) | |
| tree | 1104f50a1adaeea564344bdfe221a5edf2141077 /drivers/xen/events | |
| parent | d2ba3166f23baa53f5ee9c5c2ca43b42fb4e9e62 (diff) | |
xen/events: move 2-level specific code into its own file
In preparation for alternative event channel ABIs, move all the
functions accessing the shared data structures into their own file.
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Diffstat (limited to 'drivers/xen/events')
| -rw-r--r-- | drivers/xen/events/Makefile | 1 | ||||
| -rw-r--r-- | drivers/xen/events/events_2l.c | 348 | ||||
| -rw-r--r-- | drivers/xen/events/events_base.c | 379 | ||||
| -rw-r--r-- | drivers/xen/events/events_internal.h | 74 |
4 files changed, 440 insertions, 362 deletions
diff --git a/drivers/xen/events/Makefile b/drivers/xen/events/Makefile index f0bc6071fd84..08179fe04612 100644 --- a/drivers/xen/events/Makefile +++ b/drivers/xen/events/Makefile | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | obj-y += events.o | 1 | obj-y += events.o |
| 2 | 2 | ||
| 3 | events-y += events_base.o | 3 | events-y += events_base.o |
| 4 | events-y += events_2l.o | ||
diff --git a/drivers/xen/events/events_2l.c b/drivers/xen/events/events_2l.c new file mode 100644 index 000000000000..a77e98d025fa --- /dev/null +++ b/drivers/xen/events/events_2l.c | |||
| @@ -0,0 +1,348 @@ | |||
| 1 | /* | ||
| 2 | * Xen event channels (2-level ABI) | ||
| 3 | * | ||
| 4 | * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 | ||
| 5 | */ | ||
| 6 | |||
| 7 | #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt | ||
| 8 | |||
| 9 | #include <linux/linkage.h> | ||
| 10 | #include <linux/interrupt.h> | ||
| 11 | #include <linux/irq.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | |||
| 14 | #include <asm/sync_bitops.h> | ||
| 15 | #include <asm/xen/hypercall.h> | ||
| 16 | #include <asm/xen/hypervisor.h> | ||
| 17 | |||
| 18 | #include <xen/xen.h> | ||
| 19 | #include <xen/xen-ops.h> | ||
| 20 | #include <xen/events.h> | ||
| 21 | #include <xen/interface/xen.h> | ||
| 22 | #include <xen/interface/event_channel.h> | ||
| 23 | |||
| 24 | #include "events_internal.h" | ||
| 25 | |||
| 26 | /* | ||
| 27 | * Note sizeof(xen_ulong_t) can be more than sizeof(unsigned long). Be | ||
| 28 | * careful to only use bitops which allow for this (e.g | ||
| 29 | * test_bit/find_first_bit and friends but not __ffs) and to pass | ||
| 30 | * BITS_PER_EVTCHN_WORD as the bitmask length. | ||
| 31 | */ | ||
| 32 | #define BITS_PER_EVTCHN_WORD (sizeof(xen_ulong_t)*8) | ||
| 33 | /* | ||
| 34 | * Make a bitmask (i.e. unsigned long *) of a xen_ulong_t | ||
| 35 | * array. Primarily to avoid long lines (hence the terse name). | ||
| 36 | */ | ||
| 37 | #define BM(x) (unsigned long *)(x) | ||
| 38 | /* Find the first set bit in a evtchn mask */ | ||
| 39 | #define EVTCHN_FIRST_BIT(w) find_first_bit(BM(&(w)), BITS_PER_EVTCHN_WORD) | ||
| 40 | |||
| 41 | static DEFINE_PER_CPU(xen_ulong_t [NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD], | ||
| 42 | cpu_evtchn_mask); | ||
| 43 | |||
| 44 | void xen_evtchn_port_bind_to_cpu(struct irq_info *info, int cpu) | ||
| 45 | { | ||
| 46 | clear_bit(info->evtchn, BM(per_cpu(cpu_evtchn_mask, info->cpu))); | ||
| 47 | set_bit(info->evtchn, BM(per_cpu(cpu_evtchn_mask, cpu))); | ||
| 48 | } | ||
| 49 | |||
| 50 | void clear_evtchn(int port) | ||
| 51 | { | ||
| 52 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 53 | sync_clear_bit(port, BM(&s->evtchn_pending[0])); | ||
| 54 | } | ||
| 55 | |||
| 56 | void set_evtchn(int port) | ||
| 57 | { | ||
| 58 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 59 | sync_set_bit(port, BM(&s->evtchn_pending[0])); | ||
| 60 | } | ||
| 61 | |||
| 62 | int test_evtchn(int port) | ||
| 63 | { | ||
| 64 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 65 | return sync_test_bit(port, BM(&s->evtchn_pending[0])); | ||
| 66 | } | ||
| 67 | |||
| 68 | int test_and_set_mask(int port) | ||
| 69 | { | ||
| 70 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 71 | return sync_test_and_set_bit(port, BM(&s->evtchn_mask[0])); | ||
| 72 | } | ||
| 73 | |||
| 74 | void mask_evtchn(int port) | ||
| 75 | { | ||
| 76 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 77 | sync_set_bit(port, BM(&s->evtchn_mask[0])); | ||
| 78 | } | ||
| 79 | |||
| 80 | void unmask_evtchn(int port) | ||
| 81 | { | ||
| 82 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 83 | unsigned int cpu = get_cpu(); | ||
| 84 | int do_hypercall = 0, evtchn_pending = 0; | ||
| 85 | |||
| 86 | BUG_ON(!irqs_disabled()); | ||
| 87 | |||
| 88 | if (unlikely((cpu != cpu_from_evtchn(port)))) | ||
| 89 | do_hypercall = 1; | ||
| 90 | else { | ||
| 91 | /* | ||
| 92 | * Need to clear the mask before checking pending to | ||
| 93 | * avoid a race with an event becoming pending. | ||
| 94 | * | ||
| 95 | * EVTCHNOP_unmask will only trigger an upcall if the | ||
| 96 | * mask bit was set, so if a hypercall is needed | ||
| 97 | * remask the event. | ||
| 98 | */ | ||
| 99 | sync_clear_bit(port, BM(&s->evtchn_mask[0])); | ||
| 100 | evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0])); | ||
| 101 | |||
| 102 | if (unlikely(evtchn_pending && xen_hvm_domain())) { | ||
| 103 | sync_set_bit(port, BM(&s->evtchn_mask[0])); | ||
| 104 | do_hypercall = 1; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | /* Slow path (hypercall) if this is a non-local port or if this is | ||
| 109 | * an hvm domain and an event is pending (hvm domains don't have | ||
| 110 | * their own implementation of irq_enable). */ | ||
| 111 | if (do_hypercall) { | ||
| 112 | struct evtchn_unmask unmask = { .port = port }; | ||
| 113 | (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask); | ||
| 114 | } else { | ||
| 115 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); | ||
| 116 | |||
| 117 | /* | ||
| 118 | * The following is basically the equivalent of | ||
| 119 | * 'hw_resend_irq'. Just like a real IO-APIC we 'lose | ||
| 120 | * the interrupt edge' if the channel is masked. | ||
| 121 | */ | ||
| 122 | if (evtchn_pending && | ||
| 123 | !sync_test_and_set_bit(port / BITS_PER_EVTCHN_WORD, | ||
| 124 | BM(&vcpu_info->evtchn_pending_sel))) | ||
| 125 | vcpu_info->evtchn_upcall_pending = 1; | ||
| 126 | } | ||
| 127 | |||
| 128 | put_cpu(); | ||
| 129 | } | ||
| 130 | |||
| 131 | static DEFINE_PER_CPU(unsigned int, current_word_idx); | ||
| 132 | static DEFINE_PER_CPU(unsigned int, current_bit_idx); | ||
| 133 | |||
| 134 | /* | ||
| 135 | * Mask out the i least significant bits of w | ||
| 136 | */ | ||
| 137 | #define MASK_LSBS(w, i) (w & ((~((xen_ulong_t)0UL)) << i)) | ||
| 138 | |||
| 139 | static inline xen_ulong_t active_evtchns(unsigned int cpu, | ||
| 140 | struct shared_info *sh, | ||
| 141 | unsigned int idx) | ||
| 142 | { | ||
| 143 | return sh->evtchn_pending[idx] & | ||
| 144 | per_cpu(cpu_evtchn_mask, cpu)[idx] & | ||
| 145 | ~sh->evtchn_mask[idx]; | ||
| 146 | } | ||
| 147 | |||
| 148 | /* | ||
| 149 | * Search the CPU's pending events bitmasks. For each one found, map | ||
| 150 | * the event number to an irq, and feed it into do_IRQ() for handling. | ||
| 151 | * | ||
| 152 | * Xen uses a two-level bitmap to speed searching. The first level is | ||
| 153 | * a bitset of words which contain pending event bits. The second | ||
| 154 | * level is a bitset of pending events themselves. | ||
| 155 | */ | ||
| 156 | void xen_evtchn_handle_events(int cpu) | ||
| 157 | { | ||
| 158 | int irq; | ||
| 159 | xen_ulong_t pending_words; | ||
| 160 | xen_ulong_t pending_bits; | ||
| 161 | int start_word_idx, start_bit_idx; | ||
| 162 | int word_idx, bit_idx; | ||
| 163 | int i; | ||
| 164 | struct irq_desc *desc; | ||
| 165 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 166 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); | ||
| 167 | |||
| 168 | /* Timer interrupt has highest priority. */ | ||
| 169 | irq = irq_from_virq(cpu, VIRQ_TIMER); | ||
| 170 | if (irq != -1) { | ||
| 171 | unsigned int evtchn = evtchn_from_irq(irq); | ||
| 172 | word_idx = evtchn / BITS_PER_LONG; | ||
| 173 | bit_idx = evtchn % BITS_PER_LONG; | ||
| 174 | if (active_evtchns(cpu, s, word_idx) & (1ULL << bit_idx)) { | ||
| 175 | desc = irq_to_desc(irq); | ||
| 176 | if (desc) | ||
| 177 | generic_handle_irq_desc(irq, desc); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | /* | ||
| 182 | * Master flag must be cleared /before/ clearing | ||
| 183 | * selector flag. xchg_xen_ulong must contain an | ||
| 184 | * appropriate barrier. | ||
| 185 | */ | ||
| 186 | pending_words = xchg_xen_ulong(&vcpu_info->evtchn_pending_sel, 0); | ||
| 187 | |||
| 188 | start_word_idx = __this_cpu_read(current_word_idx); | ||
| 189 | start_bit_idx = __this_cpu_read(current_bit_idx); | ||
| 190 | |||
| 191 | word_idx = start_word_idx; | ||
| 192 | |||
| 193 | for (i = 0; pending_words != 0; i++) { | ||
| 194 | xen_ulong_t words; | ||
| 195 | |||
| 196 | words = MASK_LSBS(pending_words, word_idx); | ||
| 197 | |||
| 198 | /* | ||
| 199 | * If we masked out all events, wrap to beginning. | ||
| 200 | */ | ||
| 201 | if (words == 0) { | ||
| 202 | word_idx = 0; | ||
| 203 | bit_idx = 0; | ||
| 204 | continue; | ||
| 205 | } | ||
| 206 | word_idx = EVTCHN_FIRST_BIT(words); | ||
| 207 | |||
| 208 | pending_bits = active_evtchns(cpu, s, word_idx); | ||
| 209 | bit_idx = 0; /* usually scan entire word from start */ | ||
| 210 | /* | ||
| 211 | * We scan the starting word in two parts. | ||
| 212 | * | ||
| 213 | * 1st time: start in the middle, scanning the | ||
| 214 | * upper bits. | ||
| 215 | * | ||
| 216 | * 2nd time: scan the whole word (not just the | ||
| 217 | * parts skipped in the first pass) -- if an | ||
| 218 | * event in the previously scanned bits is | ||
| 219 | * pending again it would just be scanned on | ||
| 220 | * the next loop anyway. | ||
| 221 | */ | ||
| 222 | if (word_idx == start_word_idx) { | ||
| 223 | if (i == 0) | ||
| 224 | bit_idx = start_bit_idx; | ||
| 225 | } | ||
| 226 | |||
| 227 | do { | ||
| 228 | xen_ulong_t bits; | ||
| 229 | int port; | ||
| 230 | |||
| 231 | bits = MASK_LSBS(pending_bits, bit_idx); | ||
| 232 | |||
| 233 | /* If we masked out all events, move on. */ | ||
| 234 | if (bits == 0) | ||
| 235 | break; | ||
| 236 | |||
| 237 | bit_idx = EVTCHN_FIRST_BIT(bits); | ||
| 238 | |||
| 239 | /* Process port. */ | ||
| 240 | port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx; | ||
| 241 | irq = evtchn_to_irq[port]; | ||
| 242 | |||
| 243 | if (irq != -1) { | ||
| 244 | desc = irq_to_desc(irq); | ||
| 245 | if (desc) | ||
| 246 | generic_handle_irq_desc(irq, desc); | ||
| 247 | } | ||
| 248 | |||
| 249 | bit_idx = (bit_idx + 1) % BITS_PER_EVTCHN_WORD; | ||
| 250 | |||
| 251 | /* Next caller starts at last processed + 1 */ | ||
| 252 | __this_cpu_write(current_word_idx, | ||
| 253 | bit_idx ? word_idx : | ||
| 254 | (word_idx+1) % BITS_PER_EVTCHN_WORD); | ||
| 255 | __this_cpu_write(current_bit_idx, bit_idx); | ||
| 256 | } while (bit_idx != 0); | ||
| 257 | |||
| 258 | /* Scan start_l1i twice; all others once. */ | ||
| 259 | if ((word_idx != start_word_idx) || (i != 0)) | ||
| 260 | pending_words &= ~(1UL << word_idx); | ||
| 261 | |||
| 262 | word_idx = (word_idx + 1) % BITS_PER_EVTCHN_WORD; | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | irqreturn_t xen_debug_interrupt(int irq, void *dev_id) | ||
| 267 | { | ||
| 268 | struct shared_info *sh = HYPERVISOR_shared_info; | ||
| 269 | int cpu = smp_processor_id(); | ||
| 270 | xen_ulong_t *cpu_evtchn = per_cpu(cpu_evtchn_mask, cpu); | ||
| 271 | int i; | ||
| 272 | unsigned long flags; | ||
| 273 | static DEFINE_SPINLOCK(debug_lock); | ||
| 274 | struct vcpu_info *v; | ||
| 275 | |||
| 276 | spin_lock_irqsave(&debug_lock, flags); | ||
| 277 | |||
| 278 | printk("\nvcpu %d\n ", cpu); | ||
| 279 | |||
| 280 | for_each_online_cpu(i) { | ||
| 281 | int pending; | ||
| 282 | v = per_cpu(xen_vcpu, i); | ||
| 283 | pending = (get_irq_regs() && i == cpu) | ||
| 284 | ? xen_irqs_disabled(get_irq_regs()) | ||
| 285 | : v->evtchn_upcall_mask; | ||
| 286 | printk("%d: masked=%d pending=%d event_sel %0*"PRI_xen_ulong"\n ", i, | ||
| 287 | pending, v->evtchn_upcall_pending, | ||
| 288 | (int)(sizeof(v->evtchn_pending_sel)*2), | ||
| 289 | v->evtchn_pending_sel); | ||
| 290 | } | ||
| 291 | v = per_cpu(xen_vcpu, cpu); | ||
| 292 | |||
| 293 | printk("\npending:\n "); | ||
| 294 | for (i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--) | ||
| 295 | printk("%0*"PRI_xen_ulong"%s", | ||
| 296 | (int)sizeof(sh->evtchn_pending[0])*2, | ||
| 297 | sh->evtchn_pending[i], | ||
| 298 | i % 8 == 0 ? "\n " : " "); | ||
| 299 | printk("\nglobal mask:\n "); | ||
| 300 | for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) | ||
| 301 | printk("%0*"PRI_xen_ulong"%s", | ||
| 302 | (int)(sizeof(sh->evtchn_mask[0])*2), | ||
| 303 | sh->evtchn_mask[i], | ||
| 304 | i % 8 == 0 ? "\n " : " "); | ||
| 305 | |||
| 306 | printk("\nglobally unmasked:\n "); | ||
| 307 | for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) | ||
| 308 | printk("%0*"PRI_xen_ulong"%s", | ||
| 309 | (int)(sizeof(sh->evtchn_mask[0])*2), | ||
| 310 | sh->evtchn_pending[i] & ~sh->evtchn_mask[i], | ||
| 311 | i % 8 == 0 ? "\n " : " "); | ||
| 312 | |||
| 313 | printk("\nlocal cpu%d mask:\n ", cpu); | ||
| 314 | for (i = (NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD)-1; i >= 0; i--) | ||
| 315 | printk("%0*"PRI_xen_ulong"%s", (int)(sizeof(cpu_evtchn[0])*2), | ||
| 316 | cpu_evtchn[i], | ||
| 317 | i % 8 == 0 ? "\n " : " "); | ||
| 318 | |||
| 319 | printk("\nlocally unmasked:\n "); | ||
| 320 | for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) { | ||
| 321 | xen_ulong_t pending = sh->evtchn_pending[i] | ||
| 322 | & ~sh->evtchn_mask[i] | ||
| 323 | & cpu_evtchn[i]; | ||
| 324 | printk("%0*"PRI_xen_ulong"%s", | ||
| 325 | (int)(sizeof(sh->evtchn_mask[0])*2), | ||
| 326 | pending, i % 8 == 0 ? "\n " : " "); | ||
| 327 | } | ||
| 328 | |||
| 329 | printk("\npending list:\n"); | ||
| 330 | for (i = 0; i < NR_EVENT_CHANNELS; i++) { | ||
| 331 | if (sync_test_bit(i, BM(sh->evtchn_pending))) { | ||
| 332 | int word_idx = i / BITS_PER_EVTCHN_WORD; | ||
| 333 | printk(" %d: event %d -> irq %d%s%s%s\n", | ||
| 334 | cpu_from_evtchn(i), i, | ||
| 335 | evtchn_to_irq[i], | ||
| 336 | sync_test_bit(word_idx, BM(&v->evtchn_pending_sel)) | ||
| 337 | ? "" : " l2-clear", | ||
| 338 | !sync_test_bit(i, BM(sh->evtchn_mask)) | ||
| 339 | ? "" : " globally-masked", | ||
| 340 | sync_test_bit(i, BM(cpu_evtchn)) | ||
| 341 | ? "" : " locally-masked"); | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | spin_unlock_irqrestore(&debug_lock, flags); | ||
| 346 | |||
| 347 | return IRQ_HANDLED; | ||
| 348 | } | ||
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index fec5da4ff3a0..8771b740e30f 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c | |||
| @@ -59,6 +59,8 @@ | |||
| 59 | #include <xen/interface/vcpu.h> | 59 | #include <xen/interface/vcpu.h> |
| 60 | #include <asm/hw_irq.h> | 60 | #include <asm/hw_irq.h> |
| 61 | 61 | ||
| 62 | #include "events_internal.h" | ||
| 63 | |||
| 62 | /* | 64 | /* |
| 63 | * This lock protects updates to the following mapping and reference-count | 65 | * This lock protects updates to the following mapping and reference-count |
| 64 | * arrays. The lock does not need to be acquired to read the mapping tables. | 66 | * arrays. The lock does not need to be acquired to read the mapping tables. |
| @@ -73,72 +75,12 @@ static DEFINE_PER_CPU(int [NR_VIRQS], virq_to_irq) = {[0 ... NR_VIRQS-1] = -1}; | |||
| 73 | /* IRQ <-> IPI mapping */ | 75 | /* IRQ <-> IPI mapping */ |
| 74 | static DEFINE_PER_CPU(int [XEN_NR_IPIS], ipi_to_irq) = {[0 ... XEN_NR_IPIS-1] = -1}; | 76 | static DEFINE_PER_CPU(int [XEN_NR_IPIS], ipi_to_irq) = {[0 ... XEN_NR_IPIS-1] = -1}; |
| 75 | 77 | ||
| 76 | /* Interrupt types. */ | 78 | int *evtchn_to_irq; |
| 77 | enum xen_irq_type { | ||
| 78 | IRQT_UNBOUND = 0, | ||
| 79 | IRQT_PIRQ, | ||
| 80 | IRQT_VIRQ, | ||
| 81 | IRQT_IPI, | ||
| 82 | IRQT_EVTCHN | ||
| 83 | }; | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Packed IRQ information: | ||
| 87 | * type - enum xen_irq_type | ||
| 88 | * event channel - irq->event channel mapping | ||
| 89 | * cpu - cpu this event channel is bound to | ||
| 90 | * index - type-specific information: | ||
| 91 | * PIRQ - physical IRQ, GSI, flags, and owner domain | ||
| 92 | * VIRQ - virq number | ||
| 93 | * IPI - IPI vector | ||
| 94 | * EVTCHN - | ||
| 95 | */ | ||
| 96 | struct irq_info { | ||
| 97 | struct list_head list; | ||
| 98 | int refcnt; | ||
| 99 | enum xen_irq_type type; /* type */ | ||
| 100 | unsigned irq; | ||
| 101 | unsigned short evtchn; /* event channel */ | ||
| 102 | unsigned short cpu; /* cpu bound */ | ||
| 103 | |||
| 104 | union { | ||
| 105 | unsigned short virq; | ||
| 106 | enum ipi_vector ipi; | ||
| 107 | struct { | ||
| 108 | unsigned short pirq; | ||
| 109 | unsigned short gsi; | ||
| 110 | unsigned char flags; | ||
| 111 | uint16_t domid; | ||
| 112 | } pirq; | ||
| 113 | } u; | ||
| 114 | }; | ||
| 115 | #define PIRQ_NEEDS_EOI (1 << 0) | ||
| 116 | #define PIRQ_SHAREABLE (1 << 1) | ||
| 117 | |||
| 118 | static int *evtchn_to_irq; | ||
| 119 | #ifdef CONFIG_X86 | 79 | #ifdef CONFIG_X86 |
| 120 | static unsigned long *pirq_eoi_map; | 80 | static unsigned long *pirq_eoi_map; |
| 121 | #endif | 81 | #endif |
| 122 | static bool (*pirq_needs_eoi)(unsigned irq); | 82 | static bool (*pirq_needs_eoi)(unsigned irq); |
| 123 | 83 | ||
| 124 | /* | ||
| 125 | * Note sizeof(xen_ulong_t) can be more than sizeof(unsigned long). Be | ||
| 126 | * careful to only use bitops which allow for this (e.g | ||
| 127 | * test_bit/find_first_bit and friends but not __ffs) and to pass | ||
| 128 | * BITS_PER_EVTCHN_WORD as the bitmask length. | ||
| 129 | */ | ||
| 130 | #define BITS_PER_EVTCHN_WORD (sizeof(xen_ulong_t)*8) | ||
| 131 | /* | ||
| 132 | * Make a bitmask (i.e. unsigned long *) of a xen_ulong_t | ||
| 133 | * array. Primarily to avoid long lines (hence the terse name). | ||
| 134 | */ | ||
| 135 | #define BM(x) (unsigned long *)(x) | ||
| 136 | /* Find the first set bit in a evtchn mask */ | ||
| 137 | #define EVTCHN_FIRST_BIT(w) find_first_bit(BM(&(w)), BITS_PER_EVTCHN_WORD) | ||
| 138 | |||
| 139 | static DEFINE_PER_CPU(xen_ulong_t [NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD], | ||
| 140 | cpu_evtchn_mask); | ||
| 141 | |||
| 142 | /* Xen will never allocate port zero for any purpose. */ | 84 | /* Xen will never allocate port zero for any purpose. */ |
| 143 | #define VALID_EVTCHN(chn) ((chn) != 0) | 85 | #define VALID_EVTCHN(chn) ((chn) != 0) |
| 144 | 86 | ||
| @@ -149,7 +91,7 @@ static void enable_dynirq(struct irq_data *data); | |||
| 149 | static void disable_dynirq(struct irq_data *data); | 91 | static void disable_dynirq(struct irq_data *data); |
| 150 | 92 | ||
| 151 | /* Get info for IRQ */ | 93 | /* Get info for IRQ */ |
| 152 | static struct irq_info *info_for_irq(unsigned irq) | 94 | struct irq_info *info_for_irq(unsigned irq) |
| 153 | { | 95 | { |
| 154 | return irq_get_handler_data(irq); | 96 | return irq_get_handler_data(irq); |
| 155 | } | 97 | } |
| @@ -230,7 +172,7 @@ static void xen_irq_info_pirq_init(unsigned irq, | |||
| 230 | /* | 172 | /* |
| 231 | * Accessors for packed IRQ information. | 173 | * Accessors for packed IRQ information. |
| 232 | */ | 174 | */ |
| 233 | static unsigned int evtchn_from_irq(unsigned irq) | 175 | unsigned int evtchn_from_irq(unsigned irq) |
| 234 | { | 176 | { |
| 235 | if (unlikely(WARN(irq < 0 || irq >= nr_irqs, "Invalid irq %d!\n", irq))) | 177 | if (unlikely(WARN(irq < 0 || irq >= nr_irqs, "Invalid irq %d!\n", irq))) |
| 236 | return 0; | 178 | return 0; |
| @@ -244,6 +186,11 @@ unsigned irq_from_evtchn(unsigned int evtchn) | |||
| 244 | } | 186 | } |
| 245 | EXPORT_SYMBOL_GPL(irq_from_evtchn); | 187 | EXPORT_SYMBOL_GPL(irq_from_evtchn); |
| 246 | 188 | ||
| 189 | int irq_from_virq(unsigned int cpu, unsigned int virq) | ||
| 190 | { | ||
| 191 | return per_cpu(virq_to_irq, cpu)[virq]; | ||
| 192 | } | ||
| 193 | |||
| 247 | static enum ipi_vector ipi_from_irq(unsigned irq) | 194 | static enum ipi_vector ipi_from_irq(unsigned irq) |
| 248 | { | 195 | { |
| 249 | struct irq_info *info = info_for_irq(irq); | 196 | struct irq_info *info = info_for_irq(irq); |
| @@ -279,12 +226,12 @@ static enum xen_irq_type type_from_irq(unsigned irq) | |||
| 279 | return info_for_irq(irq)->type; | 226 | return info_for_irq(irq)->type; |
| 280 | } | 227 | } |
| 281 | 228 | ||
| 282 | static unsigned cpu_from_irq(unsigned irq) | 229 | unsigned cpu_from_irq(unsigned irq) |
| 283 | { | 230 | { |
| 284 | return info_for_irq(irq)->cpu; | 231 | return info_for_irq(irq)->cpu; |
| 285 | } | 232 | } |
| 286 | 233 | ||
| 287 | static unsigned int cpu_from_evtchn(unsigned int evtchn) | 234 | unsigned int cpu_from_evtchn(unsigned int evtchn) |
| 288 | { | 235 | { |
| 289 | int irq = evtchn_to_irq[evtchn]; | 236 | int irq = evtchn_to_irq[evtchn]; |
| 290 | unsigned ret = 0; | 237 | unsigned ret = 0; |
| @@ -310,55 +257,21 @@ static bool pirq_needs_eoi_flag(unsigned irq) | |||
| 310 | return info->u.pirq.flags & PIRQ_NEEDS_EOI; | 257 | return info->u.pirq.flags & PIRQ_NEEDS_EOI; |
| 311 | } | 258 | } |
| 312 | 259 | ||
| 313 | static inline xen_ulong_t active_evtchns(unsigned int cpu, | ||
| 314 | struct shared_info *sh, | ||
| 315 | unsigned int idx) | ||
| 316 | { | ||
| 317 | return sh->evtchn_pending[idx] & | ||
| 318 | per_cpu(cpu_evtchn_mask, cpu)[idx] & | ||
| 319 | ~sh->evtchn_mask[idx]; | ||
| 320 | } | ||
| 321 | |||
| 322 | static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) | 260 | static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) |
| 323 | { | 261 | { |
| 324 | int irq = evtchn_to_irq[chn]; | 262 | int irq = evtchn_to_irq[chn]; |
| 263 | struct irq_info *info = info_for_irq(irq); | ||
| 325 | 264 | ||
| 326 | BUG_ON(irq == -1); | 265 | BUG_ON(irq == -1); |
| 327 | #ifdef CONFIG_SMP | 266 | #ifdef CONFIG_SMP |
| 328 | cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu)); | 267 | cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu)); |
| 329 | #endif | 268 | #endif |
| 330 | 269 | ||
| 331 | clear_bit(chn, BM(per_cpu(cpu_evtchn_mask, cpu_from_irq(irq)))); | 270 | xen_evtchn_port_bind_to_cpu(info, cpu); |
| 332 | set_bit(chn, BM(per_cpu(cpu_evtchn_mask, cpu))); | ||
| 333 | 271 | ||
| 334 | info_for_irq(irq)->cpu = cpu; | 272 | info->cpu = cpu; |
| 335 | } | ||
| 336 | |||
| 337 | static inline void clear_evtchn(int port) | ||
| 338 | { | ||
| 339 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 340 | sync_clear_bit(port, BM(&s->evtchn_pending[0])); | ||
| 341 | } | ||
| 342 | |||
| 343 | static inline void set_evtchn(int port) | ||
| 344 | { | ||
| 345 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 346 | sync_set_bit(port, BM(&s->evtchn_pending[0])); | ||
| 347 | } | ||
| 348 | |||
| 349 | static inline int test_evtchn(int port) | ||
| 350 | { | ||
| 351 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 352 | return sync_test_bit(port, BM(&s->evtchn_pending[0])); | ||
| 353 | } | ||
| 354 | |||
| 355 | static inline int test_and_set_mask(int port) | ||
| 356 | { | ||
| 357 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 358 | return sync_test_and_set_bit(port, BM(&s->evtchn_mask[0])); | ||
| 359 | } | 273 | } |
| 360 | 274 | ||
| 361 | |||
| 362 | /** | 275 | /** |
| 363 | * notify_remote_via_irq - send event to remote end of event channel via irq | 276 | * notify_remote_via_irq - send event to remote end of event channel via irq |
| 364 | * @irq: irq of event channel to send event to | 277 | * @irq: irq of event channel to send event to |
| @@ -376,63 +289,6 @@ void notify_remote_via_irq(int irq) | |||
| 376 | } | 289 | } |
| 377 | EXPORT_SYMBOL_GPL(notify_remote_via_irq); | 290 | EXPORT_SYMBOL_GPL(notify_remote_via_irq); |
| 378 | 291 | ||
| 379 | static void mask_evtchn(int port) | ||
| 380 | { | ||
| 381 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 382 | sync_set_bit(port, BM(&s->evtchn_mask[0])); | ||
| 383 | } | ||
| 384 | |||
| 385 | static void unmask_evtchn(int port) | ||
| 386 | { | ||
| 387 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 388 | unsigned int cpu = get_cpu(); | ||
| 389 | int do_hypercall = 0, evtchn_pending = 0; | ||
| 390 | |||
| 391 | BUG_ON(!irqs_disabled()); | ||
| 392 | |||
| 393 | if (unlikely((cpu != cpu_from_evtchn(port)))) | ||
| 394 | do_hypercall = 1; | ||
| 395 | else { | ||
| 396 | /* | ||
| 397 | * Need to clear the mask before checking pending to | ||
| 398 | * avoid a race with an event becoming pending. | ||
| 399 | * | ||
| 400 | * EVTCHNOP_unmask will only trigger an upcall if the | ||
| 401 | * mask bit was set, so if a hypercall is needed | ||
| 402 | * remask the event. | ||
| 403 | */ | ||
| 404 | sync_clear_bit(port, BM(&s->evtchn_mask[0])); | ||
| 405 | evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0])); | ||
| 406 | |||
| 407 | if (unlikely(evtchn_pending && xen_hvm_domain())) { | ||
| 408 | sync_set_bit(port, BM(&s->evtchn_mask[0])); | ||
| 409 | do_hypercall = 1; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | /* Slow path (hypercall) if this is a non-local port or if this is | ||
| 414 | * an hvm domain and an event is pending (hvm domains don't have | ||
| 415 | * their own implementation of irq_enable). */ | ||
| 416 | if (do_hypercall) { | ||
| 417 | struct evtchn_unmask unmask = { .port = port }; | ||
| 418 | (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask); | ||
| 419 | } else { | ||
| 420 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); | ||
| 421 | |||
| 422 | /* | ||
| 423 | * The following is basically the equivalent of | ||
| 424 | * 'hw_resend_irq'. Just like a real IO-APIC we 'lose | ||
| 425 | * the interrupt edge' if the channel is masked. | ||
| 426 | */ | ||
| 427 | if (evtchn_pending && | ||
| 428 | !sync_test_and_set_bit(port / BITS_PER_EVTCHN_WORD, | ||
| 429 | BM(&vcpu_info->evtchn_pending_sel))) | ||
| 430 | vcpu_info->evtchn_upcall_pending = 1; | ||
| 431 | } | ||
| 432 | |||
| 433 | put_cpu(); | ||
| 434 | } | ||
| 435 | |||
| 436 | static void xen_irq_init(unsigned irq) | 292 | static void xen_irq_init(unsigned irq) |
| 437 | { | 293 | { |
| 438 | struct irq_info *info; | 294 | struct irq_info *info; |
| @@ -1216,222 +1072,21 @@ void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector) | |||
| 1216 | notify_remote_via_irq(irq); | 1072 | notify_remote_via_irq(irq); |
| 1217 | } | 1073 | } |
| 1218 | 1074 | ||
| 1219 | irqreturn_t xen_debug_interrupt(int irq, void *dev_id) | ||
| 1220 | { | ||
| 1221 | struct shared_info *sh = HYPERVISOR_shared_info; | ||
| 1222 | int cpu = smp_processor_id(); | ||
| 1223 | xen_ulong_t *cpu_evtchn = per_cpu(cpu_evtchn_mask, cpu); | ||
| 1224 | int i; | ||
| 1225 | unsigned long flags; | ||
| 1226 | static DEFINE_SPINLOCK(debug_lock); | ||
| 1227 | struct vcpu_info *v; | ||
| 1228 | |||
| 1229 | spin_lock_irqsave(&debug_lock, flags); | ||
| 1230 | |||
| 1231 | printk("\nvcpu %d\n ", cpu); | ||
| 1232 | |||
| 1233 | for_each_online_cpu(i) { | ||
| 1234 | int pending; | ||
| 1235 | v = per_cpu(xen_vcpu, i); | ||
| 1236 | pending = (get_irq_regs() && i == cpu) | ||
| 1237 | ? xen_irqs_disabled(get_irq_regs()) | ||
| 1238 | : v->evtchn_upcall_mask; | ||
| 1239 | printk("%d: masked=%d pending=%d event_sel %0*"PRI_xen_ulong"\n ", i, | ||
| 1240 | pending, v->evtchn_upcall_pending, | ||
| 1241 | (int)(sizeof(v->evtchn_pending_sel)*2), | ||
| 1242 | v->evtchn_pending_sel); | ||
| 1243 | } | ||
| 1244 | v = per_cpu(xen_vcpu, cpu); | ||
| 1245 | |||
| 1246 | printk("\npending:\n "); | ||
| 1247 | for (i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--) | ||
| 1248 | printk("%0*"PRI_xen_ulong"%s", | ||
| 1249 | (int)sizeof(sh->evtchn_pending[0])*2, | ||
| 1250 | sh->evtchn_pending[i], | ||
| 1251 | i % 8 == 0 ? "\n " : " "); | ||
| 1252 | printk("\nglobal mask:\n "); | ||
| 1253 | for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) | ||
| 1254 | printk("%0*"PRI_xen_ulong"%s", | ||
| 1255 | (int)(sizeof(sh->evtchn_mask[0])*2), | ||
| 1256 | sh->evtchn_mask[i], | ||
| 1257 | i % 8 == 0 ? "\n " : " "); | ||
| 1258 | |||
| 1259 | printk("\nglobally unmasked:\n "); | ||
| 1260 | for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) | ||
| 1261 | printk("%0*"PRI_xen_ulong"%s", | ||
| 1262 | (int)(sizeof(sh->evtchn_mask[0])*2), | ||
| 1263 | sh->evtchn_pending[i] & ~sh->evtchn_mask[i], | ||
| 1264 | i % 8 == 0 ? "\n " : " "); | ||
| 1265 | |||
| 1266 | printk("\nlocal cpu%d mask:\n ", cpu); | ||
| 1267 | for (i = (NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD)-1; i >= 0; i--) | ||
| 1268 | printk("%0*"PRI_xen_ulong"%s", (int)(sizeof(cpu_evtchn[0])*2), | ||
| 1269 | cpu_evtchn[i], | ||
| 1270 | i % 8 == 0 ? "\n " : " "); | ||
| 1271 | |||
| 1272 | printk("\nlocally unmasked:\n "); | ||
| 1273 | for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) { | ||
| 1274 | xen_ulong_t pending = sh->evtchn_pending[i] | ||
| 1275 | & ~sh->evtchn_mask[i] | ||
| 1276 | & cpu_evtchn[i]; | ||
| 1277 | printk("%0*"PRI_xen_ulong"%s", | ||
| 1278 | (int)(sizeof(sh->evtchn_mask[0])*2), | ||
| 1279 | pending, i % 8 == 0 ? "\n " : " "); | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | printk("\npending list:\n"); | ||
| 1283 | for (i = 0; i < NR_EVENT_CHANNELS; i++) { | ||
| 1284 | if (sync_test_bit(i, BM(sh->evtchn_pending))) { | ||
| 1285 | int word_idx = i / BITS_PER_EVTCHN_WORD; | ||
| 1286 | printk(" %d: event %d -> irq %d%s%s%s\n", | ||
| 1287 | cpu_from_evtchn(i), i, | ||
| 1288 | evtchn_to_irq[i], | ||
| 1289 | sync_test_bit(word_idx, BM(&v->evtchn_pending_sel)) | ||
| 1290 | ? "" : " l2-clear", | ||
| 1291 | !sync_test_bit(i, BM(sh->evtchn_mask)) | ||
| 1292 | ? "" : " globally-masked", | ||
| 1293 | sync_test_bit(i, BM(cpu_evtchn)) | ||
| 1294 | ? "" : " locally-masked"); | ||
| 1295 | } | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | spin_unlock_irqrestore(&debug_lock, flags); | ||
| 1299 | |||
| 1300 | return IRQ_HANDLED; | ||
| 1301 | } | ||
| 1302 | |||
| 1303 | static DEFINE_PER_CPU(unsigned, xed_nesting_count); | 1075 | static DEFINE_PER_CPU(unsigned, xed_nesting_count); |
| 1304 | static DEFINE_PER_CPU(unsigned int, current_word_idx); | ||
| 1305 | static DEFINE_PER_CPU(unsigned int, current_bit_idx); | ||
| 1306 | 1076 | ||
| 1307 | /* | ||
| 1308 | * Mask out the i least significant bits of w | ||
| 1309 | */ | ||
| 1310 | #define MASK_LSBS(w, i) (w & ((~((xen_ulong_t)0UL)) << i)) | ||
| 1311 | |||
| 1312 | /* | ||
| 1313 | * Search the CPUs pending events bitmasks. For each one found, map | ||
| 1314 | * the event number to an irq, and feed it into do_IRQ() for | ||
| 1315 | * handling. | ||
| 1316 | * | ||
| 1317 | * Xen uses a two-level bitmap to speed searching. The first level is | ||
| 1318 | * a bitset of words which contain pending event bits. The second | ||
| 1319 | * level is a bitset of pending events themselves. | ||
| 1320 | */ | ||
| 1321 | static void __xen_evtchn_do_upcall(void) | 1077 | static void __xen_evtchn_do_upcall(void) |
| 1322 | { | 1078 | { |
| 1323 | int start_word_idx, start_bit_idx; | ||
| 1324 | int word_idx, bit_idx; | ||
| 1325 | int i, irq; | ||
| 1326 | int cpu = get_cpu(); | ||
| 1327 | struct shared_info *s = HYPERVISOR_shared_info; | ||
| 1328 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); | 1079 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); |
| 1080 | int cpu = get_cpu(); | ||
| 1329 | unsigned count; | 1081 | unsigned count; |
| 1330 | 1082 | ||
| 1331 | do { | 1083 | do { |
| 1332 | xen_ulong_t pending_words; | ||
| 1333 | xen_ulong_t pending_bits; | ||
| 1334 | struct irq_desc *desc; | ||
| 1335 | |||
| 1336 | vcpu_info->evtchn_upcall_pending = 0; | 1084 | vcpu_info->evtchn_upcall_pending = 0; |
| 1337 | 1085 | ||
| 1338 | if (__this_cpu_inc_return(xed_nesting_count) - 1) | 1086 | if (__this_cpu_inc_return(xed_nesting_count) - 1) |
| 1339 | goto out; | 1087 | goto out; |
| 1340 | 1088 | ||
| 1341 | /* | 1089 | xen_evtchn_handle_events(cpu); |
| 1342 | * Master flag must be cleared /before/ clearing | ||
| 1343 | * selector flag. xchg_xen_ulong must contain an | ||
| 1344 | * appropriate barrier. | ||
| 1345 | */ | ||
| 1346 | if ((irq = per_cpu(virq_to_irq, cpu)[VIRQ_TIMER]) != -1) { | ||
| 1347 | int evtchn = evtchn_from_irq(irq); | ||
| 1348 | word_idx = evtchn / BITS_PER_LONG; | ||
| 1349 | pending_bits = evtchn % BITS_PER_LONG; | ||
| 1350 | if (active_evtchns(cpu, s, word_idx) & (1ULL << pending_bits)) { | ||
| 1351 | desc = irq_to_desc(irq); | ||
| 1352 | if (desc) | ||
| 1353 | generic_handle_irq_desc(irq, desc); | ||
| 1354 | } | ||
| 1355 | } | ||
| 1356 | |||
| 1357 | pending_words = xchg_xen_ulong(&vcpu_info->evtchn_pending_sel, 0); | ||
| 1358 | |||
| 1359 | start_word_idx = __this_cpu_read(current_word_idx); | ||
| 1360 | start_bit_idx = __this_cpu_read(current_bit_idx); | ||
| 1361 | |||
| 1362 | word_idx = start_word_idx; | ||
| 1363 | |||
| 1364 | for (i = 0; pending_words != 0; i++) { | ||
| 1365 | xen_ulong_t words; | ||
| 1366 | |||
| 1367 | words = MASK_LSBS(pending_words, word_idx); | ||
| 1368 | |||
| 1369 | /* | ||
| 1370 | * If we masked out all events, wrap to beginning. | ||
| 1371 | */ | ||
| 1372 | if (words == 0) { | ||
| 1373 | word_idx = 0; | ||
| 1374 | bit_idx = 0; | ||
| 1375 | continue; | ||
| 1376 | } | ||
| 1377 | word_idx = EVTCHN_FIRST_BIT(words); | ||
| 1378 | |||
| 1379 | pending_bits = active_evtchns(cpu, s, word_idx); | ||
| 1380 | bit_idx = 0; /* usually scan entire word from start */ | ||
| 1381 | /* | ||
| 1382 | * We scan the starting word in two parts. | ||
| 1383 | * | ||
| 1384 | * 1st time: start in the middle, scanning the | ||
| 1385 | * upper bits. | ||
| 1386 | * | ||
| 1387 | * 2nd time: scan the whole word (not just the | ||
| 1388 | * parts skipped in the first pass) -- if an | ||
| 1389 | * event in the previously scanned bits is | ||
| 1390 | * pending again it would just be scanned on | ||
| 1391 | * the next loop anyway. | ||
| 1392 | */ | ||
| 1393 | if (word_idx == start_word_idx) { | ||
| 1394 | if (i == 0) | ||
| 1395 | bit_idx = start_bit_idx; | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | do { | ||
| 1399 | xen_ulong_t bits; | ||
| 1400 | int port; | ||
| 1401 | |||
| 1402 | bits = MASK_LSBS(pending_bits, bit_idx); | ||
| 1403 | |||
| 1404 | /* If we masked out all events, move on. */ | ||
| 1405 | if (bits == 0) | ||
| 1406 | break; | ||
| 1407 | |||
| 1408 | bit_idx = EVTCHN_FIRST_BIT(bits); | ||
| 1409 | |||
| 1410 | /* Process port. */ | ||
| 1411 | port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx; | ||
| 1412 | irq = evtchn_to_irq[port]; | ||
| 1413 | |||
| 1414 | if (irq != -1) { | ||
| 1415 | desc = irq_to_desc(irq); | ||
| 1416 | if (desc) | ||
| 1417 | generic_handle_irq_desc(irq, desc); | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | bit_idx = (bit_idx + 1) % BITS_PER_EVTCHN_WORD; | ||
| 1421 | |||
| 1422 | /* Next caller starts at last processed + 1 */ | ||
| 1423 | __this_cpu_write(current_word_idx, | ||
| 1424 | bit_idx ? word_idx : | ||
| 1425 | (word_idx+1) % BITS_PER_EVTCHN_WORD); | ||
| 1426 | __this_cpu_write(current_bit_idx, bit_idx); | ||
| 1427 | } while (bit_idx != 0); | ||
| 1428 | |||
| 1429 | /* Scan start_l1i twice; all others once. */ | ||
| 1430 | if ((word_idx != start_word_idx) || (i != 0)) | ||
| 1431 | pending_words &= ~(1UL << word_idx); | ||
| 1432 | |||
| 1433 | word_idx = (word_idx + 1) % BITS_PER_EVTCHN_WORD; | ||
| 1434 | } | ||
| 1435 | 1090 | ||
| 1436 | BUG_ON(!irqs_disabled()); | 1091 | BUG_ON(!irqs_disabled()); |
| 1437 | 1092 | ||
diff --git a/drivers/xen/events/events_internal.h b/drivers/xen/events/events_internal.h new file mode 100644 index 000000000000..79ac70bbbd26 --- /dev/null +++ b/drivers/xen/events/events_internal.h | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | /* | ||
| 2 | * Xen Event Channels (internal header) | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Citrix Systems R&D Ltd. | ||
| 5 | * | ||
| 6 | * This source code is licensed under the GNU General Public License, | ||
| 7 | * Version 2 or later. See the file COPYING for more details. | ||
| 8 | */ | ||
| 9 | #ifndef __EVENTS_INTERNAL_H__ | ||
| 10 | #define __EVENTS_INTERNAL_H__ | ||
| 11 | |||
| 12 | /* Interrupt types. */ | ||
| 13 | enum xen_irq_type { | ||
| 14 | IRQT_UNBOUND = 0, | ||
| 15 | IRQT_PIRQ, | ||
| 16 | IRQT_VIRQ, | ||
| 17 | IRQT_IPI, | ||
| 18 | IRQT_EVTCHN | ||
| 19 | }; | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Packed IRQ information: | ||
| 23 | * type - enum xen_irq_type | ||
| 24 | * event channel - irq->event channel mapping | ||
| 25 | * cpu - cpu this event channel is bound to | ||
| 26 | * index - type-specific information: | ||
| 27 | * PIRQ - vector, with MSB being "needs EIO", or physical IRQ of the HVM | ||
| 28 | * guest, or GSI (real passthrough IRQ) of the device. | ||
| 29 | * VIRQ - virq number | ||
| 30 | * IPI - IPI vector | ||
| 31 | * EVTCHN - | ||
| 32 | */ | ||
| 33 | struct irq_info { | ||
| 34 | struct list_head list; | ||
| 35 | int refcnt; | ||
| 36 | enum xen_irq_type type; /* type */ | ||
| 37 | unsigned irq; | ||
| 38 | unsigned short evtchn; /* event channel */ | ||
| 39 | unsigned short cpu; /* cpu bound */ | ||
| 40 | |||
| 41 | union { | ||
| 42 | unsigned short virq; | ||
| 43 | enum ipi_vector ipi; | ||
| 44 | struct { | ||
| 45 | unsigned short pirq; | ||
| 46 | unsigned short gsi; | ||
| 47 | unsigned char vector; | ||
| 48 | unsigned char flags; | ||
| 49 | uint16_t domid; | ||
| 50 | } pirq; | ||
| 51 | } u; | ||
| 52 | }; | ||
| 53 | |||
| 54 | #define PIRQ_NEEDS_EOI (1 << 0) | ||
| 55 | #define PIRQ_SHAREABLE (1 << 1) | ||
| 56 | |||
| 57 | extern int *evtchn_to_irq; | ||
| 58 | |||
| 59 | struct irq_info *info_for_irq(unsigned irq); | ||
| 60 | unsigned cpu_from_irq(unsigned irq); | ||
| 61 | unsigned cpu_from_evtchn(unsigned int evtchn); | ||
| 62 | |||
| 63 | void xen_evtchn_port_bind_to_cpu(struct irq_info *info, int cpu); | ||
| 64 | |||
| 65 | void clear_evtchn(int port); | ||
| 66 | void set_evtchn(int port); | ||
| 67 | int test_evtchn(int port); | ||
| 68 | int test_and_set_mask(int port); | ||
| 69 | void mask_evtchn(int port); | ||
| 70 | void unmask_evtchn(int port); | ||
| 71 | |||
| 72 | void xen_evtchn_handle_events(int cpu); | ||
| 73 | |||
| 74 | #endif /* #ifndef __EVENTS_INTERNAL_H__ */ | ||
