xref: /kvmtool/arm/pci.c (revision 7a60af05c183eb25deb1c5a333c232c42eea5944)
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