ia64/xen-unstable

view xen/arch/x86/physdev.c @ 18591:ed398097c03e

x86: Move pirq logic to irq.c.

Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Oct 08 10:48:48 2008 +0100 (2008-10-08)
parents e1507b441be4
children 51a05fb4c601
line source
2 #include <xen/config.h>
3 #include <xen/init.h>
4 #include <xen/lib.h>
5 #include <xen/types.h>
6 #include <xen/sched.h>
7 #include <xen/irq.h>
8 #include <xen/event.h>
9 #include <xen/guest_access.h>
10 #include <xen/iocap.h>
11 #include <asm/current.h>
12 #include <asm/msi.h>
13 #include <asm/hypercall.h>
14 #include <public/xen.h>
15 #include <public/physdev.h>
16 #include <xsm/xsm.h>
18 #ifndef COMPAT
19 typedef long ret_t;
20 #endif
22 int
23 ioapic_guest_read(
24 unsigned long physbase, unsigned int reg, u32 *pval);
25 int
26 ioapic_guest_write(
27 unsigned long physbase, unsigned int reg, u32 pval);
29 static int physdev_map_pirq(struct physdev_map_pirq *map)
30 {
31 struct domain *d;
32 int vector, pirq, ret = 0;
33 struct msi_info _msi;
34 void *map_data = NULL;
36 if ( !IS_PRIV(current->domain) )
37 return -EPERM;
39 if ( !map )
40 return -EINVAL;
42 if ( map->domid == DOMID_SELF )
43 d = rcu_lock_domain(current->domain);
44 else
45 d = rcu_lock_domain_by_id(map->domid);
47 if ( d == NULL )
48 {
49 ret = -ESRCH;
50 goto free_domain;
51 }
53 /* Verify or get vector. */
54 switch ( map->type )
55 {
56 case MAP_PIRQ_TYPE_GSI:
57 if ( map->index < 0 || map->index >= NR_IRQS )
58 {
59 dprintk(XENLOG_G_ERR, "dom%d: map invalid irq %d\n",
60 d->domain_id, map->index);
61 ret = -EINVAL;
62 goto free_domain;
63 }
64 vector = IO_APIC_VECTOR(map->index);
65 if ( !vector )
66 {
67 dprintk(XENLOG_G_ERR, "dom%d: map irq with no vector %d\n",
68 d->domain_id, vector);
69 ret = -EINVAL;
70 goto free_domain;
71 }
72 break;
74 case MAP_PIRQ_TYPE_MSI:
75 vector = map->index;
76 if ( vector == -1 )
77 vector = assign_irq_vector(AUTO_ASSIGN);
79 if ( vector < 0 || vector >= NR_VECTORS )
80 {
81 dprintk(XENLOG_G_ERR, "dom%d: map irq with wrong vector %d\n",
82 d->domain_id, map->index);
83 ret = -EINVAL;
84 goto free_domain;
85 }
87 _msi.bus = map->bus;
88 _msi.devfn = map->devfn;
89 _msi.entry_nr = map->entry_nr;
90 _msi.table_base = map->table_base;
91 _msi.vector = vector;
92 map_data = &_msi;
93 break;
95 default:
96 dprintk(XENLOG_G_ERR, "dom%d: wrong map_pirq type %x\n",
97 d->domain_id, map->type);
98 ret = -EINVAL;
99 goto free_domain;
100 }
102 /* Verify or get pirq. */
103 spin_lock(&d->evtchn_lock);
104 if ( map->pirq < 0 )
105 {
106 if ( d->arch.vector_pirq[vector] )
107 {
108 dprintk(XENLOG_G_ERR, "dom%d: %d:%d already mapped to %d\n",
109 d->domain_id, map->index, map->pirq,
110 d->arch.vector_pirq[vector]);
111 pirq = d->arch.vector_pirq[vector];
112 if ( pirq < 0 )
113 {
114 ret = -EBUSY;
115 goto done;
116 }
117 }
118 else
119 {
120 pirq = get_free_pirq(d, map->type, map->index);
121 if ( pirq < 0 )
122 {
123 dprintk(XENLOG_G_ERR, "dom%d: no free pirq\n", d->domain_id);
124 ret = pirq;
125 goto done;
126 }
127 }
128 }
129 else
130 {
131 if ( d->arch.vector_pirq[vector] &&
132 d->arch.vector_pirq[vector] != map->pirq )
133 {
134 dprintk(XENLOG_G_ERR, "dom%d: vector %d conflicts with irq %d\n",
135 d->domain_id, map->index, map->pirq);
136 ret = -EEXIST;
137 goto done;
138 }
139 else
140 pirq = map->pirq;
141 }
144 ret = map_domain_pirq(d, pirq, vector, map->type, map_data);
145 if ( !ret )
146 map->pirq = pirq;
148 done:
149 spin_unlock(&d->evtchn_lock);
150 free_domain:
151 rcu_unlock_domain(d);
152 return ret;
153 }
155 static int physdev_unmap_pirq(struct physdev_unmap_pirq *unmap)
156 {
157 struct domain *d;
158 int ret;
160 if ( !IS_PRIV(current->domain) )
161 return -EPERM;
163 if ( unmap->domid == DOMID_SELF )
164 d = rcu_lock_domain(current->domain);
165 else
166 d = rcu_lock_domain_by_id(unmap->domid);
168 if ( d == NULL )
169 return -ESRCH;
171 spin_lock(&d->evtchn_lock);
172 ret = unmap_domain_pirq(d, unmap->pirq);
173 spin_unlock(&d->evtchn_lock);
175 rcu_unlock_domain(d);
177 return ret;
178 }
180 ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
181 {
182 int irq;
183 ret_t ret;
184 struct vcpu *v = current;
186 switch ( cmd )
187 {
188 case PHYSDEVOP_eoi: {
189 struct physdev_eoi eoi;
190 ret = -EFAULT;
191 if ( copy_from_guest(&eoi, arg, 1) != 0 )
192 break;
193 ret = pirq_guest_eoi(v->domain, eoi.irq);
194 break;
195 }
197 /* Legacy since 0x00030202. */
198 case PHYSDEVOP_IRQ_UNMASK_NOTIFY: {
199 ret = pirq_guest_unmask(v->domain);
200 break;
201 }
203 case PHYSDEVOP_irq_status_query: {
204 struct physdev_irq_status_query irq_status_query;
205 ret = -EFAULT;
206 if ( copy_from_guest(&irq_status_query, arg, 1) != 0 )
207 break;
208 irq = irq_status_query.irq;
209 ret = -EINVAL;
210 if ( (irq < 0) || (irq >= NR_IRQS) )
211 break;
212 irq_status_query.flags = 0;
213 if ( pirq_acktype(v->domain, irq) != 0 )
214 irq_status_query.flags |= XENIRQSTAT_needs_eoi;
215 if ( pirq_shared(v->domain, irq) )
216 irq_status_query.flags |= XENIRQSTAT_shared;
217 ret = copy_to_guest(arg, &irq_status_query, 1) ? -EFAULT : 0;
218 break;
219 }
221 case PHYSDEVOP_map_pirq: {
222 struct physdev_map_pirq map;
224 ret = -EFAULT;
225 if ( copy_from_guest(&map, arg, 1) != 0 )
226 break;
228 ret = physdev_map_pirq(&map);
230 if ( copy_to_guest(arg, &map, 1) != 0 )
231 ret = -EFAULT;
232 break;
233 }
235 case PHYSDEVOP_unmap_pirq: {
236 struct physdev_unmap_pirq unmap;
238 ret = -EFAULT;
239 if ( copy_from_guest(&unmap, arg, 1) != 0 )
240 break;
242 ret = physdev_unmap_pirq(&unmap);
243 break;
244 }
246 case PHYSDEVOP_apic_read: {
247 struct physdev_apic apic;
248 ret = -EFAULT;
249 if ( copy_from_guest(&apic, arg, 1) != 0 )
250 break;
251 ret = -EPERM;
252 if ( !IS_PRIV(v->domain) )
253 break;
254 ret = xsm_apic(v->domain, cmd);
255 if ( ret )
256 break;
257 ret = ioapic_guest_read(apic.apic_physbase, apic.reg, &apic.value);
258 if ( copy_to_guest(arg, &apic, 1) != 0 )
259 ret = -EFAULT;
260 break;
261 }
263 case PHYSDEVOP_apic_write: {
264 struct physdev_apic apic;
265 ret = -EFAULT;
266 if ( copy_from_guest(&apic, arg, 1) != 0 )
267 break;
268 ret = -EPERM;
269 if ( !IS_PRIV(v->domain) )
270 break;
271 ret = xsm_apic(v->domain, cmd);
272 if ( ret )
273 break;
274 ret = ioapic_guest_write(apic.apic_physbase, apic.reg, apic.value);
275 break;
276 }
278 case PHYSDEVOP_alloc_irq_vector: {
279 struct physdev_irq irq_op;
281 ret = -EFAULT;
282 if ( copy_from_guest(&irq_op, arg, 1) != 0 )
283 break;
285 ret = -EPERM;
286 if ( !IS_PRIV(v->domain) )
287 break;
289 ret = xsm_assign_vector(v->domain, irq_op.irq);
290 if ( ret )
291 break;
293 irq = irq_op.irq;
294 ret = -EINVAL;
295 if ( (irq < 0) || (irq >= NR_IRQS) )
296 break;
298 irq_op.vector = assign_irq_vector(irq);
300 spin_lock(&dom0->evtchn_lock);
301 ret = map_domain_pirq(dom0, irq_op.irq, irq_op.vector,
302 MAP_PIRQ_TYPE_GSI, NULL);
303 spin_unlock(&dom0->evtchn_lock);
305 if ( copy_to_guest(arg, &irq_op, 1) != 0 )
306 ret = -EFAULT;
307 break;
308 }
310 case PHYSDEVOP_set_iopl: {
311 struct physdev_set_iopl set_iopl;
312 ret = -EFAULT;
313 if ( copy_from_guest(&set_iopl, arg, 1) != 0 )
314 break;
315 ret = -EINVAL;
316 if ( set_iopl.iopl > 3 )
317 break;
318 ret = 0;
319 v->arch.iopl = set_iopl.iopl;
320 break;
321 }
323 case PHYSDEVOP_set_iobitmap: {
324 struct physdev_set_iobitmap set_iobitmap;
325 ret = -EFAULT;
326 if ( copy_from_guest(&set_iobitmap, arg, 1) != 0 )
327 break;
328 ret = -EINVAL;
329 if ( !guest_handle_okay(set_iobitmap.bitmap, IOBMP_BYTES) ||
330 (set_iobitmap.nr_ports > 65536) )
331 break;
332 ret = 0;
333 #ifndef COMPAT
334 v->arch.iobmp = set_iobitmap.bitmap;
335 #else
336 guest_from_compat_handle(v->arch.iobmp, set_iobitmap.bitmap);
337 #endif
338 v->arch.iobmp_limit = set_iobitmap.nr_ports;
339 break;
340 }
342 case PHYSDEVOP_manage_pci_add: {
343 struct physdev_manage_pci manage_pci;
344 ret = -EPERM;
345 if ( !IS_PRIV(v->domain) )
346 break;
347 ret = -EFAULT;
348 if ( copy_from_guest(&manage_pci, arg, 1) != 0 )
349 break;
351 ret = pci_add_device(manage_pci.bus, manage_pci.devfn);
352 break;
353 }
355 case PHYSDEVOP_manage_pci_remove: {
356 struct physdev_manage_pci manage_pci;
357 ret = -EPERM;
358 if ( !IS_PRIV(v->domain) )
359 break;
360 ret = -EFAULT;
361 if ( copy_from_guest(&manage_pci, arg, 1) != 0 )
362 break;
364 ret = pci_remove_device(manage_pci.bus, manage_pci.devfn);
365 break;
366 }
368 default:
369 ret = -ENOSYS;
370 break;
371 }
373 return ret;
374 }
376 /*
377 * Local variables:
378 * mode: C
379 * c-set-style: "BSD"
380 * c-basic-offset: 4
381 * tab-width: 4
382 * indent-tabs-mode: nil
383 * End:
384 */