diff options
Diffstat (limited to 'drivers/xen/events/events_fifo.c')
-rw-r--r-- | drivers/xen/events/events_fifo.c | 88 |
1 files changed, 57 insertions, 31 deletions
diff --git a/drivers/xen/events/events_fifo.c b/drivers/xen/events/events_fifo.c index 1de2a191b395..ef7d446e07ee 100644 --- a/drivers/xen/events/events_fifo.c +++ b/drivers/xen/events/events_fifo.c @@ -66,7 +66,21 @@ static DEFINE_PER_CPU(struct evtchn_fifo_queue, cpu_queue); static event_word_t *event_array[MAX_EVENT_ARRAY_PAGES] __read_mostly; static unsigned event_array_pages __read_mostly; +/* + * sync_set_bit() and friends must be unsigned long aligned. + */ +#if BITS_PER_LONG > 32 + +#define BM(w) (unsigned long *)((unsigned long)w & ~0x7UL) +#define EVTCHN_FIFO_BIT(b, w) \ + (((unsigned long)w & 0x4UL) ? (EVTCHN_FIFO_ ##b + 32) : EVTCHN_FIFO_ ##b) + +#else + #define BM(w) ((unsigned long *)(w)) +#define EVTCHN_FIFO_BIT(b, w) EVTCHN_FIFO_ ##b + +#endif static inline event_word_t *event_word_from_port(unsigned port) { @@ -85,6 +99,25 @@ static unsigned evtchn_fifo_nr_channels(void) return event_array_pages * EVENT_WORDS_PER_PAGE; } +static int init_control_block(int cpu, + struct evtchn_fifo_control_block *control_block) +{ + struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu); + struct evtchn_init_control init_control; + unsigned int i; + + /* Reset the control block and the local HEADs. */ + clear_page(control_block); + for (i = 0; i < EVTCHN_FIFO_MAX_QUEUES; i++) + q->head[i] = 0; + + init_control.control_gfn = virt_to_mfn(control_block); + init_control.offset = 0; + init_control.vcpu = cpu; + + return HYPERVISOR_event_channel_op(EVTCHNOP_init_control, &init_control); +} + static void free_unused_array_pages(void) { unsigned i; @@ -161,33 +194,38 @@ static void evtchn_fifo_bind_to_cpu(struct irq_info *info, unsigned cpu) static void evtchn_fifo_clear_pending(unsigned port) { event_word_t *word = event_word_from_port(port); - sync_clear_bit(EVTCHN_FIFO_PENDING, BM(word)); + sync_clear_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word)); } static void evtchn_fifo_set_pending(unsigned port) { event_word_t *word = event_word_from_port(port); - sync_set_bit(EVTCHN_FIFO_PENDING, BM(word)); + sync_set_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word)); } static bool evtchn_fifo_is_pending(unsigned port) { event_word_t *word = event_word_from_port(port); - return sync_test_bit(EVTCHN_FIFO_PENDING, BM(word)); + return sync_test_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word)); } static bool evtchn_fifo_test_and_set_mask(unsigned port) { event_word_t *word = event_word_from_port(port); - return sync_test_and_set_bit(EVTCHN_FIFO_MASKED, BM(word)); + return sync_test_and_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word)); } static void evtchn_fifo_mask(unsigned port) { event_word_t *word = event_word_from_port(port); - sync_set_bit(EVTCHN_FIFO_MASKED, BM(word)); + sync_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word)); } +static bool evtchn_fifo_is_masked(unsigned port) +{ + event_word_t *word = event_word_from_port(port); + return sync_test_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word)); +} /* * Clear MASKED, spinning if BUSY is set. */ @@ -211,7 +249,7 @@ static void evtchn_fifo_unmask(unsigned port) BUG_ON(!irqs_disabled()); clear_masked(word); - if (sync_test_bit(EVTCHN_FIFO_PENDING, BM(word))) { + if (evtchn_fifo_is_pending(port)) { struct evtchn_unmask unmask = { .port = port }; (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask); } @@ -247,7 +285,7 @@ static void handle_irq_for_port(unsigned port) static void consume_one_event(unsigned cpu, struct evtchn_fifo_control_block *control_block, - unsigned priority, uint32_t *ready) + unsigned priority, unsigned long *ready) { struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu); uint32_t head; @@ -277,10 +315,9 @@ static void consume_one_event(unsigned cpu, * copy of the ready word. */ if (head == 0) - clear_bit(priority, BM(ready)); + clear_bit(priority, ready); - if (sync_test_bit(EVTCHN_FIFO_PENDING, BM(word)) - && !sync_test_bit(EVTCHN_FIFO_MASKED, BM(word))) + if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) handle_irq_for_port(port); q->head[priority] = head; @@ -289,7 +326,7 @@ static void consume_one_event(unsigned cpu, static void evtchn_fifo_handle_events(unsigned cpu) { struct evtchn_fifo_control_block *control_block; - uint32_t ready; + unsigned long ready; unsigned q; control_block = per_cpu(cpu_control_block, cpu); @@ -309,7 +346,6 @@ static void evtchn_fifo_resume(void) for_each_possible_cpu(cpu) { void *control_block = per_cpu(cpu_control_block, cpu); - struct evtchn_init_control init_control; int ret; if (!control_block) @@ -326,12 +362,7 @@ static void evtchn_fifo_resume(void) continue; } - init_control.control_gfn = virt_to_mfn(control_block); - init_control.offset = 0; - init_control.vcpu = cpu; - - ret = HYPERVISOR_event_channel_op(EVTCHNOP_init_control, - &init_control); + ret = init_control_block(cpu, control_block); if (ret < 0) BUG(); } @@ -359,30 +390,25 @@ static const struct evtchn_ops evtchn_ops_fifo = { .resume = evtchn_fifo_resume, }; -static int evtchn_fifo_init_control_block(unsigned cpu) +static int evtchn_fifo_alloc_control_block(unsigned cpu) { - struct page *control_block = NULL; - struct evtchn_init_control init_control; + void *control_block = NULL; int ret = -ENOMEM; - control_block = alloc_page(GFP_KERNEL|__GFP_ZERO); + control_block = (void *)__get_free_page(GFP_KERNEL); if (control_block == NULL) goto error; - init_control.control_gfn = virt_to_mfn(page_address(control_block)); - init_control.offset = 0; - init_control.vcpu = cpu; - - ret = HYPERVISOR_event_channel_op(EVTCHNOP_init_control, &init_control); + ret = init_control_block(cpu, control_block); if (ret < 0) goto error; - per_cpu(cpu_control_block, cpu) = page_address(control_block); + per_cpu(cpu_control_block, cpu) = control_block; return 0; error: - __free_page(control_block); + free_page((unsigned long)control_block); return ret; } @@ -396,7 +422,7 @@ static int evtchn_fifo_cpu_notification(struct notifier_block *self, switch (action) { case CPU_UP_PREPARE: if (!per_cpu(cpu_control_block, cpu)) - ret = evtchn_fifo_init_control_block(cpu); + ret = evtchn_fifo_alloc_control_block(cpu); break; default: break; @@ -413,7 +439,7 @@ int __init xen_evtchn_fifo_init(void) int cpu = get_cpu(); int ret; - ret = evtchn_fifo_init_control_block(cpu); + ret = evtchn_fifo_alloc_control_block(cpu); if (ret < 0) goto out; |