vgic-irqfd.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. * Copyright (C) 2015, 2016 ARM Ltd.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <linux/kvm.h>
  17. #include <linux/kvm_host.h>
  18. #include <trace/events/kvm.h>
  19. #include <kvm/arm_vgic.h>
  20. #include "vgic.h"
  21. /**
  22. * vgic_irqfd_set_irq: inject the IRQ corresponding to the
  23. * irqchip routing entry
  24. *
  25. * This is the entry point for irqfd IRQ injection
  26. */
  27. static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
  28. struct kvm *kvm, int irq_source_id,
  29. int level, bool line_status)
  30. {
  31. unsigned int spi_id = e->irqchip.pin + VGIC_NR_PRIVATE_IRQS;
  32. if (!vgic_valid_spi(kvm, spi_id))
  33. return -EINVAL;
  34. return kvm_vgic_inject_irq(kvm, 0, spi_id, level, NULL);
  35. }
  36. /**
  37. * kvm_set_routing_entry: populate a kvm routing entry
  38. * from a user routing entry
  39. *
  40. * @kvm: the VM this entry is applied to
  41. * @e: kvm kernel routing entry handle
  42. * @ue: user api routing entry handle
  43. * return 0 on success, -EINVAL on errors.
  44. */
  45. int kvm_set_routing_entry(struct kvm *kvm,
  46. struct kvm_kernel_irq_routing_entry *e,
  47. const struct kvm_irq_routing_entry *ue)
  48. {
  49. int r = -EINVAL;
  50. switch (ue->type) {
  51. case KVM_IRQ_ROUTING_IRQCHIP:
  52. e->set = vgic_irqfd_set_irq;
  53. e->irqchip.irqchip = ue->u.irqchip.irqchip;
  54. e->irqchip.pin = ue->u.irqchip.pin;
  55. if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) ||
  56. (e->irqchip.irqchip >= KVM_NR_IRQCHIPS))
  57. goto out;
  58. break;
  59. case KVM_IRQ_ROUTING_MSI:
  60. e->set = kvm_set_msi;
  61. e->msi.address_lo = ue->u.msi.address_lo;
  62. e->msi.address_hi = ue->u.msi.address_hi;
  63. e->msi.data = ue->u.msi.data;
  64. e->msi.flags = ue->flags;
  65. e->msi.devid = ue->u.msi.devid;
  66. break;
  67. default:
  68. goto out;
  69. }
  70. r = 0;
  71. out:
  72. return r;
  73. }
  74. /**
  75. * kvm_set_msi: inject the MSI corresponding to the
  76. * MSI routing entry
  77. *
  78. * This is the entry point for irqfd MSI injection
  79. * and userspace MSI injection.
  80. */
  81. int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
  82. struct kvm *kvm, int irq_source_id,
  83. int level, bool line_status)
  84. {
  85. struct kvm_msi msi;
  86. msi.address_lo = e->msi.address_lo;
  87. msi.address_hi = e->msi.address_hi;
  88. msi.data = e->msi.data;
  89. msi.flags = e->msi.flags;
  90. msi.devid = e->msi.devid;
  91. if (!vgic_has_its(kvm))
  92. return -ENODEV;
  93. if (!level)
  94. return -1;
  95. return vgic_its_inject_msi(kvm, &msi);
  96. }
  97. int kvm_vgic_setup_default_irq_routing(struct kvm *kvm)
  98. {
  99. struct kvm_irq_routing_entry *entries;
  100. struct vgic_dist *dist = &kvm->arch.vgic;
  101. u32 nr = dist->nr_spis;
  102. int i, ret;
  103. entries = kcalloc(nr, sizeof(*entries), GFP_KERNEL);
  104. if (!entries)
  105. return -ENOMEM;
  106. for (i = 0; i < nr; i++) {
  107. entries[i].gsi = i;
  108. entries[i].type = KVM_IRQ_ROUTING_IRQCHIP;
  109. entries[i].u.irqchip.irqchip = 0;
  110. entries[i].u.irqchip.pin = i;
  111. }
  112. ret = kvm_set_irq_routing(kvm, entries, nr, 0);
  113. kfree(entries);
  114. return ret;
  115. }