ia64/xen-unstable

view xen/drivers/passthrough/io.c @ 19835:edfdeb150f27

Fix buildsystem to detect udev > version 124

udev removed the udevinfo symlink from versions higher than 123 and
xen's build-system could not detect if udev is in place and has the
required version.

Signed-off-by: Marc-A. Dahlhaus <mad@wol.de>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 25 13:02:37 2009 +0100 (2009-06-25)
parents bfa933a4628d
children
line source
1 /*
2 * Copyright (c) 2006, Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Copyright (C) Allen Kay <allen.m.kay@intel.com>
18 * Copyright (C) Xiaohui Xin <xiaohui.xin@intel.com>
19 */
21 #include <xen/event.h>
22 #include <xen/iommu.h>
23 #include <asm/hvm/irq.h>
24 #include <asm/hvm/iommu.h>
25 #include <xen/hvm/irq.h>
27 static int pt_irq_need_timer(uint32_t flags)
28 {
29 return !(flags & (HVM_IRQ_DPCI_GUEST_MSI | HVM_IRQ_DPCI_TRANSLATE));
30 }
32 static void pt_irq_time_out(void *data)
33 {
34 struct hvm_mirq_dpci_mapping *irq_map = data;
35 unsigned int guest_gsi, machine_gsi = 0;
36 int vector;
37 struct hvm_irq_dpci *dpci = NULL;
38 struct dev_intx_gsi_link *digl;
39 struct hvm_girq_dpci_mapping *girq;
40 uint32_t device, intx;
41 unsigned int nr_pirqs = irq_map->dom->nr_pirqs;
42 DECLARE_BITMAP(machine_gsi_map, nr_pirqs);
44 bitmap_zero(machine_gsi_map, nr_pirqs);
46 spin_lock(&irq_map->dom->event_lock);
48 dpci = domain_get_irq_dpci(irq_map->dom);
49 ASSERT(dpci);
50 list_for_each_entry ( digl, &irq_map->digl_list, list )
51 {
52 guest_gsi = digl->gsi;
53 list_for_each_entry ( girq, &dpci->girq[guest_gsi], list )
54 {
55 machine_gsi = girq->machine_gsi;
56 set_bit(machine_gsi, machine_gsi_map);
57 }
58 device = digl->device;
59 intx = digl->intx;
60 hvm_pci_intx_deassert(irq_map->dom, device, intx);
61 }
63 for ( machine_gsi = find_first_bit(machine_gsi_map, nr_pirqs);
64 machine_gsi < nr_pirqs;
65 machine_gsi = find_next_bit(machine_gsi_map, nr_pirqs,
66 machine_gsi + 1) )
67 {
68 clear_bit(machine_gsi, dpci->dirq_mask);
69 vector = domain_irq_to_vector(irq_map->dom, machine_gsi);
70 dpci->mirq[machine_gsi].pending = 0;
71 }
73 spin_unlock(&irq_map->dom->event_lock);
75 for ( machine_gsi = find_first_bit(machine_gsi_map, nr_pirqs);
76 machine_gsi < nr_pirqs;
77 machine_gsi = find_next_bit(machine_gsi_map, nr_pirqs,
78 machine_gsi + 1) )
79 {
80 pirq_guest_eoi(irq_map->dom, machine_gsi);
81 }
82 }
84 void free_hvm_irq_dpci(struct hvm_irq_dpci *dpci)
85 {
86 xfree(dpci->mirq);
87 xfree(dpci->dirq_mask);
88 xfree(dpci->mapping);
89 xfree(dpci);
90 }
92 int pt_irq_create_bind_vtd(
93 struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
94 {
95 struct hvm_irq_dpci *hvm_irq_dpci = NULL;
96 uint32_t machine_gsi, guest_gsi;
97 uint32_t device, intx, link;
98 struct dev_intx_gsi_link *digl;
99 struct hvm_girq_dpci_mapping *girq;
100 int rc, pirq = pt_irq_bind->machine_irq;
102 if ( pirq < 0 || pirq >= d->nr_pirqs )
103 return -EINVAL;
105 spin_lock(&d->event_lock);
107 hvm_irq_dpci = domain_get_irq_dpci(d);
108 if ( hvm_irq_dpci == NULL )
109 {
110 hvm_irq_dpci = xmalloc(struct hvm_irq_dpci);
111 if ( hvm_irq_dpci == NULL )
112 {
113 spin_unlock(&d->event_lock);
114 return -ENOMEM;
115 }
116 memset(hvm_irq_dpci, 0, sizeof(*hvm_irq_dpci));
117 hvm_irq_dpci->mirq = xmalloc_array(struct hvm_mirq_dpci_mapping,
118 d->nr_pirqs);
119 hvm_irq_dpci->dirq_mask = xmalloc_array(unsigned long,
120 BITS_TO_LONGS(d->nr_pirqs));
121 hvm_irq_dpci->mapping = xmalloc_array(unsigned long,
122 BITS_TO_LONGS(d->nr_pirqs));
123 if ( !hvm_irq_dpci->mirq ||
124 !hvm_irq_dpci->dirq_mask ||
125 !hvm_irq_dpci->mapping )
126 {
127 spin_unlock(&d->event_lock);
128 free_hvm_irq_dpci(hvm_irq_dpci);
129 return -ENOMEM;
130 }
131 memset(hvm_irq_dpci->mirq, 0,
132 d->nr_pirqs * sizeof(*hvm_irq_dpci->mirq));
133 bitmap_zero(hvm_irq_dpci->dirq_mask, d->nr_pirqs);
134 bitmap_zero(hvm_irq_dpci->mapping, d->nr_pirqs);
135 for ( int i = 0; i < d->nr_pirqs; i++ )
136 INIT_LIST_HEAD(&hvm_irq_dpci->mirq[i].digl_list);
137 for ( int i = 0; i < NR_HVM_IRQS; i++ )
138 INIT_LIST_HEAD(&hvm_irq_dpci->girq[i]);
140 if ( domain_set_irq_dpci(d, hvm_irq_dpci) == 0 )
141 {
142 spin_unlock(&d->event_lock);
143 free_hvm_irq_dpci(hvm_irq_dpci);
144 return -EINVAL;
145 }
146 }
148 if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI )
149 {
151 if ( !test_and_set_bit(pirq, hvm_irq_dpci->mapping))
152 {
153 hvm_irq_dpci->mirq[pirq].flags = HVM_IRQ_DPCI_MACH_MSI |
154 HVM_IRQ_DPCI_GUEST_MSI;
155 hvm_irq_dpci->mirq[pirq].gmsi.gvec = pt_irq_bind->u.msi.gvec;
156 hvm_irq_dpci->mirq[pirq].gmsi.gflags = pt_irq_bind->u.msi.gflags;
157 hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] = pirq;
158 /* bind after hvm_irq_dpci is setup to avoid race with irq handler*/
159 rc = pirq_guest_bind(d->vcpu[0], pirq, 0);
160 if ( rc == 0 && pt_irq_bind->u.msi.gtable )
161 {
162 rc = msixtbl_pt_register(d, pirq, pt_irq_bind->u.msi.gtable);
163 if ( unlikely(rc) )
164 pirq_guest_unbind(d, pirq);
165 }
166 if ( unlikely(rc) )
167 {
168 hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] = 0;
169 hvm_irq_dpci->mirq[pirq].gmsi.gflags = 0;
170 hvm_irq_dpci->mirq[pirq].gmsi.gvec = 0;
171 hvm_irq_dpci->mirq[pirq].flags = 0;
172 clear_bit(pirq, hvm_irq_dpci->mapping);
173 spin_unlock(&d->event_lock);
174 return rc;
175 }
176 }
177 else
178 {
179 uint32_t mask = HVM_IRQ_DPCI_MACH_MSI | HVM_IRQ_DPCI_GUEST_MSI;
180 uint32_t old_gvec;
182 if ( (hvm_irq_dpci->mirq[pirq].flags & mask) != mask)
183 {
184 spin_unlock(&d->event_lock);
185 return -EBUSY;
186 }
188 /* if pirq is already mapped as vmsi, update the guest data/addr */
189 old_gvec = hvm_irq_dpci->mirq[pirq].gmsi.gvec;
190 hvm_irq_dpci->msi_gvec_pirq[old_gvec] = 0;
191 hvm_irq_dpci->mirq[pirq].gmsi.gvec = pt_irq_bind->u.msi.gvec;
192 hvm_irq_dpci->mirq[pirq].gmsi.gflags = pt_irq_bind->u.msi.gflags;
193 hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] = pirq;
194 }
195 }
196 else
197 {
198 machine_gsi = pt_irq_bind->machine_irq;
199 device = pt_irq_bind->u.pci.device;
200 intx = pt_irq_bind->u.pci.intx;
201 guest_gsi = hvm_pci_intx_gsi(device, intx);
202 link = hvm_pci_intx_link(device, intx);
203 hvm_irq_dpci->link_cnt[link]++;
205 digl = xmalloc(struct dev_intx_gsi_link);
206 if ( !digl )
207 {
208 spin_unlock(&d->event_lock);
209 return -ENOMEM;
210 }
212 girq = xmalloc(struct hvm_girq_dpci_mapping);
213 if ( !girq )
214 {
215 xfree(digl);
216 spin_unlock(&d->event_lock);
217 return -ENOMEM;
218 }
220 digl->device = device;
221 digl->intx = intx;
222 digl->gsi = guest_gsi;
223 digl->link = link;
224 list_add_tail(&digl->list,
225 &hvm_irq_dpci->mirq[machine_gsi].digl_list);
227 girq->device = device;
228 girq->intx = intx;
229 girq->machine_gsi = machine_gsi;
230 list_add_tail(&girq->list, &hvm_irq_dpci->girq[guest_gsi]);
232 /* Bind the same mirq once in the same domain */
233 if ( !test_and_set_bit(machine_gsi, hvm_irq_dpci->mapping))
234 {
235 unsigned int vector = domain_irq_to_vector(d, machine_gsi);
236 unsigned int share;
238 hvm_irq_dpci->mirq[machine_gsi].dom = d;
239 if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI_TRANSLATE )
240 {
241 hvm_irq_dpci->mirq[machine_gsi].flags = HVM_IRQ_DPCI_MACH_MSI |
242 HVM_IRQ_DPCI_GUEST_PCI |
243 HVM_IRQ_DPCI_TRANSLATE;
244 share = 0;
245 }
246 else /* PT_IRQ_TYPE_PCI */
247 {
248 hvm_irq_dpci->mirq[machine_gsi].flags = HVM_IRQ_DPCI_MACH_PCI |
249 HVM_IRQ_DPCI_GUEST_PCI;
250 share = BIND_PIRQ__WILL_SHARE;
251 }
253 /* Init timer before binding */
254 if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
255 init_timer(&hvm_irq_dpci->hvm_timer[vector],
256 pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
257 /* Deal with gsi for legacy devices */
258 rc = pirq_guest_bind(d->vcpu[0], machine_gsi, share);
259 if ( unlikely(rc) )
260 {
261 if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
262 kill_timer(&hvm_irq_dpci->hvm_timer[vector]);
263 hvm_irq_dpci->mirq[machine_gsi].dom = NULL;
264 clear_bit(machine_gsi, hvm_irq_dpci->mapping);
265 list_del(&girq->list);
266 xfree(girq);
267 list_del(&digl->list);
268 hvm_irq_dpci->link_cnt[link]--;
269 spin_unlock(&d->event_lock);
270 xfree(digl);
271 return rc;
272 }
273 }
275 gdprintk(XENLOG_INFO VTDPREFIX,
276 "VT-d irq bind: m_irq = %x device = %x intx = %x\n",
277 machine_gsi, device, intx);
278 }
279 spin_unlock(&d->event_lock);
280 return 0;
281 }
283 int pt_irq_destroy_bind_vtd(
284 struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
285 {
286 struct hvm_irq_dpci *hvm_irq_dpci = NULL;
287 uint32_t machine_gsi, guest_gsi;
288 uint32_t device, intx, link;
289 struct list_head *digl_list, *tmp;
290 struct dev_intx_gsi_link *digl;
291 struct hvm_girq_dpci_mapping *girq;
293 machine_gsi = pt_irq_bind->machine_irq;
294 device = pt_irq_bind->u.pci.device;
295 intx = pt_irq_bind->u.pci.intx;
296 guest_gsi = hvm_pci_intx_gsi(device, intx);
297 link = hvm_pci_intx_link(device, intx);
299 gdprintk(XENLOG_INFO,
300 "pt_irq_destroy_bind_vtd: machine_gsi=%d "
301 "guest_gsi=%d, device=%d, intx=%d.\n",
302 machine_gsi, guest_gsi, device, intx);
303 spin_lock(&d->event_lock);
305 hvm_irq_dpci = domain_get_irq_dpci(d);
307 if ( hvm_irq_dpci == NULL )
308 {
309 spin_unlock(&d->event_lock);
310 return -EINVAL;
311 }
313 hvm_irq_dpci->link_cnt[link]--;
315 list_for_each_entry ( girq, &hvm_irq_dpci->girq[guest_gsi], list )
316 {
317 if ( girq->machine_gsi == machine_gsi )
318 {
319 list_del(&girq->list);
320 xfree(girq);
321 break;
322 }
323 }
325 /* clear the mirq info */
326 if ( test_bit(machine_gsi, hvm_irq_dpci->mapping))
327 {
328 list_for_each_safe ( digl_list, tmp,
329 &hvm_irq_dpci->mirq[machine_gsi].digl_list )
330 {
331 digl = list_entry(digl_list,
332 struct dev_intx_gsi_link, list);
333 if ( digl->device == device &&
334 digl->intx == intx &&
335 digl->link == link &&
336 digl->gsi == guest_gsi )
337 {
338 list_del(&digl->list);
339 xfree(digl);
340 }
341 }
343 if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) )
344 {
345 pirq_guest_unbind(d, machine_gsi);
346 msixtbl_pt_unregister(d, machine_gsi);
347 if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
348 kill_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]);
349 hvm_irq_dpci->mirq[machine_gsi].dom = NULL;
350 hvm_irq_dpci->mirq[machine_gsi].flags = 0;
351 clear_bit(machine_gsi, hvm_irq_dpci->mapping);
352 }
353 }
354 spin_unlock(&d->event_lock);
355 gdprintk(XENLOG_INFO,
356 "XEN_DOMCTL_irq_unmapping: m_irq = %x device = %x intx = %x\n",
357 machine_gsi, device, intx);
359 return 0;
360 }
362 int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
363 {
364 struct hvm_irq_dpci *dpci = domain_get_irq_dpci(d);
366 ASSERT(spin_is_locked(&irq_desc[domain_irq_to_vector(d, mirq)].lock));
367 if ( !iommu_enabled || (d == dom0) || !dpci ||
368 !test_bit(mirq, dpci->mapping))
369 return 0;
371 /*
372 * Set a timer here to avoid situations where the IRQ line is shared, and
373 * the device belonging to the pass-through guest is not yet active. In
374 * this case the guest may not pick up the interrupt (e.g., masked at the
375 * PIC) and we need to detect that.
376 */
377 set_bit(mirq, dpci->dirq_mask);
378 if ( pt_irq_need_timer(dpci->mirq[mirq].flags) )
379 set_timer(&dpci->hvm_timer[domain_irq_to_vector(d, mirq)],
380 NOW() + PT_IRQ_TIME_OUT);
381 vcpu_kick(d->vcpu[0]);
383 return 1;
384 }
386 #ifdef SUPPORT_MSI_REMAPPING
387 /* called with d->event_lock held */
388 static void __msi_pirq_eoi(struct domain *d, int pirq)
389 {
390 struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
391 irq_desc_t *desc;
393 if ( ( pirq >= 0 ) && ( pirq < d->nr_pirqs ) &&
394 test_bit(pirq, hvm_irq_dpci->mapping) &&
395 ( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MACH_MSI) )
396 {
397 BUG_ON(!local_irq_is_enabled());
398 desc = domain_spin_lock_irq_desc(d, pirq, NULL);
399 if ( !desc )
400 return;
402 desc->status &= ~IRQ_INPROGRESS;
403 spin_unlock_irq(&desc->lock);
405 pirq_guest_eoi(d, pirq);
406 }
407 }
409 void hvm_dpci_msi_eoi(struct domain *d, int vector)
410 {
411 struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
412 int pirq;
414 if ( !iommu_enabled || (hvm_irq_dpci == NULL) )
415 return;
417 spin_lock(&d->event_lock);
419 pirq = hvm_irq_dpci->msi_gvec_pirq[vector];
420 __msi_pirq_eoi(d, pirq);
422 spin_unlock(&d->event_lock);
423 }
425 extern int vmsi_deliver(struct domain *d, int pirq);
426 static int hvm_pci_msi_assert(struct domain *d, int pirq)
427 {
428 return vmsi_deliver(d, pirq);
429 }
430 #endif
432 void hvm_dirq_assist(struct vcpu *v)
433 {
434 unsigned int irq;
435 uint32_t device, intx;
436 struct domain *d = v->domain;
437 struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
438 struct dev_intx_gsi_link *digl;
440 if ( !iommu_enabled || (v->vcpu_id != 0) || (hvm_irq_dpci == NULL) )
441 return;
443 for ( irq = find_first_bit(hvm_irq_dpci->dirq_mask, d->nr_pirqs);
444 irq < d->nr_pirqs;
445 irq = find_next_bit(hvm_irq_dpci->dirq_mask, d->nr_pirqs, irq + 1) )
446 {
447 if ( !test_and_clear_bit(irq, hvm_irq_dpci->dirq_mask) )
448 continue;
450 spin_lock(&d->event_lock);
451 #ifdef SUPPORT_MSI_REMAPPING
452 if ( hvm_irq_dpci->mirq[irq].flags & HVM_IRQ_DPCI_GUEST_MSI )
453 {
454 hvm_pci_msi_assert(d, irq);
455 spin_unlock(&d->event_lock);
456 continue;
457 }
458 #endif
459 if ( pt_irq_need_timer(hvm_irq_dpci->mirq[irq].flags) )
460 stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)]);
462 list_for_each_entry ( digl, &hvm_irq_dpci->mirq[irq].digl_list, list )
463 {
464 device = digl->device;
465 intx = digl->intx;
466 hvm_pci_intx_assert(d, device, intx);
467 hvm_irq_dpci->mirq[irq].pending++;
469 #ifdef SUPPORT_MSI_REMAPPING
470 if ( hvm_irq_dpci->mirq[irq].flags & HVM_IRQ_DPCI_TRANSLATE )
471 {
472 /* for translated MSI to INTx interrupt, eoi as early as possible */
473 __msi_pirq_eoi(d, irq);
474 }
475 #endif
476 }
478 /*
479 * Set a timer to see if the guest can finish the interrupt or not. For
480 * example, the guest OS may unmask the PIC during boot, before the
481 * guest driver is loaded. hvm_pci_intx_assert() may succeed, but the
482 * guest will never deal with the irq, then the physical interrupt line
483 * will never be deasserted.
484 */
485 if ( pt_irq_need_timer(hvm_irq_dpci->mirq[irq].flags) )
486 set_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)],
487 NOW() + PT_IRQ_TIME_OUT);
488 spin_unlock(&d->event_lock);
489 }
490 }
492 static void __hvm_dpci_eoi(struct domain *d,
493 struct hvm_irq_dpci *hvm_irq_dpci,
494 struct hvm_girq_dpci_mapping *girq,
495 union vioapic_redir_entry *ent)
496 {
497 uint32_t device, intx, machine_gsi;
499 device = girq->device;
500 intx = girq->intx;
501 hvm_pci_intx_deassert(d, device, intx);
503 machine_gsi = girq->machine_gsi;
505 /*
506 * No need to get vector lock for timer
507 * since interrupt is still not EOIed
508 */
509 if ( --hvm_irq_dpci->mirq[machine_gsi].pending ||
510 ( ent && ent->fields.mask ) ||
511 ! pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
512 return;
514 stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]);
515 pirq_guest_eoi(d, machine_gsi);
516 }
518 void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
519 union vioapic_redir_entry *ent)
520 {
521 struct hvm_irq_dpci *hvm_irq_dpci;
522 struct hvm_girq_dpci_mapping *girq;
524 if ( !iommu_enabled )
525 return;
527 if ( guest_gsi < NR_ISAIRQS )
528 {
529 hvm_dpci_isairq_eoi(d, guest_gsi);
530 return;
531 }
533 spin_lock(&d->event_lock);
534 hvm_irq_dpci = domain_get_irq_dpci(d);
536 if ( !hvm_irq_dpci )
537 goto unlock;
539 list_for_each_entry ( girq, &hvm_irq_dpci->girq[guest_gsi], list )
540 __hvm_dpci_eoi(d, hvm_irq_dpci, girq, ent);
542 unlock:
543 spin_unlock(&d->event_lock);
544 }