diff options
Diffstat (limited to 'arch/x86/kvm/i8259.c')
-rw-r--r-- | arch/x86/kvm/i8259.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 179dcb0103fd..1ccb50c74f18 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c | |||
@@ -32,11 +32,13 @@ | |||
32 | #include <linux/kvm_host.h> | 32 | #include <linux/kvm_host.h> |
33 | 33 | ||
34 | static void pic_lock(struct kvm_pic *s) | 34 | static void pic_lock(struct kvm_pic *s) |
35 | __acquires(&s->lock) | ||
35 | { | 36 | { |
36 | spin_lock(&s->lock); | 37 | spin_lock(&s->lock); |
37 | } | 38 | } |
38 | 39 | ||
39 | static void pic_unlock(struct kvm_pic *s) | 40 | static void pic_unlock(struct kvm_pic *s) |
41 | __releases(&s->lock) | ||
40 | { | 42 | { |
41 | struct kvm *kvm = s->kvm; | 43 | struct kvm *kvm = s->kvm; |
42 | unsigned acks = s->pending_acks; | 44 | unsigned acks = s->pending_acks; |
@@ -49,7 +51,8 @@ static void pic_unlock(struct kvm_pic *s) | |||
49 | spin_unlock(&s->lock); | 51 | spin_unlock(&s->lock); |
50 | 52 | ||
51 | while (acks) { | 53 | while (acks) { |
52 | kvm_notify_acked_irq(kvm, __ffs(acks)); | 54 | kvm_notify_acked_irq(kvm, SELECT_PIC(__ffs(acks)), |
55 | __ffs(acks)); | ||
53 | acks &= acks - 1; | 56 | acks &= acks - 1; |
54 | } | 57 | } |
55 | 58 | ||
@@ -76,12 +79,13 @@ void kvm_pic_clear_isr_ack(struct kvm *kvm) | |||
76 | /* | 79 | /* |
77 | * set irq level. If an edge is detected, then the IRR is set to 1 | 80 | * set irq level. If an edge is detected, then the IRR is set to 1 |
78 | */ | 81 | */ |
79 | static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level) | 82 | static inline int pic_set_irq1(struct kvm_kpic_state *s, int irq, int level) |
80 | { | 83 | { |
81 | int mask; | 84 | int mask, ret = 1; |
82 | mask = 1 << irq; | 85 | mask = 1 << irq; |
83 | if (s->elcr & mask) /* level triggered */ | 86 | if (s->elcr & mask) /* level triggered */ |
84 | if (level) { | 87 | if (level) { |
88 | ret = !(s->irr & mask); | ||
85 | s->irr |= mask; | 89 | s->irr |= mask; |
86 | s->last_irr |= mask; | 90 | s->last_irr |= mask; |
87 | } else { | 91 | } else { |
@@ -90,11 +94,15 @@ static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level) | |||
90 | } | 94 | } |
91 | else /* edge triggered */ | 95 | else /* edge triggered */ |
92 | if (level) { | 96 | if (level) { |
93 | if ((s->last_irr & mask) == 0) | 97 | if ((s->last_irr & mask) == 0) { |
98 | ret = !(s->irr & mask); | ||
94 | s->irr |= mask; | 99 | s->irr |= mask; |
100 | } | ||
95 | s->last_irr |= mask; | 101 | s->last_irr |= mask; |
96 | } else | 102 | } else |
97 | s->last_irr &= ~mask; | 103 | s->last_irr &= ~mask; |
104 | |||
105 | return (s->imr & mask) ? -1 : ret; | ||
98 | } | 106 | } |
99 | 107 | ||
100 | /* | 108 | /* |
@@ -171,16 +179,19 @@ void kvm_pic_update_irq(struct kvm_pic *s) | |||
171 | pic_unlock(s); | 179 | pic_unlock(s); |
172 | } | 180 | } |
173 | 181 | ||
174 | void kvm_pic_set_irq(void *opaque, int irq, int level) | 182 | int kvm_pic_set_irq(void *opaque, int irq, int level) |
175 | { | 183 | { |
176 | struct kvm_pic *s = opaque; | 184 | struct kvm_pic *s = opaque; |
185 | int ret = -1; | ||
177 | 186 | ||
178 | pic_lock(s); | 187 | pic_lock(s); |
179 | if (irq >= 0 && irq < PIC_NUM_PINS) { | 188 | if (irq >= 0 && irq < PIC_NUM_PINS) { |
180 | pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); | 189 | ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); |
181 | pic_update_irq(s); | 190 | pic_update_irq(s); |
182 | } | 191 | } |
183 | pic_unlock(s); | 192 | pic_unlock(s); |
193 | |||
194 | return ret; | ||
184 | } | 195 | } |
185 | 196 | ||
186 | /* | 197 | /* |
@@ -232,7 +243,7 @@ int kvm_pic_read_irq(struct kvm *kvm) | |||
232 | } | 243 | } |
233 | pic_update_irq(s); | 244 | pic_update_irq(s); |
234 | pic_unlock(s); | 245 | pic_unlock(s); |
235 | kvm_notify_acked_irq(kvm, irq); | 246 | kvm_notify_acked_irq(kvm, SELECT_PIC(irq), irq); |
236 | 247 | ||
237 | return intno; | 248 | return intno; |
238 | } | 249 | } |