xref: /kvmtool/arm/pci.c (revision 16242d272132662650872c01a609cab001b11cae)
1*16242d27SWill Deacon #include "kvm/devices.h"
2*16242d27SWill Deacon #include "kvm/fdt.h"
3*16242d27SWill Deacon #include "kvm/of_pci.h"
4*16242d27SWill Deacon #include "kvm/pci.h"
5*16242d27SWill Deacon #include "kvm/util.h"
6*16242d27SWill Deacon 
7*16242d27SWill Deacon #include "arm-common/pci.h"
8*16242d27SWill Deacon 
9*16242d27SWill Deacon /*
10*16242d27SWill Deacon  * An entry in the interrupt-map table looks like:
11*16242d27SWill Deacon  * <pci unit address> <pci interrupt pin> <gic phandle> <gic interrupt>
12*16242d27SWill Deacon  */
13*16242d27SWill Deacon 
14*16242d27SWill Deacon struct of_gic_irq {
15*16242d27SWill Deacon 	u32 type, num, flags;
16*16242d27SWill Deacon } __attribute__((packed));
17*16242d27SWill Deacon 
18*16242d27SWill Deacon struct of_interrupt_map_entry {
19*16242d27SWill Deacon 	struct of_pci_irq_mask		pci_irq_mask;
20*16242d27SWill Deacon 	u32				gic_phandle;
21*16242d27SWill Deacon 	struct of_gic_irq		gic_irq;
22*16242d27SWill Deacon } __attribute__((packed));
23*16242d27SWill Deacon 
24*16242d27SWill Deacon void pci__generate_fdt_nodes(void *fdt, u32 gic_phandle)
25*16242d27SWill Deacon {
26*16242d27SWill Deacon 	struct device_header *dev_hdr;
27*16242d27SWill Deacon 	struct of_interrupt_map_entry irq_map[OF_PCI_IRQ_MAP_MAX];
28*16242d27SWill Deacon 	unsigned nentries = 0;
29*16242d27SWill Deacon 	/* Describe the memory ranges (config and memory) */
30*16242d27SWill Deacon 	struct of_pci_ranges_entry ranges[] = {
31*16242d27SWill Deacon 		{
32*16242d27SWill Deacon 			.pci_addr = {
33*16242d27SWill Deacon 				.hi	= cpu_to_fdt32(of_pci_b_ss(OF_PCI_SS_CONFIG)),
34*16242d27SWill Deacon 				.mid	= 0,
35*16242d27SWill Deacon 				.lo	= 0,
36*16242d27SWill Deacon 			},
37*16242d27SWill Deacon 			.cpu_addr	= cpu_to_fdt64(KVM_PCI_CFG_AREA),
38*16242d27SWill Deacon 			.length		= cpu_to_fdt64(ARM_PCI_CFG_SIZE),
39*16242d27SWill Deacon 		},
40*16242d27SWill Deacon 		{
41*16242d27SWill Deacon 			.pci_addr = {
42*16242d27SWill Deacon 				.hi	= cpu_to_fdt32(of_pci_b_ss(OF_PCI_SS_IO)),
43*16242d27SWill Deacon 				.mid	= 0,
44*16242d27SWill Deacon 				.lo	= 0,
45*16242d27SWill Deacon 			},
46*16242d27SWill Deacon 			.cpu_addr	= cpu_to_fdt64(KVM_IOPORT_AREA),
47*16242d27SWill Deacon 			.length		= cpu_to_fdt64(ARM_IOPORT_SIZE),
48*16242d27SWill Deacon 		},
49*16242d27SWill Deacon 		{
50*16242d27SWill Deacon 			.pci_addr = {
51*16242d27SWill Deacon 				.hi	= cpu_to_fdt32(of_pci_b_ss(OF_PCI_SS_M32)),
52*16242d27SWill Deacon 				.mid	= 0,
53*16242d27SWill Deacon 				.lo	= 0,
54*16242d27SWill Deacon 			},
55*16242d27SWill Deacon 			.cpu_addr	= cpu_to_fdt64(KVM_PCI_MMIO_AREA),
56*16242d27SWill Deacon 			.length		= cpu_to_fdt64(ARM_PCI_MMIO_SIZE),
57*16242d27SWill Deacon 		},
58*16242d27SWill Deacon 	};
59*16242d27SWill Deacon 
60*16242d27SWill Deacon 	/* Boilerplate PCI properties */
61*16242d27SWill Deacon 	_FDT(fdt_begin_node(fdt, "pci"));
62*16242d27SWill Deacon 	_FDT(fdt_property_cell(fdt, "#address-cells", 0x3));
63*16242d27SWill Deacon 	_FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
64*16242d27SWill Deacon 	_FDT(fdt_property_cell(fdt, "#interrupt-cells", 0x1));
65*16242d27SWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "linux,pci-virt"));
66*16242d27SWill Deacon 
67*16242d27SWill Deacon 	_FDT(fdt_property(fdt, "ranges", ranges, sizeof(ranges)));
68*16242d27SWill Deacon 
69*16242d27SWill Deacon 	/* Generate the interrupt map ... */
70*16242d27SWill Deacon 	dev_hdr = device__first_dev(DEVICE_BUS_PCI);
71*16242d27SWill Deacon 	while (dev_hdr && nentries < ARRAY_SIZE(irq_map)) {
72*16242d27SWill Deacon 		struct of_interrupt_map_entry *entry = &irq_map[nentries];
73*16242d27SWill Deacon 		struct pci_device_header *pci_hdr = dev_hdr->data;
74*16242d27SWill Deacon 		u8 dev_num = dev_hdr->dev_num;
75*16242d27SWill Deacon 		u8 pin = pci_hdr->irq_pin;
76*16242d27SWill Deacon 		u8 irq = pci_hdr->irq_line;
77*16242d27SWill Deacon 
78*16242d27SWill Deacon 		*entry = (struct of_interrupt_map_entry) {
79*16242d27SWill Deacon 			.pci_irq_mask = {
80*16242d27SWill Deacon 				.pci_addr = {
81*16242d27SWill Deacon 					.hi	= cpu_to_fdt32(of_pci_b_ddddd(dev_num)),
82*16242d27SWill Deacon 					.mid	= 0,
83*16242d27SWill Deacon 					.lo	= 0,
84*16242d27SWill Deacon 				},
85*16242d27SWill Deacon 				.pci_pin	= cpu_to_fdt32(pin),
86*16242d27SWill Deacon 			},
87*16242d27SWill Deacon 			.gic_phandle	= cpu_to_fdt32(gic_phandle),
88*16242d27SWill Deacon 			.gic_irq = {
89*16242d27SWill Deacon 				.type	= cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI),
90*16242d27SWill Deacon 				.num	= cpu_to_fdt32(irq - GIC_SPI_IRQ_BASE),
91*16242d27SWill Deacon 				.flags	= cpu_to_fdt32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI),
92*16242d27SWill Deacon 			},
93*16242d27SWill Deacon 		};
94*16242d27SWill Deacon 
95*16242d27SWill Deacon 		nentries++;
96*16242d27SWill Deacon 		dev_hdr = device__next_dev(dev_hdr);
97*16242d27SWill Deacon 	}
98*16242d27SWill Deacon 
99*16242d27SWill Deacon 	_FDT(fdt_property(fdt, "interrupt-map", irq_map,
100*16242d27SWill Deacon 			  sizeof(struct of_interrupt_map_entry) * nentries));
101*16242d27SWill Deacon 
102*16242d27SWill Deacon 	/* ... and the corresponding mask. */
103*16242d27SWill Deacon 	if (nentries) {
104*16242d27SWill Deacon 		struct of_pci_irq_mask irq_mask = {
105*16242d27SWill Deacon 			.pci_addr = {
106*16242d27SWill Deacon 				.hi	= cpu_to_fdt32(of_pci_b_ddddd(-1)),
107*16242d27SWill Deacon 				.mid	= 0,
108*16242d27SWill Deacon 				.lo	= 0,
109*16242d27SWill Deacon 			},
110*16242d27SWill Deacon 			.pci_pin	= cpu_to_fdt32(7),
111*16242d27SWill Deacon 		};
112*16242d27SWill Deacon 
113*16242d27SWill Deacon 		_FDT(fdt_property(fdt, "interrupt-map-mask", &irq_mask,
114*16242d27SWill Deacon 				  sizeof(irq_mask)));
115*16242d27SWill Deacon 	}
116*16242d27SWill Deacon 
117*16242d27SWill Deacon 	_FDT(fdt_end_node(fdt));
118*16242d27SWill Deacon }
119