From ab7f863e4183057dc494f3180199934a9637d401 Mon Sep 17 00:00:00 2001 From: Scott Rixner Date: Thu, 3 Mar 2011 09:30:08 +0000 Subject: xen: events: Process event channels notifications in round-robin order. Avoids fairness issue resulting from domain 0 processing lowest numbered event channel first. Fixes bug #1115 "Event channel port scanning unfair". Bugzilla: http://bugzilla.xensource.com/bugzilla/show_bug.cgi?id=1115 Signed-off-by: Ian Campbell [ijc: forward ported from linux-2.6.18-xen.hg 324:7fe1c6d02a2b various variables have different names in this tree: l1 -> pending_words l2 -> pending_bits l1i -> word_idx l2i -> bit_idx] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 7 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 6befe6227159..75cc6f50bd29 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1027,6 +1027,11 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id) static DEFINE_PER_CPU(unsigned, xed_nesting_count); +/* + * Mask out the i least significant bits of w + */ +#define MASK_LSBS(w, i) (w & ((~0UL) << i)) + /* * Search the CPUs pending events bitmasks. For each one found, map * the event number to an irq, and feed it into do_IRQ() for @@ -1038,6 +1043,9 @@ static DEFINE_PER_CPU(unsigned, xed_nesting_count); */ static void __xen_evtchn_do_upcall(void) { + static unsigned int last_word_idx = BITS_PER_LONG - 1; + static unsigned int last_bit_idx = BITS_PER_LONG - 1; + int word_idx, bit_idx; int cpu = get_cpu(); struct shared_info *s = HYPERVISOR_shared_info; struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); @@ -1056,17 +1064,50 @@ static void __xen_evtchn_do_upcall(void) wmb(); #endif pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0); + + word_idx = last_word_idx; + bit_idx = last_bit_idx; + while (pending_words != 0) { unsigned long pending_bits; - int word_idx = __ffs(pending_words); - pending_words &= ~(1UL << word_idx); + unsigned long words; + + word_idx = (word_idx + 1) % BITS_PER_LONG; + words = MASK_LSBS(pending_words, word_idx); + + /* + * If we masked out all events, wrap around to the + * beginning. + */ + if (words == 0) { + word_idx = BITS_PER_LONG - 1; + bit_idx = BITS_PER_LONG - 1; + continue; + } + word_idx = __ffs(words); - while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) { - int bit_idx = __ffs(pending_bits); - int port = (word_idx * BITS_PER_LONG) + bit_idx; - int irq = evtchn_to_irq[port]; + do { + unsigned long bits; + int port, irq; struct irq_desc *desc; + pending_bits = active_evtchns(cpu, s, word_idx); + + bit_idx = (bit_idx + 1) % BITS_PER_LONG; + bits = MASK_LSBS(pending_bits, bit_idx); + + /* If we masked out all events, move on. */ + if (bits == 0) { + bit_idx = BITS_PER_LONG - 1; + break; + } + + bit_idx = __ffs(bits); + + /* Process port. */ + port = (word_idx * BITS_PER_LONG) + bit_idx; + irq = evtchn_to_irq[port]; + mask_evtchn(port); clear_evtchn(port); @@ -1075,7 +1116,24 @@ static void __xen_evtchn_do_upcall(void) if (desc) generic_handle_irq_desc(irq, desc); } - } + + /* + * If this is the final port processed, we'll + * pick up here+1 next time. + */ + last_word_idx = word_idx; + last_bit_idx = bit_idx; + + } while (bit_idx != BITS_PER_LONG - 1); + + pending_bits = active_evtchns(cpu, s, word_idx); + + /* + * We handled all ports, so we can clear the + * selector bit. + */ + if (pending_bits == 0) + pending_words &= ~(1UL << word_idx); } BUG_ON(!irqs_disabled()); -- cgit v1.2.3 From f1f4a323d46c90632a4d35d34f1d347ca7cb65f5 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 3 Mar 2011 09:29:36 +0000 Subject: xen: events: Make last processed event channel a per-cpu variable. Signed-off-by: Ian Campbell [ijc: forward ported from linux-2.6.18-xen.hg 325:b2768401db94] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 75cc6f50bd29..1fc3192468ef 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1026,6 +1026,8 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id) } static DEFINE_PER_CPU(unsigned, xed_nesting_count); +static DEFINE_PER_CPU(unsigned int, last_word_idx) = { BITS_PER_LONG - 1 }; +static DEFINE_PER_CPU(unsigned int, last_bit_idx) = { BITS_PER_LONG - 1 }; /* * Mask out the i least significant bits of w @@ -1043,8 +1045,6 @@ static DEFINE_PER_CPU(unsigned, xed_nesting_count); */ static void __xen_evtchn_do_upcall(void) { - static unsigned int last_word_idx = BITS_PER_LONG - 1; - static unsigned int last_bit_idx = BITS_PER_LONG - 1; int word_idx, bit_idx; int cpu = get_cpu(); struct shared_info *s = HYPERVISOR_shared_info; @@ -1065,8 +1065,8 @@ static void __xen_evtchn_do_upcall(void) #endif pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0); - word_idx = last_word_idx; - bit_idx = last_bit_idx; + word_idx = __this_cpu_read(last_word_idx); + bit_idx = __this_cpu_read(last_bit_idx); while (pending_words != 0) { unsigned long pending_bits; @@ -1121,9 +1121,8 @@ static void __xen_evtchn_do_upcall(void) * If this is the final port processed, we'll * pick up here+1 next time. */ - last_word_idx = word_idx; - last_bit_idx = bit_idx; - + __this_cpu_write(last_word_idx, word_idx); + __this_cpu_write(last_bit_idx, bit_idx); } while (bit_idx != BITS_PER_LONG - 1); pending_bits = active_evtchns(cpu, s, word_idx); -- cgit v1.2.3 From ada6814c878c4d95fc8ca1402e49effbf3cc319a Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 3 Mar 2011 10:01:11 +0000 Subject: xen: events: Clean up round-robin evtchn scan. Also fixes a couple of boundary cases. Signed-off-by: Keir Fraser Signed-off-by: Ian Campbell [ijc: forward ported from linux-2.6.18-xen.hg 988:c88a02a22a05] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 1fc3192468ef..c49cb6d6b838 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1026,8 +1026,8 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id) } static DEFINE_PER_CPU(unsigned, xed_nesting_count); -static DEFINE_PER_CPU(unsigned int, last_word_idx) = { BITS_PER_LONG - 1 }; -static DEFINE_PER_CPU(unsigned int, last_bit_idx) = { BITS_PER_LONG - 1 }; +static DEFINE_PER_CPU(unsigned int, current_word_idx); +static DEFINE_PER_CPU(unsigned int, current_bit_idx); /* * Mask out the i least significant bits of w @@ -1065,23 +1065,21 @@ static void __xen_evtchn_do_upcall(void) #endif pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0); - word_idx = __this_cpu_read(last_word_idx); - bit_idx = __this_cpu_read(last_bit_idx); + word_idx = __this_cpu_read(current_word_idx); + bit_idx = __this_cpu_read(current_bit_idx); while (pending_words != 0) { unsigned long pending_bits; unsigned long words; - word_idx = (word_idx + 1) % BITS_PER_LONG; words = MASK_LSBS(pending_words, word_idx); /* - * If we masked out all events, wrap around to the - * beginning. + * If we masked out all events, wrap to beginning. */ if (words == 0) { - word_idx = BITS_PER_LONG - 1; - bit_idx = BITS_PER_LONG - 1; + word_idx = 0; + bit_idx = 0; continue; } word_idx = __ffs(words); @@ -1093,14 +1091,11 @@ static void __xen_evtchn_do_upcall(void) pending_bits = active_evtchns(cpu, s, word_idx); - bit_idx = (bit_idx + 1) % BITS_PER_LONG; bits = MASK_LSBS(pending_bits, bit_idx); /* If we masked out all events, move on. */ - if (bits == 0) { - bit_idx = BITS_PER_LONG - 1; + if (bits == 0) break; - } bit_idx = __ffs(bits); @@ -1117,22 +1112,23 @@ static void __xen_evtchn_do_upcall(void) generic_handle_irq_desc(irq, desc); } - /* - * If this is the final port processed, we'll - * pick up here+1 next time. - */ - __this_cpu_write(last_word_idx, word_idx); - __this_cpu_write(last_bit_idx, bit_idx); - } while (bit_idx != BITS_PER_LONG - 1); + bit_idx = (bit_idx + 1) % BITS_PER_LONG; + + /* Next caller starts at last processed + 1 */ + __this_cpu_write(current_word_idx, + bit_idx ? word_idx : + (word_idx+1) % BITS_PER_LONG); + __this_cpu_write(current_bit_idx, bit_idx); + } while (bit_idx != 0); pending_bits = active_evtchns(cpu, s, word_idx); - /* - * We handled all ports, so we can clear the - * selector bit. - */ + /* If we handled all ports, clear the selector bit. */ if (pending_bits == 0) pending_words &= ~(1UL << word_idx); + + word_idx = (word_idx + 1) % BITS_PER_LONG; + bit_idx = 0; } BUG_ON(!irqs_disabled()); -- cgit v1.2.3 From 24b51c2f2de019a4596415e7bb1e92711127d0e0 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 3 Mar 2011 11:06:28 +0000 Subject: xen: events: Make round-robin scan fairer by snapshotting each l2 word once only (except for starting l2 word, which we scan in two parts). Signed-off-by: Keir Fraser Signed-off-by: Ian Campbell [ijc: forward ported from linux-2.6.18-xen.hg 990:427276ac595d] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index c49cb6d6b838..0c3f17ba3956 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1045,7 +1045,9 @@ static DEFINE_PER_CPU(unsigned int, current_bit_idx); */ static void __xen_evtchn_do_upcall(void) { + int start_word_idx, start_bit_idx; int word_idx, bit_idx; + int i; int cpu = get_cpu(); struct shared_info *s = HYPERVISOR_shared_info; struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); @@ -1065,10 +1067,12 @@ static void __xen_evtchn_do_upcall(void) #endif pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0); - word_idx = __this_cpu_read(current_word_idx); - bit_idx = __this_cpu_read(current_bit_idx); + start_word_idx = __this_cpu_read(current_word_idx); + start_bit_idx = __this_cpu_read(current_bit_idx); + + word_idx = start_word_idx; - while (pending_words != 0) { + for (i = 0; pending_words != 0; i++) { unsigned long pending_bits; unsigned long words; @@ -1084,13 +1088,23 @@ static void __xen_evtchn_do_upcall(void) } word_idx = __ffs(words); + pending_bits = active_evtchns(cpu, s, word_idx); + bit_idx = 0; /* usually scan entire word from start */ + if (word_idx == start_word_idx) { + /* We scan the starting word in two parts */ + if (i == 0) + /* 1st time: start in the middle */ + bit_idx = start_bit_idx; + else + /* 2nd time: mask bits done already */ + bit_idx &= (1UL << start_bit_idx) - 1; + } + do { unsigned long bits; int port, irq; struct irq_desc *desc; - pending_bits = active_evtchns(cpu, s, word_idx); - bits = MASK_LSBS(pending_bits, bit_idx); /* If we masked out all events, move on. */ @@ -1121,10 +1135,8 @@ static void __xen_evtchn_do_upcall(void) __this_cpu_write(current_bit_idx, bit_idx); } while (bit_idx != 0); - pending_bits = active_evtchns(cpu, s, word_idx); - - /* If we handled all ports, clear the selector bit. */ - if (pending_bits == 0) + /* Scan start_l1i twice; all others once. */ + if ((word_idx != start_word_idx) || (i != 0)) pending_words &= ~(1UL << word_idx); word_idx = (word_idx + 1) % BITS_PER_LONG; -- cgit v1.2.3 From 3b7bcdf2823a59438301a73af8d0d31439a8f3d9 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 3 Mar 2011 10:13:26 +0000 Subject: xen: events: Remove redundant clear of l2i at end of round-robin loop Signed-off-by: Keir Fraser Signed-off-by: Ian Campbell [ijc: forward ported from linux-2.6.18-xen.hg 991:9ba6d9f3fbc0] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0c3f17ba3956..8786e06c4180 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1140,7 +1140,6 @@ static void __xen_evtchn_do_upcall(void) pending_words &= ~(1UL << word_idx); word_idx = (word_idx + 1) % BITS_PER_LONG; - bit_idx = 0; } BUG_ON(!irqs_disabled()); -- cgit v1.2.3 From be49472f0460455e8e0d9e6593837e09cbcc9ad7 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:02 +0000 Subject: xen: events: separate two unrelated halves of if condition Clarifies which bit the comment applies to. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 6befe6227159..684b0950538a 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1143,10 +1143,14 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) struct evtchn_bind_vcpu bind_vcpu; int evtchn = evtchn_from_irq(irq); - /* events delivered via platform PCI interrupts are always - * routed to vcpu 0 */ - if (!VALID_EVTCHN(evtchn) || - (xen_hvm_domain() && !xen_have_vector_callback)) + if (!VALID_EVTCHN(evtchn)) + return -1; + + /* + * Events delivered via platform PCI interrupts are always + * routed to vcpu 0 and hence cannot be rebound. + */ + if (xen_hvm_domain() && !xen_have_vector_callback) return -1; /* Send future instances of this interrupt to other vcpu. */ -- cgit v1.2.3 From 653378acdd477a299f468e396c7719911ac57881 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:04 +0000 Subject: xen: events: simplify comment It is never valid assume any particular relationship between a Xen PIRQ number and and Linux IRQ number so there is no need to hedge when saying so. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 10 +++------- include/xen/events.h | 4 +--- 2 files changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 684b0950538a..0b27080b1918 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -583,13 +583,9 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name) return xen_map_pirq_gsi(gsi, gsi, shareable, name); } -/* xen_map_pirq_gsi might allocate irqs from the top down, as a - * consequence don't assume that the irq number returned has a low value - * or can be used as a pirq number unless you know otherwise. - * - * One notable exception is when xen_map_pirq_gsi is called passing an - * hardware gsi as argument, in that case the irq number returned - * matches the gsi number passed as second argument. +/* + * Do not make any assumptions regarding the relationship between the + * IRQ number returned here and the Xen pirq argument. * * Note: We don't assign an event channel until the irq actually started * up. Return an existing irq if we've already got one for the gsi. diff --git a/include/xen/events.h b/include/xen/events.h index 962da2ced5b4..f6fed9498aa3 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -68,9 +68,7 @@ int xen_set_callback_via(uint64_t via); void xen_evtchn_do_upcall(struct pt_regs *regs); void xen_hvm_evtchn_do_upcall(void); -/* Allocate an irq for a physical interrupt, given a gsi. "Legacy" - * GSIs are identity mapped; others are dynamically allocated as - * usual. */ +/* Allocate an irq for a physical interrupt, given a gsi. */ int xen_allocate_pirq(unsigned gsi, int shareable, char *name); int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name); -- cgit v1.2.3 From a0e181167ee4254988c8c89d26ffd8ef4cb7deb0 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:03 +0000 Subject: xen: events: fix xen_map_pirq_gsi error return Fix initial value of irq so that first goto out (if pirq or gsi arguments are too large) actually returns an error. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0b27080b1918..a9c154d1d2ff 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -592,7 +592,7 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name) */ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) { - int irq = 0; + int irq = -1; struct physdev_irq irq_op; spin_lock(&irq_mapping_update_lock); -- cgit v1.2.3 From 76465b2dafb8ce471f115b6af80f7a67a1fda377 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:05 +0000 Subject: xen: events: remove unused public functions I was unable to find any user of these functions in either the functionality pending for 2.6.39 or the xen/next-2.6.32 branch of xen.git An exception to this was xen_gsi_from_irq which did appear to be used in xen/next-2.6.32's pciback. However in the 2.6.39 version of pciback xen_pirq_from_irq is, correctly AFAICT, used instead. Only a minority of functions in events.h use "extern" so drop it from those places for consistency. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 20 -------------------- include/xen/events.h | 12 +++--------- 2 files changed, 3 insertions(+), 29 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index a9c154d1d2ff..d52defda53b1 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -222,16 +222,6 @@ static unsigned gsi_from_irq(unsigned irq) 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; @@ -716,16 +706,6 @@ out: return rc; } -int xen_vector_from_irq(unsigned irq) -{ - return vector_from_irq(irq); -} - -int xen_gsi_from_irq(unsigned irq) -{ - return gsi_from_irq(irq); -} - int xen_irq_from_pirq(unsigned pirq) { return pirq_to_irq[pirq]; diff --git a/include/xen/events.h b/include/xen/events.h index f6fed9498aa3..99a64f045732 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -41,9 +41,9 @@ static inline void notify_remote_via_evtchn(int port) (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); } -extern void notify_remote_via_irq(int irq); +void notify_remote_via_irq(int irq); -extern void xen_irq_resume(void); +void xen_irq_resume(void); /* Clear an irq's pending state, in preparation for polling on it */ void xen_clear_irq_pending(int irq); @@ -62,7 +62,7 @@ void xen_poll_irq_timeout(int irq, u64 timeout); unsigned irq_from_evtchn(unsigned int evtchn); /* Xen HVM evtchn vector callback */ -extern void xen_hvm_callback_vector(void); +void xen_hvm_callback_vector(void); extern int xen_have_vector_callback; int xen_set_callback_via(uint64_t via); void xen_evtchn_do_upcall(struct pt_regs *regs); @@ -81,12 +81,6 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, /* De-allocates the above mentioned physical interrupt. */ int xen_destroy_irq(int irq); -/* Return vector allocated to pirq */ -int xen_vector_from_irq(unsigned pirq); - -/* Return gsi allocated to pirq */ -int xen_gsi_from_irq(unsigned pirq); - /* Return irq from pirq */ int xen_irq_from_pirq(unsigned pirq); -- cgit v1.2.3 From 0a85226ff291a59b2d6596b28bbc4fe368ee5266 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:06 +0000 Subject: xen: events: rename restore_cpu_pirqs -> restore_pirqs There is nothing per-cpu about this function. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index d52defda53b1..e828456777e5 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1213,7 +1213,7 @@ static int retrigger_dynirq(struct irq_data *data) return ret; } -static void restore_cpu_pirqs(void) +static void restore_pirqs(void) { int pirq, rc, irq, gsi; struct physdev_map_pirq map_irq; @@ -1375,7 +1375,7 @@ void xen_irq_resume(void) restore_cpu_ipis(cpu); } - restore_cpu_pirqs(); + restore_pirqs(); } static struct irq_chip xen_dynamic_chip __read_mostly = { -- cgit v1.2.3 From f4d0635bf8894b7ba43d7a54733f3e26fe6ced2e Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:07 +0000 Subject: xen: events: refactor GSI pirq bindings functions Following the example set by xen_allocate_pirq_msi and xen_bind_pirq_msi_to_irq: xen_allocate_pirq becomes xen_allocate_pirq_gsi and now only allocates a pirq number and does not bind it. xen_map_pirq_gsi becomes xen_bind_pirq_gsi_to_irq and binds an existing pirq. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/pci/xen.c | 41 +++++++++++++++++++++++++++++------------ drivers/xen/events.c | 7 ++++--- include/xen/events.h | 10 +++++++--- 3 files changed, 40 insertions(+), 18 deletions(-) (limited to 'drivers/xen') diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 8c4085a95ef1..e37b407a0ee8 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -50,7 +50,7 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, name = "ioapic-level"; } - irq = xen_map_pirq_gsi(map_irq.pirq, gsi, shareable, name); + irq = xen_bind_pirq_gsi_to_irq(gsi, map_irq.pirq, shareable, name); printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq); @@ -237,6 +237,7 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev) { int rc; int share = 1; + int pirq; u8 gsi; rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi); @@ -246,13 +247,21 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev) return rc; } + rc = xen_allocate_pirq_gsi(gsi); + if (rc < 0) { + dev_warn(&dev->dev, "Xen PCI: failed to allocate a PIRQ for GSI%d: %d\n", + gsi, rc); + return rc; + } + pirq = rc; + if (gsi < NR_IRQS_LEGACY) share = 0; - rc = xen_allocate_pirq(gsi, share, "pcifront"); + rc = xen_bind_pirq_gsi_to_irq(gsi, pirq, share, "pcifront"); if (rc < 0) { - dev_warn(&dev->dev, "Xen PCI: failed to register GSI%d: %d\n", - gsi, rc); + dev_warn(&dev->dev, "Xen PCI: failed to bind GSI%d (PIRQ%d) to IRQ: %d\n", + gsi, pirq, rc); return rc; } @@ -309,7 +318,7 @@ int __init pci_xen_hvm_init(void) #ifdef CONFIG_XEN_DOM0 static int xen_register_pirq(u32 gsi, int triggering) { - int rc, irq; + int rc, pirq, irq = -1; struct physdev_map_pirq map_irq; int shareable = 0; char *name; @@ -325,17 +334,20 @@ static int xen_register_pirq(u32 gsi, int triggering) name = "ioapic-level"; } - irq = xen_allocate_pirq(gsi, shareable, name); - - printk(KERN_DEBUG "xen: --> irq=%d\n", irq); + pirq = xen_allocate_pirq_gsi(gsi); + if (pirq < 0) + goto out; + irq = xen_bind_pirq_gsi_to_irq(gsi, pirq, shareable, name); if (irq < 0) goto out; + printk(KERN_DEBUG "xen: --> pirq=%d -> irq=%d\n", pirq, irq); + map_irq.domid = DOMID_SELF; map_irq.type = MAP_PIRQ_TYPE_GSI; map_irq.index = gsi; - map_irq.pirq = irq; + map_irq.pirq = pirq; rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); if (rc) { @@ -422,13 +434,18 @@ static int __init pci_xen_initial_domain(void) void __init xen_setup_pirqs(void) { - int irq; + int pirq, irq; pci_xen_initial_domain(); if (0 == nr_ioapics) { - for (irq = 0; irq < NR_IRQS_LEGACY; irq++) - xen_allocate_pirq(irq, 0, "xt-pic"); + for (irq = 0; irq < NR_IRQS_LEGACY; irq++) { + pirq = xen_allocate_pirq_gsi(irq); + if (WARN(pirq < 0, + "Could not allocate PIRQ for legacy interrupt\n")) + break; + irq = xen_bind_pirq_gsi_to_irq(irq, pirq, 0, "xt-pic"); + } return; } diff --git a/drivers/xen/events.c b/drivers/xen/events.c index e828456777e5..a40b2a1c6255 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -568,9 +568,9 @@ static int find_irq_by_gsi(unsigned gsi) return -1; } -int xen_allocate_pirq(unsigned gsi, int shareable, char *name) +int xen_allocate_pirq_gsi(unsigned gsi) { - return xen_map_pirq_gsi(gsi, gsi, shareable, name); + return gsi; } /* @@ -580,7 +580,8 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name) * Note: We don't assign an event channel until the irq actually started * up. Return an existing irq if we've already got one for the gsi. */ -int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) +int xen_bind_pirq_gsi_to_irq(unsigned gsi, + unsigned pirq, int shareable, char *name) { int irq = -1; struct physdev_irq irq_op; diff --git a/include/xen/events.h b/include/xen/events.h index 99a64f045732..32ebebacee7f 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -68,12 +68,16 @@ int xen_set_callback_via(uint64_t via); void xen_evtchn_do_upcall(struct pt_regs *regs); void xen_hvm_evtchn_do_upcall(void); -/* Allocate an irq for a physical interrupt, given a gsi. */ -int xen_allocate_pirq(unsigned gsi, int shareable, char *name); -int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name); +/* Allocate a pirq for a physical interrupt, given a gsi. */ +int xen_allocate_pirq_gsi(unsigned gsi); +/* Bind a pirq for a physical interrupt to an irq. */ +int xen_bind_pirq_gsi_to_irq(unsigned gsi, + unsigned pirq, int shareable, char *name); #ifdef CONFIG_PCI_MSI +/* Allocate a pirq for a MSI style physical interrupt. */ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc); +/* Bind an PSI pirq to an irq. */ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, int pirq, int vector, const char *name); #endif -- cgit v1.2.3 From cb60d11427bbdd42c27edfa2ef1fa6344f455e1d Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:08 +0000 Subject: xen: events: use per-cpu variable for cpu_evtchn_mask I can't see any reason why it isn't already. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index a40b2a1c6255..2dffa43696d8 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -107,19 +107,9 @@ static struct irq_info *irq_info; static int *pirq_to_irq; static int *evtchn_to_irq; -struct cpu_evtchn_s { - unsigned long bits[NR_EVENT_CHANNELS/BITS_PER_LONG]; -}; - -static __initdata struct cpu_evtchn_s init_evtchn_mask = { - .bits[0 ... (NR_EVENT_CHANNELS/BITS_PER_LONG)-1] = ~0ul, -}; -static struct cpu_evtchn_s *cpu_evtchn_mask_p = &init_evtchn_mask; -static inline unsigned long *cpu_evtchn_mask(int cpu) -{ - return cpu_evtchn_mask_p[cpu].bits; -} +static DEFINE_PER_CPU(unsigned long [NR_EVENT_CHANNELS/BITS_PER_LONG], + cpu_evtchn_mask); /* Xen will never allocate port zero for any purpose. */ #define VALID_EVTCHN(chn) ((chn) != 0) @@ -257,7 +247,7 @@ static inline unsigned long active_evtchns(unsigned int cpu, unsigned int idx) { return (sh->evtchn_pending[idx] & - cpu_evtchn_mask(cpu)[idx] & + per_cpu(cpu_evtchn_mask, cpu)[idx] & ~sh->evtchn_mask[idx]); } @@ -270,8 +260,8 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu)); #endif - clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); - set_bit(chn, cpu_evtchn_mask(cpu)); + clear_bit(chn, per_cpu(cpu_evtchn_mask, cpu_from_irq(irq))); + set_bit(chn, per_cpu(cpu_evtchn_mask, cpu)); irq_info[irq].cpu = cpu; } @@ -289,8 +279,8 @@ static void init_evtchn_cpu_bindings(void) #endif for_each_possible_cpu(i) - memset(cpu_evtchn_mask(i), - (i == 0) ? ~0 : 0, sizeof(struct cpu_evtchn_s)); + memset(per_cpu(cpu_evtchn_mask, i), + (i == 0) ? ~0 : 0, sizeof(*per_cpu(cpu_evtchn_mask, i))); } @@ -925,7 +915,7 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id) { struct shared_info *sh = HYPERVISOR_shared_info; int cpu = smp_processor_id(); - unsigned long *cpu_evtchn = cpu_evtchn_mask(cpu); + unsigned long *cpu_evtchn = per_cpu(cpu_evtchn_mask, cpu); int i; unsigned long flags; static DEFINE_SPINLOCK(debug_lock); @@ -1462,8 +1452,6 @@ void __init xen_init_IRQ(void) { int i; - cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s), - GFP_KERNEL); irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); /* We are using nr_irqs as the maximum number of pirq available but -- cgit v1.2.3 From 9158c3588a0693ef11208f5961f0d6b0241694d8 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:09 +0000 Subject: xen: events: turn irq_info constructors into initialiser functions Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 104 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 38 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 2dffa43696d8..72725faa2e85 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -118,46 +118,76 @@ static struct irq_chip xen_dynamic_chip; static struct irq_chip xen_percpu_chip; static struct irq_chip xen_pirq_chip; -/* Constructor for packed IRQ information. */ -static struct irq_info mk_unbound_info(void) +/* Get info for IRQ */ +static struct irq_info *info_for_irq(unsigned irq) { - return (struct irq_info) { .type = IRQT_UNBOUND }; + return &irq_info[irq]; } -static struct irq_info mk_evtchn_info(unsigned short evtchn) +/* Constructors for packed IRQ information. */ +static void xen_irq_info_common_init(struct irq_info *info, + enum xen_irq_type type, + unsigned short evtchn, + unsigned short cpu) { - return (struct irq_info) { .type = IRQT_EVTCHN, .evtchn = evtchn, - .cpu = 0 }; + + BUG_ON(info->type != IRQT_UNBOUND && info->type != type); + + info->type = type; + info->evtchn = evtchn; + info->cpu = cpu; } -static struct irq_info mk_ipi_info(unsigned short evtchn, enum ipi_vector ipi) +static void xen_irq_info_evtchn_init(unsigned irq, + unsigned short evtchn) { - return (struct irq_info) { .type = IRQT_IPI, .evtchn = evtchn, - .cpu = 0, .u.ipi = ipi }; + struct irq_info *info = info_for_irq(irq); + + xen_irq_info_common_init(info, IRQT_EVTCHN, evtchn, 0); } -static struct irq_info mk_virq_info(unsigned short evtchn, unsigned short virq) +static void xen_irq_info_ipi_init(unsigned irq, + unsigned short evtchn, + enum ipi_vector ipi) { - return (struct irq_info) { .type = IRQT_VIRQ, .evtchn = evtchn, - .cpu = 0, .u.virq = virq }; + struct irq_info *info = info_for_irq(irq); + + xen_irq_info_common_init(info, IRQT_IPI, evtchn, 0); + + info->u.ipi = ipi; } -static struct irq_info mk_pirq_info(unsigned short evtchn, unsigned short pirq, - unsigned short gsi, unsigned short vector) +static void xen_irq_info_virq_init(unsigned irq, + unsigned short evtchn, + unsigned short virq) { - return (struct irq_info) { .type = IRQT_PIRQ, .evtchn = evtchn, - .cpu = 0, - .u.pirq = { .pirq = pirq, .gsi = gsi, .vector = vector } }; + struct irq_info *info = info_for_irq(irq); + + xen_irq_info_common_init(info, IRQT_VIRQ, evtchn, 0); + + info->u.virq = virq; } -/* - * Accessors for packed IRQ information. - */ -static struct irq_info *info_for_irq(unsigned irq) +static void xen_irq_info_pirq_init(unsigned irq, + unsigned short evtchn, + unsigned short pirq, + unsigned short gsi, + unsigned short vector, + unsigned char flags) { - return &irq_info[irq]; + struct irq_info *info = info_for_irq(irq); + + xen_irq_info_common_init(info, IRQT_PIRQ, evtchn, 0); + + info->u.pirq.pirq = pirq; + info->u.pirq.gsi = gsi; + info->u.pirq.vector = vector; + info->u.pirq.flags = flags; } +/* + * Accessors for packed IRQ information. + */ static unsigned int evtchn_from_irq(unsigned irq) { if (unlikely(WARN(irq < 0 || irq >= nr_irqs, "Invalid irq %d!\n", irq))) @@ -414,6 +444,8 @@ static int xen_allocate_irq_gsi(unsigned gsi) static void xen_free_irq(unsigned irq) { + irq_info[irq].type = IRQT_UNBOUND; + /* Legacy IRQ descriptors are managed by the arch. */ if (irq < NR_IRQS_LEGACY) return; @@ -610,8 +642,8 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, goto out; } - irq_info[irq] = mk_pirq_info(0, pirq, gsi, irq_op.vector); - irq_info[irq].u.pirq.flags |= shareable ? PIRQ_SHAREABLE : 0; + xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, + shareable ? PIRQ_SHAREABLE : 0); pirq_to_irq[pirq] = irq; out: @@ -649,7 +681,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, set_irq_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, name); - irq_info[irq] = mk_pirq_info(0, pirq, 0, vector); + xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0); pirq_to_irq[pirq] = irq; ret = set_irq_msi(irq, msidesc); if (ret < 0) @@ -688,8 +720,6 @@ int xen_destroy_irq(int irq) } pirq_to_irq[info->u.pirq.pirq] = -1; - irq_info[irq] = mk_unbound_info(); - xen_free_irq(irq); out: @@ -717,7 +747,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) handle_fasteoi_irq, "event"); evtchn_to_irq[evtchn] = irq; - irq_info[irq] = mk_evtchn_info(evtchn); + xen_irq_info_evtchn_init(irq, evtchn); } spin_unlock(&irq_mapping_update_lock); @@ -750,7 +780,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_ipi_info(evtchn, ipi); + xen_irq_info_ipi_init(irq, evtchn, ipi); per_cpu(ipi_to_irq, cpu)[ipi] = irq; bind_evtchn_to_cpu(evtchn, cpu); @@ -785,7 +815,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) evtchn = bind_virq.port; evtchn_to_irq[evtchn] = irq; - irq_info[irq] = mk_virq_info(evtchn, virq); + xen_irq_info_virq_init(irq, evtchn, virq); per_cpu(virq_to_irq, cpu)[virq] = irq; @@ -828,11 +858,9 @@ static void unbind_from_irq(unsigned int irq) evtchn_to_irq[evtchn] = -1; } - if (irq_info[irq].type != IRQT_UNBOUND) { - irq_info[irq] = mk_unbound_info(); + BUG_ON(irq_info[irq].type == IRQT_UNBOUND); - xen_free_irq(irq); - } + xen_free_irq(irq); spin_unlock(&irq_mapping_update_lock); } @@ -1093,7 +1121,7 @@ void rebind_evtchn_irq(int evtchn, int irq) BUG_ON(info->type == IRQT_UNBOUND); evtchn_to_irq[evtchn] = irq; - irq_info[irq] = mk_evtchn_info(evtchn); + xen_irq_info_evtchn_init(irq, evtchn); spin_unlock(&irq_mapping_update_lock); @@ -1229,7 +1257,7 @@ static void restore_pirqs(void) if (rc) { printk(KERN_WARNING "xen map irq failed gsi=%d irq=%d pirq=%d rc=%d\n", gsi, irq, pirq, rc); - irq_info[irq] = mk_unbound_info(); + xen_free_irq(irq); pirq_to_irq[pirq] = -1; continue; } @@ -1261,7 +1289,7 @@ static void restore_cpu_virqs(unsigned int cpu) /* Record the new mapping. */ evtchn_to_irq[evtchn] = irq; - irq_info[irq] = mk_virq_info(evtchn, virq); + xen_irq_info_virq_init(irq, evtchn, virq); bind_evtchn_to_cpu(evtchn, cpu); } } @@ -1286,7 +1314,7 @@ static void restore_cpu_ipis(unsigned int cpu) /* Record the new mapping. */ evtchn_to_irq[evtchn] = irq; - irq_info[irq] = mk_ipi_info(evtchn, ipi); + xen_irq_info_ipi_init(irq, evtchn, ipi); bind_evtchn_to_cpu(evtchn, cpu); } } -- cgit v1.2.3 From 3d4cfa3736f2f080d3bde4f4329b7b6a7544e093 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:10 +0000 Subject: xen: events: push setup of irq<->{evtchn,ipi,virq,pirq} maps into irq_info init functions Encapsulate setup of XXX_to_irq array in the relevant xen_irq_info_*_init function. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 72725faa2e85..cf372d41077d 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -126,6 +126,7 @@ static struct irq_info *info_for_irq(unsigned irq) /* Constructors for packed IRQ information. */ static void xen_irq_info_common_init(struct irq_info *info, + unsigned irq, enum xen_irq_type type, unsigned short evtchn, unsigned short cpu) @@ -136,6 +137,8 @@ static void xen_irq_info_common_init(struct irq_info *info, info->type = type; info->evtchn = evtchn; info->cpu = cpu; + + evtchn_to_irq[evtchn] = irq; } static void xen_irq_info_evtchn_init(unsigned irq, @@ -143,29 +146,35 @@ static void xen_irq_info_evtchn_init(unsigned irq, { struct irq_info *info = info_for_irq(irq); - xen_irq_info_common_init(info, IRQT_EVTCHN, evtchn, 0); + xen_irq_info_common_init(info, irq, IRQT_EVTCHN, evtchn, 0); } -static void xen_irq_info_ipi_init(unsigned irq, +static void xen_irq_info_ipi_init(unsigned cpu, + unsigned irq, unsigned short evtchn, enum ipi_vector ipi) { struct irq_info *info = info_for_irq(irq); - xen_irq_info_common_init(info, IRQT_IPI, evtchn, 0); + xen_irq_info_common_init(info, irq, IRQT_IPI, evtchn, 0); info->u.ipi = ipi; + + per_cpu(ipi_to_irq, cpu)[ipi] = irq; } -static void xen_irq_info_virq_init(unsigned irq, +static void xen_irq_info_virq_init(unsigned cpu, + unsigned irq, unsigned short evtchn, unsigned short virq) { struct irq_info *info = info_for_irq(irq); - xen_irq_info_common_init(info, IRQT_VIRQ, evtchn, 0); + xen_irq_info_common_init(info, irq, IRQT_VIRQ, evtchn, 0); info->u.virq = virq; + + per_cpu(virq_to_irq, cpu)[virq] = irq; } static void xen_irq_info_pirq_init(unsigned irq, @@ -177,12 +186,14 @@ static void xen_irq_info_pirq_init(unsigned irq, { struct irq_info *info = info_for_irq(irq); - xen_irq_info_common_init(info, IRQT_PIRQ, evtchn, 0); + xen_irq_info_common_init(info, irq, IRQT_PIRQ, evtchn, 0); info->u.pirq.pirq = pirq; info->u.pirq.gsi = gsi; info->u.pirq.vector = vector; info->u.pirq.flags = flags; + + pirq_to_irq[pirq] = irq; } /* @@ -644,7 +655,6 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, shareable ? PIRQ_SHAREABLE : 0); - pirq_to_irq[pirq] = irq; out: spin_unlock(&irq_mapping_update_lock); @@ -682,7 +692,6 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, handle_level_irq, name); xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0); - pirq_to_irq[pirq] = irq; ret = set_irq_msi(irq, msidesc); if (ret < 0) goto error_irq; @@ -746,7 +755,6 @@ int bind_evtchn_to_irq(unsigned int evtchn) set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, handle_fasteoi_irq, "event"); - evtchn_to_irq[evtchn] = irq; xen_irq_info_evtchn_init(irq, evtchn); } @@ -779,9 +787,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) BUG(); evtchn = bind_ipi.port; - evtchn_to_irq[evtchn] = irq; - xen_irq_info_ipi_init(irq, evtchn, ipi); - per_cpu(ipi_to_irq, cpu)[ipi] = irq; + xen_irq_info_ipi_init(cpu, irq, evtchn, ipi); bind_evtchn_to_cpu(evtchn, cpu); } @@ -814,10 +820,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) BUG(); evtchn = bind_virq.port; - evtchn_to_irq[evtchn] = irq; - xen_irq_info_virq_init(irq, evtchn, virq); - - per_cpu(virq_to_irq, cpu)[virq] = irq; + xen_irq_info_virq_init(cpu, irq, evtchn, virq); bind_evtchn_to_cpu(evtchn, cpu); } @@ -1120,7 +1123,6 @@ void rebind_evtchn_irq(int evtchn, int irq) so there should be a proper type */ BUG_ON(info->type == IRQT_UNBOUND); - evtchn_to_irq[evtchn] = irq; xen_irq_info_evtchn_init(irq, evtchn); spin_unlock(&irq_mapping_update_lock); @@ -1288,8 +1290,7 @@ static void restore_cpu_virqs(unsigned int cpu) evtchn = bind_virq.port; /* Record the new mapping. */ - evtchn_to_irq[evtchn] = irq; - xen_irq_info_virq_init(irq, evtchn, virq); + xen_irq_info_virq_init(cpu, irq, evtchn, virq); bind_evtchn_to_cpu(evtchn, cpu); } } @@ -1313,8 +1314,7 @@ static void restore_cpu_ipis(unsigned int cpu) evtchn = bind_ipi.port; /* Record the new mapping. */ - evtchn_to_irq[evtchn] = irq; - xen_irq_info_ipi_init(irq, evtchn, ipi); + xen_irq_info_ipi_init(cpu, irq, evtchn, ipi); bind_evtchn_to_cpu(evtchn, cpu); } } -- cgit v1.2.3 From 6cb6537d34a146c8f3e232da9ffd79ae1265fed3 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:11 +0000 Subject: xen: events: maintain a list of Xen interrupts In a PVHVM kernel not all interrupts are Xen interrupts (APIC interrupts can also be present). Currently we get away with walking over all interrupts because the lookup in the irq_info array simply returns IRQT_UNBOUND and we ignore it. However this array will be going away in a future patch so we need to manually track which interrupts have been allocated by the Xen events infrastructure. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 59 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 15 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index cf372d41077d..e119989ec15b 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -56,6 +56,8 @@ */ static DEFINE_SPINLOCK(irq_mapping_update_lock); +static LIST_HEAD(xen_irq_list_head); + /* IRQ <-> VIRQ mapping. */ static DEFINE_PER_CPU(int [NR_VIRQS], virq_to_irq) = {[0 ... NR_VIRQS-1] = -1}; @@ -85,7 +87,9 @@ enum xen_irq_type { */ struct irq_info { + struct list_head list; enum xen_irq_type type; /* type */ + unsigned irq; unsigned short evtchn; /* event channel */ unsigned short cpu; /* cpu bound */ @@ -135,6 +139,7 @@ static void xen_irq_info_common_init(struct irq_info *info, BUG_ON(info->type != IRQT_UNBOUND && info->type != type); info->type = type; + info->irq = irq; info->evtchn = evtchn; info->cpu = cpu; @@ -311,10 +316,11 @@ static void init_evtchn_cpu_bindings(void) { int i; #ifdef CONFIG_SMP - struct irq_desc *desc; + struct irq_info *info; /* By default all event channels notify CPU#0. */ - for_each_irq_desc(i, desc) { + list_for_each_entry(info, &xen_irq_list_head, list) { + struct irq_desc *desc = irq_to_desc(info->irq); cpumask_copy(desc->irq_data.affinity, cpumask_of(0)); } #endif @@ -397,6 +403,21 @@ static void unmask_evtchn(int port) put_cpu(); } +static void xen_irq_init(unsigned irq) +{ + struct irq_info *info; + struct irq_desc *desc = irq_to_desc(irq); + + /* By default all event channels notify CPU#0. */ + cpumask_copy(desc->irq_data.affinity, cpumask_of(0)); + + info = &irq_info[irq]; + + info->type = IRQT_UNBOUND; + + list_add_tail(&info->list, &xen_irq_list_head); +} + static int xen_allocate_irq_dynamic(void) { int first = 0; @@ -426,6 +447,8 @@ retry: if (irq < 0) panic("No available IRQ to bind to: increase nr_irqs!\n"); + xen_irq_init(irq); + return irq; } @@ -444,18 +467,25 @@ static int xen_allocate_irq_gsi(unsigned gsi) /* Legacy IRQ descriptors are already allocated by the arch. */ if (gsi < NR_IRQS_LEGACY) - return gsi; + irq = gsi; + else + irq = irq_alloc_desc_at(gsi, -1); - irq = irq_alloc_desc_at(gsi, -1); if (irq < 0) panic("Unable to allocate to IRQ%d (%d)\n", gsi, irq); + xen_irq_init(irq); + return irq; } static void xen_free_irq(unsigned irq) { - irq_info[irq].type = IRQT_UNBOUND; + struct irq_info *info = &irq_info[irq]; + + info->type = IRQT_UNBOUND; + + list_del(&info->list); /* Legacy IRQ descriptors are managed by the arch. */ if (irq < NR_IRQS_LEGACY) @@ -586,16 +616,14 @@ static void ack_pirq(struct irq_data *data) static int find_irq_by_gsi(unsigned gsi) { - int irq; - - for (irq = 0; irq < nr_irqs; irq++) { - struct irq_info *info = info_for_irq(irq); + struct irq_info *info; - if (info == NULL || info->type != IRQT_PIRQ) + list_for_each_entry(info, &xen_irq_list_head, list) { + if (info->type != IRQT_PIRQ) continue; - if (gsi_from_irq(irq) == gsi) - return irq; + if (info->u.pirq.gsi == gsi) + return info->irq; } return -1; @@ -1374,7 +1402,8 @@ void xen_poll_irq(int irq) void xen_irq_resume(void) { - unsigned int cpu, irq, evtchn; + unsigned int cpu, evtchn; + struct irq_info *info; init_evtchn_cpu_bindings(); @@ -1383,8 +1412,8 @@ void xen_irq_resume(void) mask_evtchn(evtchn); /* No IRQ <-> event-channel mappings. */ - for (irq = 0; irq < nr_irqs; irq++) - irq_info[irq].evtchn = 0; /* zap event-channel binding */ + list_for_each_entry(info, &xen_irq_list_head, list) + info->evtchn = 0; /* zap event-channel binding */ for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) evtchn_to_irq[evtchn] = -1; -- cgit v1.2.3 From ca62ce8cde36cde5a31af8f9bb23e6430700e437 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:12 +0000 Subject: xen: events: dynamically allocate irq info structures Removes nr_irq sized array allocation at start of day. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index e119989ec15b..002283e01749 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -107,7 +107,6 @@ struct irq_info #define PIRQ_NEEDS_EOI (1 << 0) #define PIRQ_SHAREABLE (1 << 1) -static struct irq_info *irq_info; static int *pirq_to_irq; static int *evtchn_to_irq; @@ -125,7 +124,7 @@ static struct irq_chip xen_pirq_chip; /* Get info for IRQ */ static struct irq_info *info_for_irq(unsigned irq) { - return &irq_info[irq]; + return get_irq_data(irq); } /* Constructors for packed IRQ information. */ @@ -309,7 +308,7 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) clear_bit(chn, per_cpu(cpu_evtchn_mask, cpu_from_irq(irq))); set_bit(chn, per_cpu(cpu_evtchn_mask, cpu)); - irq_info[irq].cpu = cpu; + info_for_irq(irq)->cpu = cpu; } static void init_evtchn_cpu_bindings(void) @@ -328,7 +327,6 @@ static void init_evtchn_cpu_bindings(void) for_each_possible_cpu(i) memset(per_cpu(cpu_evtchn_mask, i), (i == 0) ? ~0 : 0, sizeof(*per_cpu(cpu_evtchn_mask, i))); - } static inline void clear_evtchn(int port) @@ -411,10 +409,14 @@ static void xen_irq_init(unsigned irq) /* By default all event channels notify CPU#0. */ cpumask_copy(desc->irq_data.affinity, cpumask_of(0)); - info = &irq_info[irq]; + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) + panic("Unable to allocate metadata for IRQ%d\n", irq); info->type = IRQT_UNBOUND; + set_irq_data(irq, info); + list_add_tail(&info->list, &xen_irq_list_head); } @@ -481,12 +483,14 @@ static int xen_allocate_irq_gsi(unsigned gsi) static void xen_free_irq(unsigned irq) { - struct irq_info *info = &irq_info[irq]; - - info->type = IRQT_UNBOUND; + struct irq_info *info = get_irq_data(irq); list_del(&info->list); + set_irq_data(irq, NULL); + + kfree(info); + /* Legacy IRQ descriptors are managed by the arch. */ if (irq < NR_IRQS_LEGACY) return; @@ -649,10 +653,9 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, spin_lock(&irq_mapping_update_lock); - if ((pirq > nr_irqs) || (gsi > nr_irqs)) { - printk(KERN_WARNING "xen_map_pirq_gsi: %s %s is incorrect!\n", - pirq > nr_irqs ? "pirq" :"", - gsi > nr_irqs ? "gsi" : ""); + if (pirq > nr_irqs) { + printk(KERN_WARNING "xen_map_pirq_gsi: pirq %d > nr_irqs %d!\n", + pirq, nr_irqs); goto out; } @@ -889,7 +892,7 @@ static void unbind_from_irq(unsigned int irq) evtchn_to_irq[evtchn] = -1; } - BUG_ON(irq_info[irq].type == IRQT_UNBOUND); + BUG_ON(info_for_irq(irq)->type == IRQT_UNBOUND); xen_free_irq(irq); @@ -1509,8 +1512,6 @@ void __init xen_init_IRQ(void) { int i; - irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); - /* We are using nr_irqs as the maximum number of pirq available but * that number is actually chosen by Xen and we don't know exactly * what it is. Be careful choosing high pirq numbers. */ -- cgit v1.2.3 From 69c358ce377e998e3ababb494c2f8769dfb1715d Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:13 +0000 Subject: xen: events: remove use of nr_irqs as upper bound on number of pirqs There isn't really much relationship between the two, other than nr_irqs often being the larger of the two. Allows us to remove a nr_irqs sized array, the only users of this array are MSI setup and restore, neither of which are particularly performance critical. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 59 ++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 34 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 002283e01749..6782251e4029 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -107,8 +107,6 @@ struct irq_info #define PIRQ_NEEDS_EOI (1 << 0) #define PIRQ_SHAREABLE (1 << 1) -static int *pirq_to_irq; - static int *evtchn_to_irq; static DEFINE_PER_CPU(unsigned long [NR_EVENT_CHANNELS/BITS_PER_LONG], @@ -196,8 +194,6 @@ static void xen_irq_info_pirq_init(unsigned irq, info->u.pirq.gsi = gsi; info->u.pirq.vector = vector; info->u.pirq.flags = flags; - - pirq_to_irq[pirq] = irq; } /* @@ -247,16 +243,6 @@ static unsigned pirq_from_irq(unsigned irq) return info->u.pirq.pirq; } -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 enum xen_irq_type type_from_irq(unsigned irq) { return info_for_irq(irq)->type; @@ -653,12 +639,6 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, spin_lock(&irq_mapping_update_lock); - if (pirq > nr_irqs) { - printk(KERN_WARNING "xen_map_pirq_gsi: pirq %d > nr_irqs %d!\n", - pirq, nr_irqs); - goto out; - } - irq = find_irq_by_gsi(gsi); if (irq != -1) { printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n", @@ -758,7 +738,6 @@ int xen_destroy_irq(int irq) goto out; } } - pirq_to_irq[info->u.pirq.pirq] = -1; xen_free_irq(irq); @@ -769,7 +748,24 @@ out: int xen_irq_from_pirq(unsigned pirq) { - return pirq_to_irq[pirq]; + int irq; + + struct irq_info *info; + + spin_lock(&irq_mapping_update_lock); + + list_for_each_entry(info, &xen_irq_list_head, list) { + if (info == NULL || info->type != IRQT_PIRQ) + continue; + irq = info->irq; + if (info->u.pirq.pirq == pirq) + goto out; + } + irq = -1; +out: + spin_lock(&irq_mapping_update_lock); + + return irq; } int bind_evtchn_to_irq(unsigned int evtchn) @@ -1269,15 +1265,18 @@ static void restore_pirqs(void) { int pirq, rc, irq, gsi; struct physdev_map_pirq map_irq; + struct irq_info *info; - for (pirq = 0; pirq < nr_irqs; pirq++) { - irq = pirq_to_irq[pirq]; - if (irq == -1) + list_for_each_entry(info, &xen_irq_list_head, list) { + if (info->type != IRQT_PIRQ) continue; + pirq = info->u.pirq.pirq; + gsi = info->u.pirq.gsi; + irq = info->irq; + /* save/restore of PT devices doesn't work, so at this point the * only devices present are GSI based emulated devices */ - gsi = gsi_from_irq(irq); if (!gsi) continue; @@ -1291,7 +1290,6 @@ static void restore_pirqs(void) printk(KERN_WARNING "xen map irq failed gsi=%d irq=%d pirq=%d rc=%d\n", gsi, irq, pirq, rc); xen_free_irq(irq); - pirq_to_irq[pirq] = -1; continue; } @@ -1512,13 +1510,6 @@ void __init xen_init_IRQ(void) { int i; - /* We are using nr_irqs as the maximum number of pirq available but - * that number is actually chosen by Xen and we don't know exactly - * what it is. Be careful choosing high pirq numbers. */ - pirq_to_irq = kcalloc(nr_irqs, sizeof(*pirq_to_irq), GFP_KERNEL); - for (i = 0; i < nr_irqs; i++) - pirq_to_irq[i] = -1; - evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), GFP_KERNEL); for (i = 0; i < NR_EVENT_CHANNELS; i++) -- cgit v1.2.3 From 6cb9bf3aaffcdd175574a9d66af4ad69156d0070 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:14 +0000 Subject: xen: events: do not workaround too-small nr_irqs With the introduction of e7bcecb7b1d2 "genirq: Make nr_irqs runtime expandable" nr_irqs can grow as necessary to accommodate our allocation requests. Signed-off-by: Ian Campbell Cc: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 6782251e4029..7c3668960c75 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -423,15 +423,8 @@ static int xen_allocate_irq_dynamic(void) first = get_nr_irqs_gsi(); #endif -retry: irq = irq_alloc_desc_from(first, -1); - if (irq == -ENOMEM && first > NR_IRQS_LEGACY) { - printk(KERN_ERR "Out of dynamic IRQ space and eating into GSI space. You should increase nr_irqs\n"); - first = max(NR_IRQS_LEGACY, first - NR_IRQS_LEGACY); - goto retry; - } - if (irq < 0) panic("No available IRQ to bind to: increase nr_irqs!\n"); -- cgit v1.2.3 From 7bee976822a78bbb278790c2cd64293568592cdb Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 10 Mar 2011 16:08:15 +0000 Subject: xen: events: propagate irq allocation failure instead of panicking Running out of IRQs need not be fatal to the machine as a whole. Signed-off-by: Ian Campbell Cc: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 7c3668960c75..3566c00e1e3d 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -406,7 +406,7 @@ static void xen_irq_init(unsigned irq) list_add_tail(&info->list, &xen_irq_list_head); } -static int xen_allocate_irq_dynamic(void) +static int __must_check xen_allocate_irq_dynamic(void) { int first = 0; int irq; @@ -425,15 +425,12 @@ static int xen_allocate_irq_dynamic(void) irq = irq_alloc_desc_from(first, -1); - if (irq < 0) - panic("No available IRQ to bind to: increase nr_irqs!\n"); - xen_irq_init(irq); return irq; } -static int xen_allocate_irq_gsi(unsigned gsi) +static int __must_check xen_allocate_irq_gsi(unsigned gsi) { int irq; @@ -452,9 +449,6 @@ static int xen_allocate_irq_gsi(unsigned gsi) else irq = irq_alloc_desc_at(gsi, -1); - if (irq < 0) - panic("Unable to allocate to IRQ%d (%d)\n", gsi, irq); - xen_irq_init(irq); return irq; @@ -640,6 +634,8 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, } irq = xen_allocate_irq_gsi(gsi); + if (irq < 0) + goto out; set_irq_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, name); @@ -771,6 +767,8 @@ int bind_evtchn_to_irq(unsigned int evtchn) if (irq == -1) { irq = xen_allocate_irq_dynamic(); + if (irq == -1) + goto out; set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, handle_fasteoi_irq, "event"); @@ -778,6 +776,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) xen_irq_info_evtchn_init(irq, evtchn); } +out: spin_unlock(&irq_mapping_update_lock); return irq; @@ -829,6 +828,8 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) if (irq == -1) { irq = xen_allocate_irq_dynamic(); + if (irq == -1) + goto out; set_irq_chip_and_handler_name(irq, &xen_percpu_chip, handle_percpu_irq, "virq"); @@ -845,6 +846,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) bind_evtchn_to_cpu(evtchn, cpu); } +out: spin_unlock(&irq_mapping_update_lock); return irq; @@ -897,6 +899,8 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn, int retval; irq = bind_evtchn_to_irq(evtchn); + if (irq < 0) + return irq; retval = request_irq(irq, handler, irqflags, devname, dev_id); if (retval != 0) { unbind_from_irq(irq); @@ -915,6 +919,8 @@ int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu, int retval; irq = bind_virq_to_irq(virq, cpu); + if (irq < 0) + return irq; retval = request_irq(irq, handler, irqflags, devname, dev_id); if (retval != 0) { unbind_from_irq(irq); -- cgit v1.2.3 From a7b807ce8c86925eef92fe6aa79cea4ac7f097c4 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 14 Mar 2011 09:50:39 +0000 Subject: xen: events: correct locking in xen_irq_from_pirq One of those spin_lock() calls should be an unlock... Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 3566c00e1e3d..dc8177950d05 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -752,7 +752,7 @@ int xen_irq_from_pirq(unsigned pirq) } irq = -1; out: - spin_lock(&irq_mapping_update_lock); + spin_unlock(&irq_mapping_update_lock); return irq; } -- cgit v1.2.3 From 44626e4a3bd764283193e14e64f9324e48b4bfd8 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 15 Mar 2011 16:40:33 -0400 Subject: xen: events: Fix compile error if CONFIG_SMP is not defined. drivers/xen/events.c:396: error: 'struct irq_data' has no member named 'affinity' Reported-by: Randy Dunlap Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/xen') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index dc8177950d05..4591853f6ebc 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -392,8 +392,10 @@ static void xen_irq_init(unsigned irq) struct irq_info *info; struct irq_desc *desc = irq_to_desc(irq); +#ifdef CONFIG_SMP /* By default all event channels notify CPU#0. */ cpumask_copy(desc->irq_data.affinity, cpumask_of(0)); +#endif info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) -- cgit v1.2.3