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