xen.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * Xen PCI Frontend Stub - puts some "dummy" functions in to the Linux
  3. * x86 PCI core to support the Xen PCI Frontend
  4. *
  5. * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
  6. */
  7. #include <linux/module.h>
  8. #include <linux/init.h>
  9. #include <linux/pci.h>
  10. #include <linux/acpi.h>
  11. #include <linux/io.h>
  12. #include <asm/pci_x86.h>
  13. #include <asm/xen/hypervisor.h>
  14. #include <xen/features.h>
  15. #include <xen/events.h>
  16. #include <asm/xen/pci.h>
  17. #ifdef CONFIG_ACPI
  18. static int xen_hvm_register_pirq(u32 gsi, int triggering)
  19. {
  20. int rc, irq;
  21. struct physdev_map_pirq map_irq;
  22. int shareable = 0;
  23. char *name;
  24. if (!xen_hvm_domain())
  25. return -1;
  26. map_irq.domid = DOMID_SELF;
  27. map_irq.type = MAP_PIRQ_TYPE_GSI;
  28. map_irq.index = gsi;
  29. map_irq.pirq = -1;
  30. rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
  31. if (rc) {
  32. printk(KERN_WARNING "xen map irq failed %d\n", rc);
  33. return -1;
  34. }
  35. if (triggering == ACPI_EDGE_SENSITIVE) {
  36. shareable = 0;
  37. name = "ioapic-edge";
  38. } else {
  39. shareable = 1;
  40. name = "ioapic-level";
  41. }
  42. irq = xen_map_pirq_gsi(map_irq.pirq, gsi, shareable, name);
  43. printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
  44. return irq;
  45. }
  46. static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
  47. int trigger, int polarity)
  48. {
  49. return xen_hvm_register_pirq(gsi, trigger);
  50. }
  51. #endif
  52. #if defined(CONFIG_PCI_MSI)
  53. #include <linux/msi.h>
  54. struct xen_pci_frontend_ops *xen_pci_frontend;
  55. EXPORT_SYMBOL_GPL(xen_pci_frontend);
  56. /*
  57. * For MSI interrupts we have to use drivers/xen/event.s functions to
  58. * allocate an irq_desc and setup the right */
  59. static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
  60. {
  61. int irq, ret, i;
  62. struct msi_desc *msidesc;
  63. int *v;
  64. v = kzalloc(sizeof(int) * max(1, nvec), GFP_KERNEL);
  65. if (!v)
  66. return -ENOMEM;
  67. if (!xen_initial_domain()) {
  68. if (type == PCI_CAP_ID_MSIX)
  69. ret = xen_pci_frontend_enable_msix(dev, &v, nvec);
  70. else
  71. ret = xen_pci_frontend_enable_msi(dev, &v);
  72. if (ret)
  73. goto error;
  74. }
  75. i = 0;
  76. list_for_each_entry(msidesc, &dev->msi_list, list) {
  77. irq = xen_allocate_pirq(v[i], 0, /* not sharable */
  78. (type == PCI_CAP_ID_MSIX) ?
  79. "pcifront-msi-x" : "pcifront-msi");
  80. if (irq < 0)
  81. return -1;
  82. ret = set_irq_msi(irq, msidesc);
  83. if (ret)
  84. goto error_while;
  85. i++;
  86. }
  87. kfree(v);
  88. return 0;
  89. error_while:
  90. unbind_from_irqhandler(irq, NULL);
  91. error:
  92. if (ret == -ENODEV)
  93. dev_err(&dev->dev, "Xen PCI frontend has not registered" \
  94. " MSI/MSI-X support!\n");
  95. kfree(v);
  96. return ret;
  97. }
  98. static void xen_teardown_msi_irqs(struct pci_dev *dev)
  99. {
  100. /* Only do this when were are in non-privileged mode.*/
  101. if (!xen_initial_domain()) {
  102. struct msi_desc *msidesc;
  103. msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
  104. if (msidesc->msi_attrib.is_msix)
  105. xen_pci_frontend_disable_msix(dev);
  106. else
  107. xen_pci_frontend_disable_msi(dev);
  108. }
  109. }
  110. static void xen_teardown_msi_irq(unsigned int irq)
  111. {
  112. xen_destroy_irq(irq);
  113. }
  114. #endif
  115. static int xen_pcifront_enable_irq(struct pci_dev *dev)
  116. {
  117. int rc;
  118. int share = 1;
  119. dev_info(&dev->dev, "Xen PCI enabling IRQ: %d\n", dev->irq);
  120. if (dev->irq < 0)
  121. return -EINVAL;
  122. if (dev->irq < NR_IRQS_LEGACY)
  123. share = 0;
  124. rc = xen_allocate_pirq(dev->irq, share, "pcifront");
  125. if (rc < 0) {
  126. dev_warn(&dev->dev, "Xen PCI IRQ: %d, failed to register:%d\n",
  127. dev->irq, rc);
  128. return rc;
  129. }
  130. return 0;
  131. }
  132. int __init pci_xen_init(void)
  133. {
  134. if (!xen_pv_domain() || xen_initial_domain())
  135. return -ENODEV;
  136. printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
  137. pcibios_set_cache_line_size();
  138. pcibios_enable_irq = xen_pcifront_enable_irq;
  139. pcibios_disable_irq = NULL;
  140. #ifdef CONFIG_ACPI
  141. /* Keep ACPI out of the picture */
  142. acpi_noirq = 1;
  143. #endif
  144. #ifdef CONFIG_PCI_MSI
  145. x86_msi.setup_msi_irqs = xen_setup_msi_irqs;
  146. x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
  147. x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs;
  148. #endif
  149. return 0;
  150. }
  151. int __init pci_xen_hvm_init(void)
  152. {
  153. if (!xen_feature(XENFEAT_hvm_pirqs))
  154. return 0;
  155. #ifdef CONFIG_ACPI
  156. /*
  157. * We don't want to change the actual ACPI delivery model,
  158. * just how GSIs get registered.
  159. */
  160. __acpi_register_gsi = acpi_register_gsi_xen_hvm;
  161. #endif
  162. return 0;
  163. }