diff options
author | Paul Mackerras <paulus@samba.org> | 2013-04-17 16:32:04 -0400 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2013-04-26 14:27:33 -0400 |
commit | d19bd86204f85d42873e07bb64a27587fc380b5b (patch) | |
tree | 1fc7dce84e6f1007a09e424b9c0b83cee8e5b631 | |
parent | 4619ac88b72c43c622ef1eae3069de0e6f2cba9d (diff) |
KVM: PPC: Book3S: Add support for ibm,int-on/off RTAS calls
This adds support for the ibm,int-on and ibm,int-off RTAS calls to the
in-kernel XICS emulation and corrects the handling of the saved
priority by the ibm,set-xive RTAS call. With this, ibm,int-off sets
the specified interrupt's priority in its saved_priority field and
sets the priority to 0xff (the least favoured value). ibm,int-on
restores the saved_priority to the priority field, and ibm,set-xive
sets both the priority and the saved_priority to the specified
priority value.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
-rw-r--r-- | arch/powerpc/include/asm/kvm_ppc.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_rtas.c | 40 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_xics.c | 84 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_xics.h | 2 |
4 files changed, 113 insertions, 15 deletions
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 1589fd8bf063..cfaa47995c0e 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h | |||
@@ -174,6 +174,8 @@ extern int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, | |||
174 | u32 priority); | 174 | u32 priority); |
175 | extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, | 175 | extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, |
176 | u32 *priority); | 176 | u32 *priority); |
177 | extern int kvmppc_xics_int_on(struct kvm *kvm, u32 irq); | ||
178 | extern int kvmppc_xics_int_off(struct kvm *kvm, u32 irq); | ||
177 | 179 | ||
178 | /* | 180 | /* |
179 | * Cuts out inst bits with ordering according to spec. | 181 | * Cuts out inst bits with ordering according to spec. |
diff --git a/arch/powerpc/kvm/book3s_rtas.c b/arch/powerpc/kvm/book3s_rtas.c index 77f9aa5f4ba5..3219ba895246 100644 --- a/arch/powerpc/kvm/book3s_rtas.c +++ b/arch/powerpc/kvm/book3s_rtas.c | |||
@@ -63,6 +63,44 @@ static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args) | |||
63 | out: | 63 | out: |
64 | args->rets[0] = rc; | 64 | args->rets[0] = rc; |
65 | } | 65 | } |
66 | |||
67 | static void kvm_rtas_int_off(struct kvm_vcpu *vcpu, struct rtas_args *args) | ||
68 | { | ||
69 | u32 irq; | ||
70 | int rc; | ||
71 | |||
72 | if (args->nargs != 1 || args->nret != 1) { | ||
73 | rc = -3; | ||
74 | goto out; | ||
75 | } | ||
76 | |||
77 | irq = args->args[0]; | ||
78 | |||
79 | rc = kvmppc_xics_int_off(vcpu->kvm, irq); | ||
80 | if (rc) | ||
81 | rc = -3; | ||
82 | out: | ||
83 | args->rets[0] = rc; | ||
84 | } | ||
85 | |||
86 | static void kvm_rtas_int_on(struct kvm_vcpu *vcpu, struct rtas_args *args) | ||
87 | { | ||
88 | u32 irq; | ||
89 | int rc; | ||
90 | |||
91 | if (args->nargs != 1 || args->nret != 1) { | ||
92 | rc = -3; | ||
93 | goto out; | ||
94 | } | ||
95 | |||
96 | irq = args->args[0]; | ||
97 | |||
98 | rc = kvmppc_xics_int_on(vcpu->kvm, irq); | ||
99 | if (rc) | ||
100 | rc = -3; | ||
101 | out: | ||
102 | args->rets[0] = rc; | ||
103 | } | ||
66 | #endif /* CONFIG_KVM_XICS */ | 104 | #endif /* CONFIG_KVM_XICS */ |
67 | 105 | ||
68 | struct rtas_handler { | 106 | struct rtas_handler { |
@@ -74,6 +112,8 @@ static struct rtas_handler rtas_handlers[] = { | |||
74 | #ifdef CONFIG_KVM_XICS | 112 | #ifdef CONFIG_KVM_XICS |
75 | { .name = "ibm,set-xive", .handler = kvm_rtas_set_xive }, | 113 | { .name = "ibm,set-xive", .handler = kvm_rtas_set_xive }, |
76 | { .name = "ibm,get-xive", .handler = kvm_rtas_get_xive }, | 114 | { .name = "ibm,get-xive", .handler = kvm_rtas_get_xive }, |
115 | { .name = "ibm,int-off", .handler = kvm_rtas_int_off }, | ||
116 | { .name = "ibm,int-on", .handler = kvm_rtas_int_on }, | ||
77 | #endif | 117 | #endif |
78 | }; | 118 | }; |
79 | 119 | ||
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index 7fd247cbd0d1..9fb2d3909c46 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c | |||
@@ -123,6 +123,28 @@ static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics, | |||
123 | mutex_unlock(&ics->lock); | 123 | mutex_unlock(&ics->lock); |
124 | } | 124 | } |
125 | 125 | ||
126 | static bool write_xive(struct kvmppc_xics *xics, struct kvmppc_ics *ics, | ||
127 | struct ics_irq_state *state, | ||
128 | u32 server, u32 priority, u32 saved_priority) | ||
129 | { | ||
130 | bool deliver; | ||
131 | |||
132 | mutex_lock(&ics->lock); | ||
133 | |||
134 | state->server = server; | ||
135 | state->priority = priority; | ||
136 | state->saved_priority = saved_priority; | ||
137 | deliver = false; | ||
138 | if ((state->masked_pending || state->resend) && priority != MASKED) { | ||
139 | state->masked_pending = 0; | ||
140 | deliver = true; | ||
141 | } | ||
142 | |||
143 | mutex_unlock(&ics->lock); | ||
144 | |||
145 | return deliver; | ||
146 | } | ||
147 | |||
126 | int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) | 148 | int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) |
127 | { | 149 | { |
128 | struct kvmppc_xics *xics = kvm->arch.xics; | 150 | struct kvmppc_xics *xics = kvm->arch.xics; |
@@ -130,7 +152,6 @@ int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) | |||
130 | struct kvmppc_ics *ics; | 152 | struct kvmppc_ics *ics; |
131 | struct ics_irq_state *state; | 153 | struct ics_irq_state *state; |
132 | u16 src; | 154 | u16 src; |
133 | bool deliver; | ||
134 | 155 | ||
135 | if (!xics) | 156 | if (!xics) |
136 | return -ENODEV; | 157 | return -ENODEV; |
@@ -144,23 +165,11 @@ int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) | |||
144 | if (!icp) | 165 | if (!icp) |
145 | return -EINVAL; | 166 | return -EINVAL; |
146 | 167 | ||
147 | mutex_lock(&ics->lock); | ||
148 | |||
149 | XICS_DBG("set_xive %#x server %#x prio %#x MP:%d RS:%d\n", | 168 | XICS_DBG("set_xive %#x server %#x prio %#x MP:%d RS:%d\n", |
150 | irq, server, priority, | 169 | irq, server, priority, |
151 | state->masked_pending, state->resend); | 170 | state->masked_pending, state->resend); |
152 | 171 | ||
153 | state->server = server; | 172 | if (write_xive(xics, ics, state, server, priority, priority)) |
154 | state->priority = priority; | ||
155 | deliver = false; | ||
156 | if ((state->masked_pending || state->resend) && priority != MASKED) { | ||
157 | state->masked_pending = 0; | ||
158 | deliver = true; | ||
159 | } | ||
160 | |||
161 | mutex_unlock(&ics->lock); | ||
162 | |||
163 | if (deliver) | ||
164 | icp_deliver_irq(xics, icp, irq); | 173 | icp_deliver_irq(xics, icp, irq); |
165 | 174 | ||
166 | return 0; | 175 | return 0; |
@@ -189,6 +198,53 @@ int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, u32 *priority) | |||
189 | return 0; | 198 | return 0; |
190 | } | 199 | } |
191 | 200 | ||
201 | int kvmppc_xics_int_on(struct kvm *kvm, u32 irq) | ||
202 | { | ||
203 | struct kvmppc_xics *xics = kvm->arch.xics; | ||
204 | struct kvmppc_icp *icp; | ||
205 | struct kvmppc_ics *ics; | ||
206 | struct ics_irq_state *state; | ||
207 | u16 src; | ||
208 | |||
209 | if (!xics) | ||
210 | return -ENODEV; | ||
211 | |||
212 | ics = kvmppc_xics_find_ics(xics, irq, &src); | ||
213 | if (!ics) | ||
214 | return -EINVAL; | ||
215 | state = &ics->irq_state[src]; | ||
216 | |||
217 | icp = kvmppc_xics_find_server(kvm, state->server); | ||
218 | if (!icp) | ||
219 | return -EINVAL; | ||
220 | |||
221 | if (write_xive(xics, ics, state, state->server, state->saved_priority, | ||
222 | state->saved_priority)) | ||
223 | icp_deliver_irq(xics, icp, irq); | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | int kvmppc_xics_int_off(struct kvm *kvm, u32 irq) | ||
229 | { | ||
230 | struct kvmppc_xics *xics = kvm->arch.xics; | ||
231 | struct kvmppc_ics *ics; | ||
232 | struct ics_irq_state *state; | ||
233 | u16 src; | ||
234 | |||
235 | if (!xics) | ||
236 | return -ENODEV; | ||
237 | |||
238 | ics = kvmppc_xics_find_ics(xics, irq, &src); | ||
239 | if (!ics) | ||
240 | return -EINVAL; | ||
241 | state = &ics->irq_state[src]; | ||
242 | |||
243 | write_xive(xics, ics, state, state->server, MASKED, state->priority); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
192 | /* -- ICP routines, including hcalls -- */ | 248 | /* -- ICP routines, including hcalls -- */ |
193 | 249 | ||
194 | static inline bool icp_try_update(struct kvmppc_icp *icp, | 250 | static inline bool icp_try_update(struct kvmppc_icp *icp, |
diff --git a/arch/powerpc/kvm/book3s_xics.h b/arch/powerpc/kvm/book3s_xics.h index c816c5a49c90..e4fdec3dde77 100644 --- a/arch/powerpc/kvm/book3s_xics.h +++ b/arch/powerpc/kvm/book3s_xics.h | |||
@@ -36,7 +36,7 @@ struct ics_irq_state { | |||
36 | u32 number; | 36 | u32 number; |
37 | u32 server; | 37 | u32 server; |
38 | u8 priority; | 38 | u8 priority; |
39 | u8 saved_priority; /* currently unused */ | 39 | u8 saved_priority; |
40 | u8 resend; | 40 | u8 resend; |
41 | u8 masked_pending; | 41 | u8 masked_pending; |
42 | u8 asserted; /* Only for LSI */ | 42 | u8 asserted; /* Only for LSI */ |