diff options
author | Scott Rixner <rixner@rice.edu> | 2011-03-03 04:30:08 -0500 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2011-03-10 14:47:55 -0500 |
commit | ab7f863e4183057dc494f3180199934a9637d401 (patch) | |
tree | ce9d47b75c63937fa77285f8475b7207834d760c /drivers/xen | |
parent | 71eef7d1e3d9df760897fdd2cad6949a8bcf1620 (diff) |
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 <ian.campbell@citrix.com>
[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 <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/events.c | 72 |
1 files changed, 65 insertions, 7 deletions
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 | |||
@@ -1028,6 +1028,11 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id) | |||
1028 | static DEFINE_PER_CPU(unsigned, xed_nesting_count); | 1028 | static DEFINE_PER_CPU(unsigned, xed_nesting_count); |
1029 | 1029 | ||
1030 | /* | 1030 | /* |
1031 | * Mask out the i least significant bits of w | ||
1032 | */ | ||
1033 | #define MASK_LSBS(w, i) (w & ((~0UL) << i)) | ||
1034 | |||
1035 | /* | ||
1031 | * Search the CPUs pending events bitmasks. For each one found, map | 1036 | * Search the CPUs pending events bitmasks. For each one found, map |
1032 | * the event number to an irq, and feed it into do_IRQ() for | 1037 | * the event number to an irq, and feed it into do_IRQ() for |
1033 | * handling. | 1038 | * handling. |
@@ -1038,6 +1043,9 @@ static DEFINE_PER_CPU(unsigned, xed_nesting_count); | |||
1038 | */ | 1043 | */ |
1039 | static void __xen_evtchn_do_upcall(void) | 1044 | static void __xen_evtchn_do_upcall(void) |
1040 | { | 1045 | { |
1046 | static unsigned int last_word_idx = BITS_PER_LONG - 1; | ||
1047 | static unsigned int last_bit_idx = BITS_PER_LONG - 1; | ||
1048 | int word_idx, bit_idx; | ||
1041 | int cpu = get_cpu(); | 1049 | int cpu = get_cpu(); |
1042 | struct shared_info *s = HYPERVISOR_shared_info; | 1050 | struct shared_info *s = HYPERVISOR_shared_info; |
1043 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); | 1051 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); |
@@ -1056,17 +1064,50 @@ static void __xen_evtchn_do_upcall(void) | |||
1056 | wmb(); | 1064 | wmb(); |
1057 | #endif | 1065 | #endif |
1058 | pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0); | 1066 | pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0); |
1067 | |||
1068 | word_idx = last_word_idx; | ||
1069 | bit_idx = last_bit_idx; | ||
1070 | |||
1059 | while (pending_words != 0) { | 1071 | while (pending_words != 0) { |
1060 | unsigned long pending_bits; | 1072 | unsigned long pending_bits; |
1061 | int word_idx = __ffs(pending_words); | 1073 | unsigned long words; |
1062 | pending_words &= ~(1UL << word_idx); | 1074 | |
1075 | word_idx = (word_idx + 1) % BITS_PER_LONG; | ||
1076 | words = MASK_LSBS(pending_words, word_idx); | ||
1077 | |||
1078 | /* | ||
1079 | * If we masked out all events, wrap around to the | ||
1080 | * beginning. | ||
1081 | */ | ||
1082 | if (words == 0) { | ||
1083 | word_idx = BITS_PER_LONG - 1; | ||
1084 | bit_idx = BITS_PER_LONG - 1; | ||
1085 | continue; | ||
1086 | } | ||
1087 | word_idx = __ffs(words); | ||
1063 | 1088 | ||
1064 | while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) { | 1089 | do { |
1065 | int bit_idx = __ffs(pending_bits); | 1090 | unsigned long bits; |
1066 | int port = (word_idx * BITS_PER_LONG) + bit_idx; | 1091 | int port, irq; |
1067 | int irq = evtchn_to_irq[port]; | ||
1068 | struct irq_desc *desc; | 1092 | struct irq_desc *desc; |
1069 | 1093 | ||
1094 | pending_bits = active_evtchns(cpu, s, word_idx); | ||
1095 | |||
1096 | bit_idx = (bit_idx + 1) % BITS_PER_LONG; | ||
1097 | bits = MASK_LSBS(pending_bits, bit_idx); | ||
1098 | |||
1099 | /* If we masked out all events, move on. */ | ||
1100 | if (bits == 0) { | ||
1101 | bit_idx = BITS_PER_LONG - 1; | ||
1102 | break; | ||
1103 | } | ||
1104 | |||
1105 | bit_idx = __ffs(bits); | ||
1106 | |||
1107 | /* Process port. */ | ||
1108 | port = (word_idx * BITS_PER_LONG) + bit_idx; | ||
1109 | irq = evtchn_to_irq[port]; | ||
1110 | |||
1070 | mask_evtchn(port); | 1111 | mask_evtchn(port); |
1071 | clear_evtchn(port); | 1112 | clear_evtchn(port); |
1072 | 1113 | ||
@@ -1075,7 +1116,24 @@ static void __xen_evtchn_do_upcall(void) | |||
1075 | if (desc) | 1116 | if (desc) |
1076 | generic_handle_irq_desc(irq, desc); | 1117 | generic_handle_irq_desc(irq, desc); |
1077 | } | 1118 | } |
1078 | } | 1119 | |
1120 | /* | ||
1121 | * If this is the final port processed, we'll | ||
1122 | * pick up here+1 next time. | ||
1123 | */ | ||
1124 | last_word_idx = word_idx; | ||
1125 | last_bit_idx = bit_idx; | ||
1126 | |||
1127 | } while (bit_idx != BITS_PER_LONG - 1); | ||
1128 | |||
1129 | pending_bits = active_evtchns(cpu, s, word_idx); | ||
1130 | |||
1131 | /* | ||
1132 | * We handled all ports, so we can clear the | ||
1133 | * selector bit. | ||
1134 | */ | ||
1135 | if (pending_bits == 0) | ||
1136 | pending_words &= ~(1UL << word_idx); | ||
1079 | } | 1137 | } |
1080 | 1138 | ||
1081 | BUG_ON(!irqs_disabled()); | 1139 | BUG_ON(!irqs_disabled()); |