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