xref: /kvmtool/riscv/pci.c (revision cdd7d8cc0109bb8e2a0a04c5fe904b5ad4f07a80)
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