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