1*f6108d72SJean-Philippe Brucker #include <errno.h> 2*f6108d72SJean-Philippe Brucker #include <stdlib.h> 3*f6108d72SJean-Philippe Brucker 4*f6108d72SJean-Philippe Brucker #include "kvm/irq.h" 5*f6108d72SJean-Philippe Brucker #include "kvm/kvm.h" 6*f6108d72SJean-Philippe Brucker #include "kvm/util.h" 7*f6108d72SJean-Philippe Brucker 8*f6108d72SJean-Philippe Brucker #include "arm-common/gic.h" 9*f6108d72SJean-Philippe Brucker 10*f6108d72SJean-Philippe Brucker #define GICV2M_MSI_TYPER 0x008 11*f6108d72SJean-Philippe Brucker #define GICV2M_MSI_SETSPI 0x040 12*f6108d72SJean-Philippe Brucker #define GICV2M_MSI_IIDR 0xfcc 13*f6108d72SJean-Philippe Brucker 14*f6108d72SJean-Philippe Brucker #define GICV2M_SPI_MASK 0x3ff 15*f6108d72SJean-Philippe Brucker #define GICV2M_MSI_TYPER_VAL(start, nr) \ 16*f6108d72SJean-Philippe Brucker (((start) & GICV2M_SPI_MASK) << 16 | ((nr) & GICV2M_SPI_MASK)) 17*f6108d72SJean-Philippe Brucker 18*f6108d72SJean-Philippe Brucker struct gicv2m_chip { 19*f6108d72SJean-Philippe Brucker int first_spi; 20*f6108d72SJean-Philippe Brucker int num_spis; 21*f6108d72SJean-Philippe Brucker int *spis; 22*f6108d72SJean-Philippe Brucker u64 base; 23*f6108d72SJean-Philippe Brucker u64 size; 24*f6108d72SJean-Philippe Brucker }; 25*f6108d72SJean-Philippe Brucker 26*f6108d72SJean-Philippe Brucker static struct gicv2m_chip v2m; 27*f6108d72SJean-Philippe Brucker 28*f6108d72SJean-Philippe Brucker /* 29*f6108d72SJean-Philippe Brucker * MSI routing is setup lazily, when the guest writes the MSI tables. The guest 30*f6108d72SJean-Philippe Brucker * writes which SPI is associated to an MSI vector into the message data field. 31*f6108d72SJean-Philippe Brucker * The IRQ code notifies us of any change to MSI routing via this callback. 32*f6108d72SJean-Philippe Brucker * Store the MSI->SPI translation for later. 33*f6108d72SJean-Philippe Brucker * 34*f6108d72SJean-Philippe Brucker * Data is the GIC interrupt ID, that includes SGIs and PPIs. SGIs at 0-15, PPIs 35*f6108d72SJean-Philippe Brucker * are 16-31 and SPIs are 32-1019. What we're saving for later is the MSI's GSI 36*f6108d72SJean-Philippe Brucker * number, a logical ID used by KVM for routing. The GSI of an SPI is implicitly 37*f6108d72SJean-Philippe Brucker * defined by KVM to be its pin number (SPI index), and the GSI of an MSI is 38*f6108d72SJean-Philippe Brucker * allocated by kvmtool. 39*f6108d72SJean-Philippe Brucker */ 40*f6108d72SJean-Philippe Brucker static int gicv2m_update_routing(struct kvm *kvm, 41*f6108d72SJean-Philippe Brucker struct kvm_irq_routing_entry *entry) 42*f6108d72SJean-Philippe Brucker { 43*f6108d72SJean-Philippe Brucker int spi; 44*f6108d72SJean-Philippe Brucker 45*f6108d72SJean-Philippe Brucker if (entry->type != KVM_IRQ_ROUTING_MSI) 46*f6108d72SJean-Philippe Brucker return -EINVAL; 47*f6108d72SJean-Philippe Brucker 48*f6108d72SJean-Philippe Brucker if (!entry->u.msi.address_hi && !entry->u.msi.address_lo) 49*f6108d72SJean-Philippe Brucker return 0; 50*f6108d72SJean-Philippe Brucker 51*f6108d72SJean-Philippe Brucker spi = entry->u.msi.data & GICV2M_SPI_MASK; 52*f6108d72SJean-Philippe Brucker if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) { 53*f6108d72SJean-Philippe Brucker pr_err("invalid SPI number %d", spi); 54*f6108d72SJean-Philippe Brucker return -EINVAL; 55*f6108d72SJean-Philippe Brucker } 56*f6108d72SJean-Philippe Brucker 57*f6108d72SJean-Philippe Brucker v2m.spis[spi - v2m.first_spi] = entry->gsi; 58*f6108d72SJean-Philippe Brucker 59*f6108d72SJean-Philippe Brucker return 0; 60*f6108d72SJean-Philippe Brucker } 61*f6108d72SJean-Philippe Brucker 62*f6108d72SJean-Philippe Brucker /* 63*f6108d72SJean-Philippe Brucker * Find SPI bound to the given MSI and return the associated GSI. 64*f6108d72SJean-Philippe Brucker */ 65*f6108d72SJean-Philippe Brucker static int gicv2m_translate_gsi(struct kvm *kvm, u32 gsi) 66*f6108d72SJean-Philippe Brucker { 67*f6108d72SJean-Philippe Brucker int i; 68*f6108d72SJean-Philippe Brucker 69*f6108d72SJean-Philippe Brucker for (i = 0; i < v2m.num_spis; i++) { 70*f6108d72SJean-Philippe Brucker if (v2m.spis[i] == (int)gsi) 71*f6108d72SJean-Philippe Brucker return i + v2m.first_spi - KVM_IRQ_OFFSET; 72*f6108d72SJean-Philippe Brucker } 73*f6108d72SJean-Philippe Brucker 74*f6108d72SJean-Philippe Brucker /* Not an MSI */ 75*f6108d72SJean-Philippe Brucker return gsi; 76*f6108d72SJean-Philippe Brucker } 77*f6108d72SJean-Philippe Brucker 78*f6108d72SJean-Philippe Brucker static bool gicv2m_can_signal_msi(struct kvm *kvm) 79*f6108d72SJean-Philippe Brucker { 80*f6108d72SJean-Philippe Brucker return true; 81*f6108d72SJean-Philippe Brucker } 82*f6108d72SJean-Philippe Brucker 83*f6108d72SJean-Philippe Brucker /* 84*f6108d72SJean-Philippe Brucker * Instead of setting up MSI routes, virtual devices can also trigger them 85*f6108d72SJean-Philippe Brucker * manually (like a direct write to MSI_SETSPI). In this case, trigger the SPI 86*f6108d72SJean-Philippe Brucker * directly. 87*f6108d72SJean-Philippe Brucker */ 88*f6108d72SJean-Philippe Brucker static int gicv2m_signal_msi(struct kvm *kvm, struct kvm_msi *msi) 89*f6108d72SJean-Philippe Brucker { 90*f6108d72SJean-Philippe Brucker int spi = msi->data & GICV2M_SPI_MASK; 91*f6108d72SJean-Philippe Brucker 92*f6108d72SJean-Philippe Brucker if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) { 93*f6108d72SJean-Philippe Brucker pr_err("invalid SPI number %d", spi); 94*f6108d72SJean-Philippe Brucker return -EINVAL; 95*f6108d72SJean-Philippe Brucker } 96*f6108d72SJean-Philippe Brucker 97*f6108d72SJean-Philippe Brucker kvm__irq_trigger(kvm, spi); 98*f6108d72SJean-Philippe Brucker return 0; 99*f6108d72SJean-Philippe Brucker } 100*f6108d72SJean-Philippe Brucker 101*f6108d72SJean-Philippe Brucker static struct msi_routing_ops gicv2m_routing = { 102*f6108d72SJean-Philippe Brucker .update_route = gicv2m_update_routing, 103*f6108d72SJean-Philippe Brucker .translate_gsi = gicv2m_translate_gsi, 104*f6108d72SJean-Philippe Brucker .can_signal_msi = gicv2m_can_signal_msi, 105*f6108d72SJean-Philippe Brucker .signal_msi = gicv2m_signal_msi, 106*f6108d72SJean-Philippe Brucker }; 107*f6108d72SJean-Philippe Brucker 108*f6108d72SJean-Philippe Brucker static void gicv2m_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, 109*f6108d72SJean-Philippe Brucker u32 len, u8 is_write, void *ptr) 110*f6108d72SJean-Philippe Brucker { 111*f6108d72SJean-Philippe Brucker if (is_write) 112*f6108d72SJean-Philippe Brucker return; 113*f6108d72SJean-Philippe Brucker 114*f6108d72SJean-Philippe Brucker addr -= v2m.base; 115*f6108d72SJean-Philippe Brucker 116*f6108d72SJean-Philippe Brucker switch (addr) { 117*f6108d72SJean-Philippe Brucker case GICV2M_MSI_TYPER: 118*f6108d72SJean-Philippe Brucker *(u32 *)data = GICV2M_MSI_TYPER_VAL(v2m.first_spi, 119*f6108d72SJean-Philippe Brucker v2m.num_spis); 120*f6108d72SJean-Philippe Brucker break; 121*f6108d72SJean-Philippe Brucker case GICV2M_MSI_IIDR: 122*f6108d72SJean-Philippe Brucker *(u32 *)data = 0x0; 123*f6108d72SJean-Philippe Brucker break; 124*f6108d72SJean-Philippe Brucker } 125*f6108d72SJean-Philippe Brucker } 126*f6108d72SJean-Philippe Brucker 127*f6108d72SJean-Philippe Brucker int gic__create_gicv2m_frame(struct kvm *kvm, u64 base) 128*f6108d72SJean-Philippe Brucker { 129*f6108d72SJean-Philippe Brucker int i; 130*f6108d72SJean-Philippe Brucker int irq = irq__alloc_line(); 131*f6108d72SJean-Philippe Brucker 132*f6108d72SJean-Philippe Brucker v2m = (struct gicv2m_chip) { 133*f6108d72SJean-Philippe Brucker .first_spi = irq, /* Includes GIC_SPI_IRQ_BASE */ 134*f6108d72SJean-Philippe Brucker .num_spis = 64, /* arbitrary */ 135*f6108d72SJean-Philippe Brucker .base = base, 136*f6108d72SJean-Philippe Brucker .size = KVM_VGIC_V2M_SIZE, 137*f6108d72SJean-Philippe Brucker }; 138*f6108d72SJean-Philippe Brucker 139*f6108d72SJean-Philippe Brucker v2m.spis = calloc(v2m.num_spis, sizeof(int)); 140*f6108d72SJean-Philippe Brucker if (!v2m.spis) 141*f6108d72SJean-Philippe Brucker return -ENOMEM; 142*f6108d72SJean-Philippe Brucker 143*f6108d72SJean-Philippe Brucker v2m.spis[0] = -1; 144*f6108d72SJean-Philippe Brucker for (i = 1; i < v2m.num_spis; i++) { 145*f6108d72SJean-Philippe Brucker irq__alloc_line(); 146*f6108d72SJean-Philippe Brucker v2m.spis[i] = -1; 147*f6108d72SJean-Philippe Brucker } 148*f6108d72SJean-Philippe Brucker 149*f6108d72SJean-Philippe Brucker msi_routing_ops = &gicv2m_routing; 150*f6108d72SJean-Philippe Brucker 151*f6108d72SJean-Philippe Brucker return kvm__register_mmio(kvm, base, KVM_VGIC_V2M_SIZE, false, 152*f6108d72SJean-Philippe Brucker gicv2m_mmio_callback, kvm); 153*f6108d72SJean-Philippe Brucker } 154