aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-04-17 16:32:04 -0400
committerAlexander Graf <agraf@suse.de>2013-04-26 14:27:33 -0400
commitd19bd86204f85d42873e07bb64a27587fc380b5b (patch)
tree1fc7dce84e6f1007a09e424b9c0b83cee8e5b631
parent4619ac88b72c43c622ef1eae3069de0e6f2cba9d (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.h2
-rw-r--r--arch/powerpc/kvm/book3s_rtas.c40
-rw-r--r--arch/powerpc/kvm/book3s_xics.c84
-rw-r--r--arch/powerpc/kvm/book3s_xics.h2
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);
175extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, 175extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server,
176 u32 *priority); 176 u32 *priority);
177extern int kvmppc_xics_int_on(struct kvm *kvm, u32 irq);
178extern 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)
63out: 63out:
64 args->rets[0] = rc; 64 args->rets[0] = rc;
65} 65}
66
67static 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;
82out:
83 args->rets[0] = rc;
84}
85
86static 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;
101out:
102 args->rets[0] = rc;
103}
66#endif /* CONFIG_KVM_XICS */ 104#endif /* CONFIG_KVM_XICS */
67 105
68struct rtas_handler { 106struct 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
126static 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
126int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority) 148int 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
201int 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
228int 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
194static inline bool icp_try_update(struct kvmppc_icp *icp, 250static 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 */