116242d27SWill Deacon #include "kvm/devices.h" 216242d27SWill Deacon #include "kvm/fdt.h" 36078a454SJean-Philippe Brucker #include "kvm/kvm.h" 416242d27SWill Deacon #include "kvm/of_pci.h" 516242d27SWill Deacon #include "kvm/pci.h" 616242d27SWill Deacon #include "kvm/util.h" 716242d27SWill Deacon 816242d27SWill Deacon #include "arm-common/pci.h" 916242d27SWill Deacon 1016242d27SWill Deacon /* 1116242d27SWill Deacon * An entry in the interrupt-map table looks like: 1216242d27SWill Deacon * <pci unit address> <pci interrupt pin> <gic phandle> <gic interrupt> 1316242d27SWill Deacon */ 1416242d27SWill Deacon 1516242d27SWill Deacon struct of_gic_irq { 1616242d27SWill Deacon u32 type, num, flags; 1716242d27SWill Deacon } __attribute__((packed)); 1816242d27SWill Deacon 1916242d27SWill Deacon struct of_interrupt_map_entry { 2016242d27SWill Deacon struct of_pci_irq_mask pci_irq_mask; 2116242d27SWill Deacon u32 gic_phandle; 2214421de9SAndre Przywara u32 gic_addr_hi; 2314421de9SAndre Przywara u32 gic_addr_lo; 2416242d27SWill Deacon struct of_gic_irq gic_irq; 2516242d27SWill Deacon } __attribute__((packed)); 2616242d27SWill Deacon 270063d50cSAndre Przywara void pci__generate_fdt_nodes(void *fdt) 2816242d27SWill Deacon { 2916242d27SWill Deacon struct device_header *dev_hdr; 3016242d27SWill Deacon struct of_interrupt_map_entry irq_map[OF_PCI_IRQ_MAP_MAX]; 3116242d27SWill Deacon unsigned nentries = 0; 321fcf0d77SWill Deacon /* Bus range */ 33c94286f0SAlexandru Elisei u32 bus_range[] = { cpu_to_fdt32(0), cpu_to_fdt32(0), }; 341fcf0d77SWill Deacon /* Configuration Space */ 351fcf0d77SWill Deacon u64 cfg_reg_prop[] = { cpu_to_fdt64(KVM_PCI_CFG_AREA), 361fcf0d77SWill Deacon cpu_to_fdt64(ARM_PCI_CFG_SIZE), }; 371fcf0d77SWill Deacon /* Describe the memory ranges */ 3816242d27SWill Deacon struct of_pci_ranges_entry ranges[] = { 3916242d27SWill Deacon { 4016242d27SWill Deacon .pci_addr = { 4116242d27SWill Deacon .hi = cpu_to_fdt32(of_pci_b_ss(OF_PCI_SS_IO)), 4216242d27SWill Deacon .mid = 0, 4316242d27SWill Deacon .lo = 0, 4416242d27SWill Deacon }, 4516242d27SWill Deacon .cpu_addr = cpu_to_fdt64(KVM_IOPORT_AREA), 4616242d27SWill Deacon .length = cpu_to_fdt64(ARM_IOPORT_SIZE), 4716242d27SWill Deacon }, 4816242d27SWill Deacon { 4916242d27SWill Deacon .pci_addr = { 5016242d27SWill Deacon .hi = cpu_to_fdt32(of_pci_b_ss(OF_PCI_SS_M32)), 511fcf0d77SWill Deacon .mid = cpu_to_fdt32(KVM_PCI_MMIO_AREA >> 32), 521fcf0d77SWill Deacon .lo = cpu_to_fdt32(KVM_PCI_MMIO_AREA), 5316242d27SWill Deacon }, 5416242d27SWill Deacon .cpu_addr = cpu_to_fdt64(KVM_PCI_MMIO_AREA), 5516242d27SWill Deacon .length = cpu_to_fdt64(ARM_PCI_MMIO_SIZE), 5616242d27SWill Deacon }, 5716242d27SWill Deacon }; 5816242d27SWill Deacon 5916242d27SWill Deacon /* Boilerplate PCI properties */ 6016242d27SWill Deacon _FDT(fdt_begin_node(fdt, "pci")); 611fcf0d77SWill Deacon _FDT(fdt_property_string(fdt, "device_type", "pci")); 6216242d27SWill Deacon _FDT(fdt_property_cell(fdt, "#address-cells", 0x3)); 6316242d27SWill Deacon _FDT(fdt_property_cell(fdt, "#size-cells", 0x2)); 6416242d27SWill Deacon _FDT(fdt_property_cell(fdt, "#interrupt-cells", 0x1)); 65e69b7663SAlexandru Elisei _FDT(fdt_property_string(fdt, "compatible", "pci-host-ecam-generic")); 669a8af7e3SRobin Murphy _FDT(fdt_property(fdt, "dma-coherent", NULL, 0)); 6716242d27SWill Deacon 681fcf0d77SWill Deacon _FDT(fdt_property(fdt, "bus-range", bus_range, sizeof(bus_range))); 691fcf0d77SWill Deacon _FDT(fdt_property(fdt, "reg", &cfg_reg_prop, sizeof(cfg_reg_prop))); 7016242d27SWill Deacon _FDT(fdt_property(fdt, "ranges", ranges, sizeof(ranges))); 7114421de9SAndre Przywara _FDT(fdt_property_cell(fdt, "msi-parent", PHANDLE_MSI)); 7216242d27SWill Deacon 7316242d27SWill Deacon /* Generate the interrupt map ... */ 7416242d27SWill Deacon dev_hdr = device__first_dev(DEVICE_BUS_PCI); 7516242d27SWill Deacon while (dev_hdr && nentries < ARRAY_SIZE(irq_map)) { 7616242d27SWill Deacon struct of_interrupt_map_entry *entry = &irq_map[nentries]; 7716242d27SWill Deacon struct pci_device_header *pci_hdr = dev_hdr->data; 7816242d27SWill Deacon u8 dev_num = dev_hdr->dev_num; 7916242d27SWill Deacon u8 pin = pci_hdr->irq_pin; 8016242d27SWill Deacon u8 irq = pci_hdr->irq_line; 81ff01b5dbSJean-Philippe Brucker u32 irq_flags = pci_hdr->irq_type; 8216242d27SWill Deacon 83*7a60af05SSathyam Panda /* 84*7a60af05SSathyam Panda * Avoid adding entries in "interrupt-map" for devices that 85*7a60af05SSathyam Panda * will be using advance interrupt mechanisms like MSI or 86*7a60af05SSathyam Panda * MSI-X instead of legacy interrupt pins INTA#..INTD# 87*7a60af05SSathyam Panda */ 88*7a60af05SSathyam Panda if (pin == 0) { 89*7a60af05SSathyam Panda dev_hdr = device__next_dev(dev_hdr); 90*7a60af05SSathyam Panda continue; 91*7a60af05SSathyam Panda } 92*7a60af05SSathyam Panda 9316242d27SWill Deacon *entry = (struct of_interrupt_map_entry) { 9416242d27SWill Deacon .pci_irq_mask = { 9516242d27SWill Deacon .pci_addr = { 9616242d27SWill Deacon .hi = cpu_to_fdt32(of_pci_b_ddddd(dev_num)), 9716242d27SWill Deacon .mid = 0, 9816242d27SWill Deacon .lo = 0, 9916242d27SWill Deacon }, 10016242d27SWill Deacon .pci_pin = cpu_to_fdt32(pin), 10116242d27SWill Deacon }, 1020063d50cSAndre Przywara .gic_phandle = cpu_to_fdt32(PHANDLE_GIC), 10314421de9SAndre Przywara .gic_addr_hi = 0, 10414421de9SAndre Przywara .gic_addr_lo = 0, 10516242d27SWill Deacon .gic_irq = { 10616242d27SWill Deacon .type = cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI), 10716242d27SWill Deacon .num = cpu_to_fdt32(irq - GIC_SPI_IRQ_BASE), 108ff01b5dbSJean-Philippe Brucker .flags = cpu_to_fdt32(irq_flags), 10916242d27SWill Deacon }, 11016242d27SWill Deacon }; 11116242d27SWill Deacon 11216242d27SWill Deacon nentries++; 11316242d27SWill Deacon dev_hdr = device__next_dev(dev_hdr); 11416242d27SWill Deacon } 11516242d27SWill Deacon 11616242d27SWill Deacon _FDT(fdt_property(fdt, "interrupt-map", irq_map, 11716242d27SWill Deacon sizeof(struct of_interrupt_map_entry) * nentries)); 11816242d27SWill Deacon 11916242d27SWill Deacon /* ... and the corresponding mask. */ 12016242d27SWill Deacon if (nentries) { 12116242d27SWill Deacon struct of_pci_irq_mask irq_mask = { 12216242d27SWill Deacon .pci_addr = { 12316242d27SWill Deacon .hi = cpu_to_fdt32(of_pci_b_ddddd(-1)), 12416242d27SWill Deacon .mid = 0, 12516242d27SWill Deacon .lo = 0, 12616242d27SWill Deacon }, 12716242d27SWill Deacon .pci_pin = cpu_to_fdt32(7), 12816242d27SWill Deacon }; 12916242d27SWill Deacon 13016242d27SWill Deacon _FDT(fdt_property(fdt, "interrupt-map-mask", &irq_mask, 13116242d27SWill Deacon sizeof(irq_mask))); 13216242d27SWill Deacon } 13316242d27SWill Deacon 13416242d27SWill Deacon _FDT(fdt_end_node(fdt)); 13516242d27SWill Deacon } 136