diff options
| -rw-r--r-- | drivers/xen/events/events_2l.c | 11 | ||||
| -rw-r--r-- | drivers/xen/events/events_base.c | 175 | ||||
| -rw-r--r-- | drivers/xen/events/events_internal.h | 18 |
3 files changed, 149 insertions, 55 deletions
diff --git a/drivers/xen/events/events_2l.c b/drivers/xen/events/events_2l.c index e55677cca745..ecb402a149e3 100644 --- a/drivers/xen/events/events_2l.c +++ b/drivers/xen/events/events_2l.c | |||
| @@ -41,6 +41,11 @@ | |||
| 41 | static DEFINE_PER_CPU(xen_ulong_t [NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD], | 41 | static DEFINE_PER_CPU(xen_ulong_t [NR_EVENT_CHANNELS/BITS_PER_EVTCHN_WORD], |
| 42 | cpu_evtchn_mask); | 42 | cpu_evtchn_mask); |
| 43 | 43 | ||
| 44 | static unsigned evtchn_2l_max_channels(void) | ||
| 45 | { | ||
| 46 | return NR_EVENT_CHANNELS; | ||
| 47 | } | ||
| 48 | |||
| 44 | static void evtchn_2l_bind_to_cpu(struct irq_info *info, unsigned cpu) | 49 | static void evtchn_2l_bind_to_cpu(struct irq_info *info, unsigned cpu) |
| 45 | { | 50 | { |
| 46 | clear_bit(info->evtchn, BM(per_cpu(cpu_evtchn_mask, info->cpu))); | 51 | clear_bit(info->evtchn, BM(per_cpu(cpu_evtchn_mask, info->cpu))); |
| @@ -238,7 +243,7 @@ static void evtchn_2l_handle_events(unsigned cpu) | |||
| 238 | 243 | ||
| 239 | /* Process port. */ | 244 | /* Process port. */ |
| 240 | port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx; | 245 | port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx; |
| 241 | irq = evtchn_to_irq[port]; | 246 | irq = get_evtchn_to_irq(port); |
| 242 | 247 | ||
| 243 | if (irq != -1) { | 248 | if (irq != -1) { |
| 244 | desc = irq_to_desc(irq); | 249 | desc = irq_to_desc(irq); |
| @@ -332,7 +337,7 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id) | |||
| 332 | int word_idx = i / BITS_PER_EVTCHN_WORD; | 337 | int word_idx = i / BITS_PER_EVTCHN_WORD; |
| 333 | printk(" %d: event %d -> irq %d%s%s%s\n", | 338 | printk(" %d: event %d -> irq %d%s%s%s\n", |
| 334 | cpu_from_evtchn(i), i, | 339 | cpu_from_evtchn(i), i, |
| 335 | evtchn_to_irq[i], | 340 | get_evtchn_to_irq(i), |
| 336 | sync_test_bit(word_idx, BM(&v->evtchn_pending_sel)) | 341 | sync_test_bit(word_idx, BM(&v->evtchn_pending_sel)) |
| 337 | ? "" : " l2-clear", | 342 | ? "" : " l2-clear", |
| 338 | !sync_test_bit(i, BM(sh->evtchn_mask)) | 343 | !sync_test_bit(i, BM(sh->evtchn_mask)) |
| @@ -348,6 +353,8 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id) | |||
| 348 | } | 353 | } |
| 349 | 354 | ||
| 350 | static const struct evtchn_ops evtchn_ops_2l = { | 355 | static const struct evtchn_ops evtchn_ops_2l = { |
| 356 | .max_channels = evtchn_2l_max_channels, | ||
| 357 | .nr_channels = evtchn_2l_max_channels, | ||
| 351 | .bind_to_cpu = evtchn_2l_bind_to_cpu, | 358 | .bind_to_cpu = evtchn_2l_bind_to_cpu, |
| 352 | .clear_pending = evtchn_2l_clear_pending, | 359 | .clear_pending = evtchn_2l_clear_pending, |
| 353 | .set_pending = evtchn_2l_set_pending, | 360 | .set_pending = evtchn_2l_set_pending, |
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 929eccb77270..a6906665de53 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c | |||
| @@ -77,12 +77,16 @@ static DEFINE_PER_CPU(int [NR_VIRQS], virq_to_irq) = {[0 ... NR_VIRQS-1] = -1}; | |||
| 77 | /* IRQ <-> IPI mapping */ | 77 | /* IRQ <-> IPI mapping */ |
| 78 | static DEFINE_PER_CPU(int [XEN_NR_IPIS], ipi_to_irq) = {[0 ... XEN_NR_IPIS-1] = -1}; | 78 | static DEFINE_PER_CPU(int [XEN_NR_IPIS], ipi_to_irq) = {[0 ... XEN_NR_IPIS-1] = -1}; |
| 79 | 79 | ||
| 80 | int *evtchn_to_irq; | 80 | int **evtchn_to_irq; |
| 81 | #ifdef CONFIG_X86 | 81 | #ifdef CONFIG_X86 |
| 82 | static unsigned long *pirq_eoi_map; | 82 | static unsigned long *pirq_eoi_map; |
| 83 | #endif | 83 | #endif |
| 84 | static bool (*pirq_needs_eoi)(unsigned irq); | 84 | static bool (*pirq_needs_eoi)(unsigned irq); |
| 85 | 85 | ||
| 86 | #define EVTCHN_ROW(e) (e / (PAGE_SIZE/sizeof(**evtchn_to_irq))) | ||
| 87 | #define EVTCHN_COL(e) (e % (PAGE_SIZE/sizeof(**evtchn_to_irq))) | ||
| 88 | #define EVTCHN_PER_ROW (PAGE_SIZE / sizeof(**evtchn_to_irq)) | ||
| 89 | |||
| 86 | /* Xen will never allocate port zero for any purpose. */ | 90 | /* Xen will never allocate port zero for any purpose. */ |
| 87 | #define VALID_EVTCHN(chn) ((chn) != 0) | 91 | #define VALID_EVTCHN(chn) ((chn) != 0) |
| 88 | 92 | ||
| @@ -92,6 +96,61 @@ static struct irq_chip xen_pirq_chip; | |||
| 92 | static void enable_dynirq(struct irq_data *data); | 96 | static void enable_dynirq(struct irq_data *data); |
| 93 | static void disable_dynirq(struct irq_data *data); | 97 | static void disable_dynirq(struct irq_data *data); |
| 94 | 98 | ||
| 99 | static void clear_evtchn_to_irq_row(unsigned row) | ||
| 100 | { | ||
| 101 | unsigned col; | ||
| 102 | |||
| 103 | for (col = 0; col < EVTCHN_PER_ROW; col++) | ||
| 104 | evtchn_to_irq[row][col] = -1; | ||
| 105 | } | ||
| 106 | |||
| 107 | static void clear_evtchn_to_irq_all(void) | ||
| 108 | { | ||
| 109 | unsigned row; | ||
| 110 | |||
| 111 | for (row = 0; row < EVTCHN_ROW(xen_evtchn_max_channels()); row++) { | ||
| 112 | if (evtchn_to_irq[row] == NULL) | ||
| 113 | continue; | ||
| 114 | clear_evtchn_to_irq_row(row); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | static int set_evtchn_to_irq(unsigned evtchn, unsigned irq) | ||
| 119 | { | ||
| 120 | unsigned row; | ||
| 121 | unsigned col; | ||
| 122 | |||
| 123 | if (evtchn >= xen_evtchn_max_channels()) | ||
| 124 | return -EINVAL; | ||
| 125 | |||
| 126 | row = EVTCHN_ROW(evtchn); | ||
| 127 | col = EVTCHN_COL(evtchn); | ||
| 128 | |||
| 129 | if (evtchn_to_irq[row] == NULL) { | ||
| 130 | /* Unallocated irq entries return -1 anyway */ | ||
| 131 | if (irq == -1) | ||
| 132 | return 0; | ||
| 133 | |||
| 134 | evtchn_to_irq[row] = (int *)get_zeroed_page(GFP_KERNEL); | ||
| 135 | if (evtchn_to_irq[row] == NULL) | ||
| 136 | return -ENOMEM; | ||
| 137 | |||
| 138 | clear_evtchn_to_irq_row(row); | ||
| 139 | } | ||
| 140 | |||
| 141 | evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)] = irq; | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | int get_evtchn_to_irq(unsigned evtchn) | ||
| 146 | { | ||
| 147 | if (evtchn >= xen_evtchn_max_channels()) | ||
| 148 | return -1; | ||
| 149 | if (evtchn_to_irq[EVTCHN_ROW(evtchn)] == NULL) | ||
| 150 | return -1; | ||
| 151 | return evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)]; | ||
| 152 | } | ||
| 153 | |||
| 95 | /* Get info for IRQ */ | 154 | /* Get info for IRQ */ |
| 96 | struct irq_info *info_for_irq(unsigned irq) | 155 | struct irq_info *info_for_irq(unsigned irq) |
| 97 | { | 156 | { |
| @@ -102,9 +161,10 @@ struct irq_info *info_for_irq(unsigned irq) | |||
| 102 | static int xen_irq_info_common_setup(struct irq_info *info, | 161 | static int xen_irq_info_common_setup(struct irq_info *info, |
| 103 | unsigned irq, | 162 | unsigned irq, |
| 104 | enum xen_irq_type type, | 163 | enum xen_irq_type type, |
| 105 | unsigned short evtchn, | 164 | unsigned evtchn, |
| 106 | unsigned short cpu) | 165 | unsigned short cpu) |
| 107 | { | 166 | { |
| 167 | int ret; | ||
| 108 | 168 | ||
| 109 | BUG_ON(info->type != IRQT_UNBOUND && info->type != type); | 169 | BUG_ON(info->type != IRQT_UNBOUND && info->type != type); |
| 110 | 170 | ||
| @@ -113,7 +173,9 @@ static int xen_irq_info_common_setup(struct irq_info *info, | |||
| 113 | info->evtchn = evtchn; | 173 | info->evtchn = evtchn; |
| 114 | info->cpu = cpu; | 174 | info->cpu = cpu; |
| 115 | 175 | ||
| 116 | evtchn_to_irq[evtchn] = irq; | 176 | ret = set_evtchn_to_irq(evtchn, irq); |
| 177 | if (ret < 0) | ||
| 178 | return ret; | ||
| 117 | 179 | ||
| 118 | irq_clear_status_flags(irq, IRQ_NOREQUEST|IRQ_NOAUTOEN); | 180 | irq_clear_status_flags(irq, IRQ_NOREQUEST|IRQ_NOAUTOEN); |
| 119 | 181 | ||
| @@ -121,7 +183,7 @@ static int xen_irq_info_common_setup(struct irq_info *info, | |||
| 121 | } | 183 | } |
| 122 | 184 | ||
| 123 | static int xen_irq_info_evtchn_setup(unsigned irq, | 185 | static int xen_irq_info_evtchn_setup(unsigned irq, |
| 124 | unsigned short evtchn) | 186 | unsigned evtchn) |
| 125 | { | 187 | { |
| 126 | struct irq_info *info = info_for_irq(irq); | 188 | struct irq_info *info = info_for_irq(irq); |
| 127 | 189 | ||
| @@ -130,7 +192,7 @@ static int xen_irq_info_evtchn_setup(unsigned irq, | |||
| 130 | 192 | ||
| 131 | static int xen_irq_info_ipi_setup(unsigned cpu, | 193 | static int xen_irq_info_ipi_setup(unsigned cpu, |
| 132 | unsigned irq, | 194 | unsigned irq, |
| 133 | unsigned short evtchn, | 195 | unsigned evtchn, |
| 134 | enum ipi_vector ipi) | 196 | enum ipi_vector ipi) |
| 135 | { | 197 | { |
| 136 | struct irq_info *info = info_for_irq(irq); | 198 | struct irq_info *info = info_for_irq(irq); |
| @@ -144,8 +206,8 @@ static int xen_irq_info_ipi_setup(unsigned cpu, | |||
| 144 | 206 | ||
| 145 | static int xen_irq_info_virq_setup(unsigned cpu, | 207 | static int xen_irq_info_virq_setup(unsigned cpu, |
| 146 | unsigned irq, | 208 | unsigned irq, |
| 147 | unsigned short evtchn, | 209 | unsigned evtchn, |
| 148 | unsigned short virq) | 210 | unsigned virq) |
| 149 | { | 211 | { |
| 150 | struct irq_info *info = info_for_irq(irq); | 212 | struct irq_info *info = info_for_irq(irq); |
| 151 | 213 | ||
| @@ -157,9 +219,9 @@ static int xen_irq_info_virq_setup(unsigned cpu, | |||
| 157 | } | 219 | } |
| 158 | 220 | ||
| 159 | static int xen_irq_info_pirq_setup(unsigned irq, | 221 | static int xen_irq_info_pirq_setup(unsigned irq, |
| 160 | unsigned short evtchn, | 222 | unsigned evtchn, |
| 161 | unsigned short pirq, | 223 | unsigned pirq, |
| 162 | unsigned short gsi, | 224 | unsigned gsi, |
| 163 | uint16_t domid, | 225 | uint16_t domid, |
| 164 | unsigned char flags) | 226 | unsigned char flags) |
| 165 | { | 227 | { |
| @@ -173,6 +235,12 @@ static int xen_irq_info_pirq_setup(unsigned irq, | |||
| 173 | return xen_irq_info_common_setup(info, irq, IRQT_PIRQ, evtchn, 0); | 235 | return xen_irq_info_common_setup(info, irq, IRQT_PIRQ, evtchn, 0); |
| 174 | } | 236 | } |
| 175 | 237 | ||
| 238 | static void xen_irq_info_cleanup(struct irq_info *info) | ||
| 239 | { | ||
| 240 | set_evtchn_to_irq(info->evtchn, -1); | ||
| 241 | info->evtchn = 0; | ||
| 242 | } | ||
| 243 | |||
| 176 | /* | 244 | /* |
| 177 | * Accessors for packed IRQ information. | 245 | * Accessors for packed IRQ information. |
| 178 | */ | 246 | */ |
| @@ -186,7 +254,7 @@ unsigned int evtchn_from_irq(unsigned irq) | |||
| 186 | 254 | ||
| 187 | unsigned irq_from_evtchn(unsigned int evtchn) | 255 | unsigned irq_from_evtchn(unsigned int evtchn) |
| 188 | { | 256 | { |
| 189 | return evtchn_to_irq[evtchn]; | 257 | return get_evtchn_to_irq(evtchn); |
| 190 | } | 258 | } |
| 191 | EXPORT_SYMBOL_GPL(irq_from_evtchn); | 259 | EXPORT_SYMBOL_GPL(irq_from_evtchn); |
| 192 | 260 | ||
| @@ -237,7 +305,7 @@ unsigned cpu_from_irq(unsigned irq) | |||
| 237 | 305 | ||
| 238 | unsigned int cpu_from_evtchn(unsigned int evtchn) | 306 | unsigned int cpu_from_evtchn(unsigned int evtchn) |
| 239 | { | 307 | { |
| 240 | int irq = evtchn_to_irq[evtchn]; | 308 | int irq = get_evtchn_to_irq(evtchn); |
| 241 | unsigned ret = 0; | 309 | unsigned ret = 0; |
| 242 | 310 | ||
| 243 | if (irq != -1) | 311 | if (irq != -1) |
| @@ -263,7 +331,7 @@ static bool pirq_needs_eoi_flag(unsigned irq) | |||
| 263 | 331 | ||
| 264 | static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) | 332 | static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) |
| 265 | { | 333 | { |
| 266 | int irq = evtchn_to_irq[chn]; | 334 | int irq = get_evtchn_to_irq(chn); |
| 267 | struct irq_info *info = info_for_irq(irq); | 335 | struct irq_info *info = info_for_irq(irq); |
| 268 | 336 | ||
| 269 | BUG_ON(irq == -1); | 337 | BUG_ON(irq == -1); |
| @@ -386,6 +454,18 @@ static void xen_free_irq(unsigned irq) | |||
| 386 | irq_free_desc(irq); | 454 | irq_free_desc(irq); |
| 387 | } | 455 | } |
| 388 | 456 | ||
| 457 | static void xen_evtchn_close(unsigned int port) | ||
| 458 | { | ||
| 459 | struct evtchn_close close; | ||
| 460 | |||
| 461 | close.port = port; | ||
| 462 | if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) | ||
| 463 | BUG(); | ||
| 464 | |||
| 465 | /* Closed ports are implicitly re-bound to VCPU0. */ | ||
| 466 | bind_evtchn_to_cpu(port, 0); | ||
| 467 | } | ||
| 468 | |||
| 389 | static void pirq_query_unmask(int irq) | 469 | static void pirq_query_unmask(int irq) |
| 390 | { | 470 | { |
| 391 | struct physdev_irq_status_query irq_status; | 471 | struct physdev_irq_status_query irq_status; |
| @@ -458,7 +538,13 @@ static unsigned int __startup_pirq(unsigned int irq) | |||
| 458 | 538 | ||
| 459 | pirq_query_unmask(irq); | 539 | pirq_query_unmask(irq); |
| 460 | 540 | ||
| 461 | evtchn_to_irq[evtchn] = irq; | 541 | rc = set_evtchn_to_irq(evtchn, irq); |
| 542 | if (rc != 0) { | ||
| 543 | pr_err("irq%d: Failed to set port to irq mapping (%d)\n", | ||
| 544 | irq, rc); | ||
| 545 | xen_evtchn_close(evtchn); | ||
| 546 | return 0; | ||
| 547 | } | ||
| 462 | bind_evtchn_to_cpu(evtchn, 0); | 548 | bind_evtchn_to_cpu(evtchn, 0); |
| 463 | info->evtchn = evtchn; | 549 | info->evtchn = evtchn; |
| 464 | 550 | ||
| @@ -476,10 +562,9 @@ static unsigned int startup_pirq(struct irq_data *data) | |||
| 476 | 562 | ||
| 477 | static void shutdown_pirq(struct irq_data *data) | 563 | static void shutdown_pirq(struct irq_data *data) |
| 478 | { | 564 | { |
| 479 | struct evtchn_close close; | ||
| 480 | unsigned int irq = data->irq; | 565 | unsigned int irq = data->irq; |
| 481 | struct irq_info *info = info_for_irq(irq); | 566 | struct irq_info *info = info_for_irq(irq); |
| 482 | int evtchn = evtchn_from_irq(irq); | 567 | unsigned evtchn = evtchn_from_irq(irq); |
| 483 | 568 | ||
| 484 | BUG_ON(info->type != IRQT_PIRQ); | 569 | BUG_ON(info->type != IRQT_PIRQ); |
| 485 | 570 | ||
| @@ -487,14 +572,8 @@ static void shutdown_pirq(struct irq_data *data) | |||
| 487 | return; | 572 | return; |
| 488 | 573 | ||
| 489 | mask_evtchn(evtchn); | 574 | mask_evtchn(evtchn); |
| 490 | 575 | xen_evtchn_close(evtchn); | |
| 491 | close.port = evtchn; | 576 | xen_irq_info_cleanup(info); |
| 492 | if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) | ||
| 493 | BUG(); | ||
| 494 | |||
| 495 | bind_evtchn_to_cpu(evtchn, 0); | ||
| 496 | evtchn_to_irq[evtchn] = -1; | ||
| 497 | info->evtchn = 0; | ||
| 498 | } | 577 | } |
| 499 | 578 | ||
| 500 | static void enable_pirq(struct irq_data *data) | 579 | static void enable_pirq(struct irq_data *data) |
| @@ -525,7 +604,6 @@ EXPORT_SYMBOL_GPL(xen_irq_from_gsi); | |||
| 525 | 604 | ||
| 526 | static void __unbind_from_irq(unsigned int irq) | 605 | static void __unbind_from_irq(unsigned int irq) |
| 527 | { | 606 | { |
| 528 | struct evtchn_close close; | ||
| 529 | int evtchn = evtchn_from_irq(irq); | 607 | int evtchn = evtchn_from_irq(irq); |
| 530 | struct irq_info *info = irq_get_handler_data(irq); | 608 | struct irq_info *info = irq_get_handler_data(irq); |
| 531 | 609 | ||
| @@ -536,27 +614,22 @@ static void __unbind_from_irq(unsigned int irq) | |||
| 536 | } | 614 | } |
| 537 | 615 | ||
| 538 | if (VALID_EVTCHN(evtchn)) { | 616 | if (VALID_EVTCHN(evtchn)) { |
| 539 | close.port = evtchn; | 617 | unsigned int cpu = cpu_from_irq(irq); |
| 540 | if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) | 618 | |
| 541 | BUG(); | 619 | xen_evtchn_close(evtchn); |
| 542 | 620 | ||
| 543 | switch (type_from_irq(irq)) { | 621 | switch (type_from_irq(irq)) { |
| 544 | case IRQT_VIRQ: | 622 | case IRQT_VIRQ: |
| 545 | per_cpu(virq_to_irq, cpu_from_evtchn(evtchn)) | 623 | per_cpu(virq_to_irq, cpu)[virq_from_irq(irq)] = -1; |
| 546 | [virq_from_irq(irq)] = -1; | ||
| 547 | break; | 624 | break; |
| 548 | case IRQT_IPI: | 625 | case IRQT_IPI: |
| 549 | per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn)) | 626 | per_cpu(ipi_to_irq, cpu)[ipi_from_irq(irq)] = -1; |
| 550 | [ipi_from_irq(irq)] = -1; | ||
| 551 | break; | 627 | break; |
| 552 | default: | 628 | default: |
| 553 | break; | 629 | break; |
| 554 | } | 630 | } |
| 555 | 631 | ||
| 556 | /* Closed ports are implicitly re-bound to VCPU0. */ | 632 | xen_irq_info_cleanup(info); |
| 557 | bind_evtchn_to_cpu(evtchn, 0); | ||
| 558 | |||
| 559 | evtchn_to_irq[evtchn] = -1; | ||
| 560 | } | 633 | } |
| 561 | 634 | ||
| 562 | BUG_ON(info_for_irq(irq)->type == IRQT_UNBOUND); | 635 | BUG_ON(info_for_irq(irq)->type == IRQT_UNBOUND); |
| @@ -760,9 +833,12 @@ int bind_evtchn_to_irq(unsigned int evtchn) | |||
| 760 | int irq; | 833 | int irq; |
| 761 | int ret; | 834 | int ret; |
| 762 | 835 | ||
| 836 | if (evtchn >= xen_evtchn_max_channels()) | ||
| 837 | return -ENOMEM; | ||
| 838 | |||
| 763 | mutex_lock(&irq_mapping_update_lock); | 839 | mutex_lock(&irq_mapping_update_lock); |
| 764 | 840 | ||
| 765 | irq = evtchn_to_irq[evtchn]; | 841 | irq = get_evtchn_to_irq(evtchn); |
| 766 | 842 | ||
| 767 | if (irq == -1) { | 843 | if (irq == -1) { |
| 768 | irq = xen_allocate_irq_dynamic(); | 844 | irq = xen_allocate_irq_dynamic(); |
| @@ -852,7 +928,7 @@ static int find_virq(unsigned int virq, unsigned int cpu) | |||
| 852 | int port, rc = -ENOENT; | 928 | int port, rc = -ENOENT; |
| 853 | 929 | ||
| 854 | memset(&status, 0, sizeof(status)); | 930 | memset(&status, 0, sizeof(status)); |
| 855 | for (port = 0; port <= NR_EVENT_CHANNELS; port++) { | 931 | for (port = 0; port < xen_evtchn_max_channels(); port++) { |
| 856 | status.dom = DOMID_SELF; | 932 | status.dom = DOMID_SELF; |
| 857 | status.port = port; | 933 | status.port = port; |
| 858 | rc = HYPERVISOR_event_channel_op(EVTCHNOP_status, &status); | 934 | rc = HYPERVISOR_event_channel_op(EVTCHNOP_status, &status); |
| @@ -1022,7 +1098,7 @@ EXPORT_SYMBOL_GPL(unbind_from_irqhandler); | |||
| 1022 | 1098 | ||
| 1023 | int evtchn_make_refcounted(unsigned int evtchn) | 1099 | int evtchn_make_refcounted(unsigned int evtchn) |
| 1024 | { | 1100 | { |
| 1025 | int irq = evtchn_to_irq[evtchn]; | 1101 | int irq = get_evtchn_to_irq(evtchn); |
| 1026 | struct irq_info *info; | 1102 | struct irq_info *info; |
| 1027 | 1103 | ||
| 1028 | if (irq == -1) | 1104 | if (irq == -1) |
| @@ -1047,12 +1123,12 @@ int evtchn_get(unsigned int evtchn) | |||
| 1047 | struct irq_info *info; | 1123 | struct irq_info *info; |
| 1048 | int err = -ENOENT; | 1124 | int err = -ENOENT; |
| 1049 | 1125 | ||
| 1050 | if (evtchn >= NR_EVENT_CHANNELS) | 1126 | if (evtchn >= xen_evtchn_max_channels()) |
| 1051 | return -EINVAL; | 1127 | return -EINVAL; |
| 1052 | 1128 | ||
| 1053 | mutex_lock(&irq_mapping_update_lock); | 1129 | mutex_lock(&irq_mapping_update_lock); |
| 1054 | 1130 | ||
| 1055 | irq = evtchn_to_irq[evtchn]; | 1131 | irq = get_evtchn_to_irq(evtchn); |
| 1056 | if (irq == -1) | 1132 | if (irq == -1) |
| 1057 | goto done; | 1133 | goto done; |
| 1058 | 1134 | ||
| @@ -1076,7 +1152,7 @@ EXPORT_SYMBOL_GPL(evtchn_get); | |||
| 1076 | 1152 | ||
| 1077 | void evtchn_put(unsigned int evtchn) | 1153 | void evtchn_put(unsigned int evtchn) |
| 1078 | { | 1154 | { |
| 1079 | int irq = evtchn_to_irq[evtchn]; | 1155 | int irq = get_evtchn_to_irq(evtchn); |
| 1080 | if (WARN_ON(irq == -1)) | 1156 | if (WARN_ON(irq == -1)) |
| 1081 | return; | 1157 | return; |
| 1082 | unbind_from_irq(irq); | 1158 | unbind_from_irq(irq); |
| @@ -1163,7 +1239,7 @@ void rebind_evtchn_irq(int evtchn, int irq) | |||
| 1163 | mutex_lock(&irq_mapping_update_lock); | 1239 | mutex_lock(&irq_mapping_update_lock); |
| 1164 | 1240 | ||
| 1165 | /* After resume the irq<->evtchn mappings are all cleared out */ | 1241 | /* After resume the irq<->evtchn mappings are all cleared out */ |
| 1166 | BUG_ON(evtchn_to_irq[evtchn] != -1); | 1242 | BUG_ON(get_evtchn_to_irq(evtchn) != -1); |
| 1167 | /* Expect irq to have been bound before, | 1243 | /* Expect irq to have been bound before, |
| 1168 | so there should be a proper type */ | 1244 | so there should be a proper type */ |
| 1169 | BUG_ON(info->type == IRQT_UNBOUND); | 1245 | BUG_ON(info->type == IRQT_UNBOUND); |
| @@ -1448,15 +1524,14 @@ void xen_irq_resume(void) | |||
| 1448 | struct irq_info *info; | 1524 | struct irq_info *info; |
| 1449 | 1525 | ||
| 1450 | /* New event-channel space is not 'live' yet. */ | 1526 | /* New event-channel space is not 'live' yet. */ |
| 1451 | for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) | 1527 | for (evtchn = 0; evtchn < xen_evtchn_nr_channels(); evtchn++) |
| 1452 | mask_evtchn(evtchn); | 1528 | mask_evtchn(evtchn); |
| 1453 | 1529 | ||
| 1454 | /* No IRQ <-> event-channel mappings. */ | 1530 | /* No IRQ <-> event-channel mappings. */ |
| 1455 | list_for_each_entry(info, &xen_irq_list_head, list) | 1531 | list_for_each_entry(info, &xen_irq_list_head, list) |
| 1456 | info->evtchn = 0; /* zap event-channel binding */ | 1532 | info->evtchn = 0; /* zap event-channel binding */ |
| 1457 | 1533 | ||
| 1458 | for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) | 1534 | clear_evtchn_to_irq_all(); |
| 1459 | evtchn_to_irq[evtchn] = -1; | ||
| 1460 | 1535 | ||
| 1461 | for_each_possible_cpu(cpu) { | 1536 | for_each_possible_cpu(cpu) { |
| 1462 | restore_cpu_virqs(cpu); | 1537 | restore_cpu_virqs(cpu); |
| @@ -1553,14 +1628,12 @@ void __init xen_init_IRQ(void) | |||
| 1553 | 1628 | ||
| 1554 | xen_evtchn_2l_init(); | 1629 | xen_evtchn_2l_init(); |
| 1555 | 1630 | ||
| 1556 | evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), | 1631 | evtchn_to_irq = kcalloc(EVTCHN_ROW(xen_evtchn_max_channels()), |
| 1557 | GFP_KERNEL); | 1632 | sizeof(*evtchn_to_irq), GFP_KERNEL); |
| 1558 | BUG_ON(!evtchn_to_irq); | 1633 | BUG_ON(!evtchn_to_irq); |
| 1559 | for (i = 0; i < NR_EVENT_CHANNELS; i++) | ||
| 1560 | evtchn_to_irq[i] = -1; | ||
| 1561 | 1634 | ||
| 1562 | /* No event channels are 'live' right now. */ | 1635 | /* No event channels are 'live' right now. */ |
| 1563 | for (i = 0; i < NR_EVENT_CHANNELS; i++) | 1636 | for (i = 0; i < xen_evtchn_nr_channels(); i++) |
| 1564 | mask_evtchn(i); | 1637 | mask_evtchn(i); |
| 1565 | 1638 | ||
| 1566 | pirq_needs_eoi = pirq_needs_eoi_flag; | 1639 | pirq_needs_eoi = pirq_needs_eoi_flag; |
diff --git a/drivers/xen/events/events_internal.h b/drivers/xen/events/events_internal.h index dc9650265e04..a3d9aeceda1a 100644 --- a/drivers/xen/events/events_internal.h +++ b/drivers/xen/events/events_internal.h | |||
| @@ -35,7 +35,7 @@ struct irq_info { | |||
| 35 | int refcnt; | 35 | int refcnt; |
| 36 | enum xen_irq_type type; /* type */ | 36 | enum xen_irq_type type; /* type */ |
| 37 | unsigned irq; | 37 | unsigned irq; |
| 38 | unsigned short evtchn; /* event channel */ | 38 | unsigned int evtchn; /* event channel */ |
| 39 | unsigned short cpu; /* cpu bound */ | 39 | unsigned short cpu; /* cpu bound */ |
| 40 | 40 | ||
| 41 | union { | 41 | union { |
| @@ -55,6 +55,9 @@ struct irq_info { | |||
| 55 | #define PIRQ_SHAREABLE (1 << 1) | 55 | #define PIRQ_SHAREABLE (1 << 1) |
| 56 | 56 | ||
| 57 | struct evtchn_ops { | 57 | struct evtchn_ops { |
| 58 | unsigned (*max_channels)(void); | ||
| 59 | unsigned (*nr_channels)(void); | ||
| 60 | |||
| 58 | int (*setup)(struct irq_info *info); | 61 | int (*setup)(struct irq_info *info); |
| 59 | void (*bind_to_cpu)(struct irq_info *info, unsigned cpu); | 62 | void (*bind_to_cpu)(struct irq_info *info, unsigned cpu); |
| 60 | 63 | ||
| @@ -70,12 +73,23 @@ struct evtchn_ops { | |||
| 70 | 73 | ||
| 71 | extern const struct evtchn_ops *evtchn_ops; | 74 | extern const struct evtchn_ops *evtchn_ops; |
| 72 | 75 | ||
| 73 | extern int *evtchn_to_irq; | 76 | extern int **evtchn_to_irq; |
| 77 | int get_evtchn_to_irq(unsigned int evtchn); | ||
| 74 | 78 | ||
| 75 | struct irq_info *info_for_irq(unsigned irq); | 79 | struct irq_info *info_for_irq(unsigned irq); |
| 76 | unsigned cpu_from_irq(unsigned irq); | 80 | unsigned cpu_from_irq(unsigned irq); |
| 77 | unsigned cpu_from_evtchn(unsigned int evtchn); | 81 | unsigned cpu_from_evtchn(unsigned int evtchn); |
| 78 | 82 | ||
| 83 | static inline unsigned xen_evtchn_max_channels(void) | ||
| 84 | { | ||
| 85 | return evtchn_ops->max_channels(); | ||
| 86 | } | ||
| 87 | |||
| 88 | static inline unsigned xen_evtchn_nr_channels(void) | ||
| 89 | { | ||
| 90 | return evtchn_ops->nr_channels(); | ||
| 91 | } | ||
| 92 | |||
| 79 | /* | 93 | /* |
| 80 | * Do any ABI specific setup for a bound event channel before it can | 94 | * Do any ABI specific setup for a bound event channel before it can |
| 81 | * be unmasked and used. | 95 | * be unmasked and used. |
