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