xref: /kvmtool/powerpc/spapr_pci.c (revision c481cfd579e5039b5ed6443c4905a43e53fd91aa)
1*c481cfd5SMatt Evans /*
2*c481cfd5SMatt Evans  * SPAPR PHB emulation, RTAS interface to PCI config space, device tree nodes
3*c481cfd5SMatt Evans  * for enumerated devices.
4*c481cfd5SMatt Evans  *
5*c481cfd5SMatt Evans  * Borrowed heavily from QEMU's spapr_pci.c,
6*c481cfd5SMatt Evans  * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation.
7*c481cfd5SMatt Evans  * Copyright (c) 2011 David Gibson, IBM Corporation.
8*c481cfd5SMatt Evans  *
9*c481cfd5SMatt Evans  * Modifications copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
10*c481cfd5SMatt Evans  *
11*c481cfd5SMatt Evans  * This program is free software; you can redistribute it and/or modify it
12*c481cfd5SMatt Evans  * under the terms of the GNU General Public License version 2 as published
13*c481cfd5SMatt Evans  * by the Free Software Foundation.
14*c481cfd5SMatt Evans  */
15*c481cfd5SMatt Evans 
16*c481cfd5SMatt Evans #include "spapr.h"
17*c481cfd5SMatt Evans #include "spapr_pci.h"
18*c481cfd5SMatt Evans #include "kvm/util.h"
19*c481cfd5SMatt Evans #include "kvm/pci.h"
20*c481cfd5SMatt Evans #include "libfdt.h"
21*c481cfd5SMatt Evans 
22*c481cfd5SMatt Evans #include <linux/pci_regs.h>
23*c481cfd5SMatt Evans #include <linux/byteorder.h>
24*c481cfd5SMatt Evans 
25*c481cfd5SMatt Evans 
26*c481cfd5SMatt Evans /* #define DEBUG_PHB yes */
27*c481cfd5SMatt Evans #ifdef DEBUG_PHB
28*c481cfd5SMatt Evans #define phb_dprintf(fmt, ...)					\
29*c481cfd5SMatt Evans 	do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
30*c481cfd5SMatt Evans #else
31*c481cfd5SMatt Evans #define phb_dprintf(fmt, ...)			\
32*c481cfd5SMatt Evans 	do { } while (0)
33*c481cfd5SMatt Evans #endif
34*c481cfd5SMatt Evans 
35*c481cfd5SMatt Evans static const uint32_t bars[] = {
36*c481cfd5SMatt Evans 	PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1,
37*c481cfd5SMatt Evans 	PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3,
38*c481cfd5SMatt Evans 	PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5
39*c481cfd5SMatt Evans 	/*, PCI_ROM_ADDRESS*/
40*c481cfd5SMatt Evans };
41*c481cfd5SMatt Evans 
42*c481cfd5SMatt Evans #define PCI_NUM_REGIONS		7
43*c481cfd5SMatt Evans 
44*c481cfd5SMatt Evans /* Macros to operate with address in OF binding to PCI */
45*c481cfd5SMatt Evans #define b_x(x, p, l)	(((x) & ((1<<(l))-1)) << (p))
46*c481cfd5SMatt Evans #define b_n(x)		b_x((x), 31, 1) /* 0 if relocatable */
47*c481cfd5SMatt Evans #define b_p(x)		b_x((x), 30, 1) /* 1 if prefetchable */
48*c481cfd5SMatt Evans #define b_t(x)		b_x((x), 29, 1) /* 1 if the address is aliased */
49*c481cfd5SMatt Evans #define b_ss(x)		b_x((x), 24, 2) /* the space code */
50*c481cfd5SMatt Evans #define b_bbbbbbbb(x)	b_x((x), 16, 8) /* bus number */
51*c481cfd5SMatt Evans #define b_ddddd(x)	b_x((x), 11, 5) /* device number */
52*c481cfd5SMatt Evans #define b_fff(x)	b_x((x), 8, 3)	/* function number */
53*c481cfd5SMatt Evans #define b_rrrrrrrr(x)	b_x((x), 0, 8)	/* register number */
54*c481cfd5SMatt Evans 
55*c481cfd5SMatt Evans #define SS_M64		3
56*c481cfd5SMatt Evans #define SS_M32		2
57*c481cfd5SMatt Evans #define SS_IO		1
58*c481cfd5SMatt Evans #define SS_CONFIG	0
59*c481cfd5SMatt Evans 
60*c481cfd5SMatt Evans 
61*c481cfd5SMatt Evans static struct spapr_phb phb;
62*c481cfd5SMatt Evans 
63*c481cfd5SMatt Evans 
64*c481cfd5SMatt Evans static void rtas_ibm_read_pci_config(struct kvm_cpu *vcpu,
65*c481cfd5SMatt Evans 				     uint32_t token, uint32_t nargs,
66*c481cfd5SMatt Evans 				     target_ulong args,
67*c481cfd5SMatt Evans 				     uint32_t nret, target_ulong rets)
68*c481cfd5SMatt Evans {
69*c481cfd5SMatt Evans 	uint32_t val = 0;
70*c481cfd5SMatt Evans 	uint64_t buid = ((uint64_t)rtas_ld(vcpu->kvm, args, 1) << 32) | rtas_ld(vcpu->kvm, args, 2);
71*c481cfd5SMatt Evans 	union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
72*c481cfd5SMatt Evans 	struct pci_device_header *dev = pci__find_dev(addr.device_number);
73*c481cfd5SMatt Evans 	uint32_t size = rtas_ld(vcpu->kvm, args, 3);
74*c481cfd5SMatt Evans 
75*c481cfd5SMatt Evans 	if (buid != phb.buid || !dev || (size > 4)) {
76*c481cfd5SMatt Evans 		phb_dprintf("- cfgRd buid 0x%lx cfg addr 0x%x size %d not found\n",
77*c481cfd5SMatt Evans 			    buid, addr.w, size);
78*c481cfd5SMatt Evans 
79*c481cfd5SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -1);
80*c481cfd5SMatt Evans 		return;
81*c481cfd5SMatt Evans 	}
82*c481cfd5SMatt Evans 	pci__config_rd(vcpu->kvm, addr, &val, size);
83*c481cfd5SMatt Evans 	/* It appears this wants a byteswapped result... */
84*c481cfd5SMatt Evans 	switch (size) {
85*c481cfd5SMatt Evans 	case 4:
86*c481cfd5SMatt Evans 		val = le32_to_cpu(val);
87*c481cfd5SMatt Evans 		break;
88*c481cfd5SMatt Evans 	case 2:
89*c481cfd5SMatt Evans 		val = le16_to_cpu(val>>16);
90*c481cfd5SMatt Evans 		break;
91*c481cfd5SMatt Evans 	case 1:
92*c481cfd5SMatt Evans 		val = val >> 24;
93*c481cfd5SMatt Evans 		break;
94*c481cfd5SMatt Evans 	}
95*c481cfd5SMatt Evans 	phb_dprintf("- cfgRd buid 0x%lx addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
96*c481cfd5SMatt Evans 		    buid, addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
97*c481cfd5SMatt Evans 		    addr.register_number, val);
98*c481cfd5SMatt Evans 
99*c481cfd5SMatt Evans 	rtas_st(vcpu->kvm, rets, 0, 0);
100*c481cfd5SMatt Evans 	rtas_st(vcpu->kvm, rets, 1, val);
101*c481cfd5SMatt Evans }
102*c481cfd5SMatt Evans 
103*c481cfd5SMatt Evans static void rtas_read_pci_config(struct kvm_cpu *vcpu,
104*c481cfd5SMatt Evans 				 uint32_t token, uint32_t nargs,
105*c481cfd5SMatt Evans 				 target_ulong args,
106*c481cfd5SMatt Evans 				 uint32_t nret, target_ulong rets)
107*c481cfd5SMatt Evans {
108*c481cfd5SMatt Evans 	uint32_t val;
109*c481cfd5SMatt Evans 	union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
110*c481cfd5SMatt Evans 	struct pci_device_header *dev = pci__find_dev(addr.device_number);
111*c481cfd5SMatt Evans 	uint32_t size = rtas_ld(vcpu->kvm, args, 1);
112*c481cfd5SMatt Evans 
113*c481cfd5SMatt Evans 	if (!dev || (size > 4)) {
114*c481cfd5SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -1);
115*c481cfd5SMatt Evans 		return;
116*c481cfd5SMatt Evans 	}
117*c481cfd5SMatt Evans 	pci__config_rd(vcpu->kvm, addr, &val, size);
118*c481cfd5SMatt Evans 	switch (size) {
119*c481cfd5SMatt Evans 	case 4:
120*c481cfd5SMatt Evans 		val = le32_to_cpu(val);
121*c481cfd5SMatt Evans 		break;
122*c481cfd5SMatt Evans 	case 2:
123*c481cfd5SMatt Evans 		val = le16_to_cpu(val>>16); /* We're yuck-endian. */
124*c481cfd5SMatt Evans 		break;
125*c481cfd5SMatt Evans 	case 1:
126*c481cfd5SMatt Evans 		val = val >> 24;
127*c481cfd5SMatt Evans 		break;
128*c481cfd5SMatt Evans 	}
129*c481cfd5SMatt Evans 	phb_dprintf("- cfgRd addr 0x%x size %d, val 0x%x\n", addr.w, size, val);
130*c481cfd5SMatt Evans 	rtas_st(vcpu->kvm, rets, 0, 0);
131*c481cfd5SMatt Evans 	rtas_st(vcpu->kvm, rets, 1, val);
132*c481cfd5SMatt Evans }
133*c481cfd5SMatt Evans 
134*c481cfd5SMatt Evans static void rtas_ibm_write_pci_config(struct kvm_cpu *vcpu,
135*c481cfd5SMatt Evans 				      uint32_t token, uint32_t nargs,
136*c481cfd5SMatt Evans 				      target_ulong args,
137*c481cfd5SMatt Evans 				      uint32_t nret, target_ulong rets)
138*c481cfd5SMatt Evans {
139*c481cfd5SMatt Evans 	uint64_t buid = ((uint64_t)rtas_ld(vcpu->kvm, args, 1) << 32) | rtas_ld(vcpu->kvm, args, 2);
140*c481cfd5SMatt Evans 	union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
141*c481cfd5SMatt Evans 	struct pci_device_header *dev = pci__find_dev(addr.device_number);
142*c481cfd5SMatt Evans 	uint32_t size = rtas_ld(vcpu->kvm, args, 3);
143*c481cfd5SMatt Evans 	uint32_t val = rtas_ld(vcpu->kvm, args, 4);
144*c481cfd5SMatt Evans 
145*c481cfd5SMatt Evans 	if (buid != phb.buid || !dev || (size > 4)) {
146*c481cfd5SMatt Evans 		phb_dprintf("- cfgWr buid 0x%lx cfg addr 0x%x/%d error (val 0x%x)\n",
147*c481cfd5SMatt Evans 			    buid, addr.w, size, val);
148*c481cfd5SMatt Evans 
149*c481cfd5SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -1);
150*c481cfd5SMatt Evans 		return;
151*c481cfd5SMatt Evans 	}
152*c481cfd5SMatt Evans 	phb_dprintf("- cfgWr buid 0x%lx addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
153*c481cfd5SMatt Evans 		    buid, addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
154*c481cfd5SMatt Evans 		    addr.register_number, val);
155*c481cfd5SMatt Evans 	switch (size) {
156*c481cfd5SMatt Evans 	case 4:
157*c481cfd5SMatt Evans 		val = le32_to_cpu(val);
158*c481cfd5SMatt Evans 		break;
159*c481cfd5SMatt Evans 	case 2:
160*c481cfd5SMatt Evans 		val = le16_to_cpu(val) << 16;
161*c481cfd5SMatt Evans 		break;
162*c481cfd5SMatt Evans 	case 1:
163*c481cfd5SMatt Evans 		val = val >> 24;
164*c481cfd5SMatt Evans 		break;
165*c481cfd5SMatt Evans 	}
166*c481cfd5SMatt Evans 	pci__config_wr(vcpu->kvm, addr, &val, size);
167*c481cfd5SMatt Evans 	rtas_st(vcpu->kvm, rets, 0, 0);
168*c481cfd5SMatt Evans }
169*c481cfd5SMatt Evans 
170*c481cfd5SMatt Evans static void rtas_write_pci_config(struct kvm_cpu *vcpu,
171*c481cfd5SMatt Evans 				  uint32_t token, uint32_t nargs,
172*c481cfd5SMatt Evans 				  target_ulong args,
173*c481cfd5SMatt Evans 				  uint32_t nret, target_ulong rets)
174*c481cfd5SMatt Evans {
175*c481cfd5SMatt Evans 	union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
176*c481cfd5SMatt Evans 	struct pci_device_header *dev = pci__find_dev(addr.device_number);
177*c481cfd5SMatt Evans 	uint32_t size = rtas_ld(vcpu->kvm, args, 1);
178*c481cfd5SMatt Evans 	uint32_t val = rtas_ld(vcpu->kvm, args, 2);
179*c481cfd5SMatt Evans 
180*c481cfd5SMatt Evans 	if (!dev || (size > 4)) {
181*c481cfd5SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -1);
182*c481cfd5SMatt Evans 		return;
183*c481cfd5SMatt Evans 	}
184*c481cfd5SMatt Evans 
185*c481cfd5SMatt Evans 	phb_dprintf("- cfgWr addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
186*c481cfd5SMatt Evans 		    addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
187*c481cfd5SMatt Evans 		    addr.register_number, val);
188*c481cfd5SMatt Evans 	switch (size) {
189*c481cfd5SMatt Evans 	case 4:
190*c481cfd5SMatt Evans 		val = le32_to_cpu(val);
191*c481cfd5SMatt Evans 		break;
192*c481cfd5SMatt Evans 	case 2:
193*c481cfd5SMatt Evans 		val = le16_to_cpu(val) << 16;
194*c481cfd5SMatt Evans 		break;
195*c481cfd5SMatt Evans 	case 1:
196*c481cfd5SMatt Evans 		val = val >> 24;
197*c481cfd5SMatt Evans 		break;
198*c481cfd5SMatt Evans 	}
199*c481cfd5SMatt Evans 	pci__config_wr(vcpu->kvm, addr, &val, size);
200*c481cfd5SMatt Evans 	rtas_st(vcpu->kvm, rets, 0, 0);
201*c481cfd5SMatt Evans }
202*c481cfd5SMatt Evans 
203*c481cfd5SMatt Evans void spapr_create_phb(struct kvm *kvm,
204*c481cfd5SMatt Evans 		      const char *busname, uint64_t buid,
205*c481cfd5SMatt Evans 		      uint64_t mem_win_addr, uint64_t mem_win_size,
206*c481cfd5SMatt Evans 		      uint64_t io_win_addr, uint64_t io_win_size)
207*c481cfd5SMatt Evans {
208*c481cfd5SMatt Evans 	/*
209*c481cfd5SMatt Evans 	 * Since kvmtool doesn't really have any concept of buses etc.,
210*c481cfd5SMatt Evans 	 * there's nothing to register here.  Just register RTAS.
211*c481cfd5SMatt Evans 	 */
212*c481cfd5SMatt Evans 	spapr_rtas_register("read-pci-config", rtas_read_pci_config);
213*c481cfd5SMatt Evans 	spapr_rtas_register("write-pci-config", rtas_write_pci_config);
214*c481cfd5SMatt Evans 	spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
215*c481cfd5SMatt Evans 	spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
216*c481cfd5SMatt Evans 
217*c481cfd5SMatt Evans 	phb.buid = buid;
218*c481cfd5SMatt Evans 	phb.mem_addr = mem_win_addr;
219*c481cfd5SMatt Evans 	phb.mem_size = mem_win_size;
220*c481cfd5SMatt Evans 	phb.io_addr  = io_win_addr;
221*c481cfd5SMatt Evans 	phb.io_size  = io_win_size;
222*c481cfd5SMatt Evans 
223*c481cfd5SMatt Evans 	kvm->phb = &phb;
224*c481cfd5SMatt Evans }
225*c481cfd5SMatt Evans 
226*c481cfd5SMatt Evans static uint32_t bar_to_ss(unsigned long bar)
227*c481cfd5SMatt Evans {
228*c481cfd5SMatt Evans 	if ((bar & PCI_BASE_ADDRESS_SPACE) ==
229*c481cfd5SMatt Evans 	    PCI_BASE_ADDRESS_SPACE_IO)
230*c481cfd5SMatt Evans 		return SS_IO;
231*c481cfd5SMatt Evans 	else if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64)
232*c481cfd5SMatt Evans 		return SS_M64;
233*c481cfd5SMatt Evans 	else
234*c481cfd5SMatt Evans 		return SS_M32;
235*c481cfd5SMatt Evans }
236*c481cfd5SMatt Evans 
237*c481cfd5SMatt Evans static unsigned long bar_to_addr(unsigned long bar)
238*c481cfd5SMatt Evans {
239*c481cfd5SMatt Evans 	if ((bar & PCI_BASE_ADDRESS_SPACE) ==
240*c481cfd5SMatt Evans 	    PCI_BASE_ADDRESS_SPACE_IO)
241*c481cfd5SMatt Evans 		return bar & PCI_BASE_ADDRESS_IO_MASK;
242*c481cfd5SMatt Evans 	else
243*c481cfd5SMatt Evans 		return bar & PCI_BASE_ADDRESS_MEM_MASK;
244*c481cfd5SMatt Evans }
245*c481cfd5SMatt Evans 
246*c481cfd5SMatt Evans int spapr_populate_pci_devices(struct kvm *kvm,
247*c481cfd5SMatt Evans 			       uint32_t xics_phandle,
248*c481cfd5SMatt Evans 			       void *fdt)
249*c481cfd5SMatt Evans {
250*c481cfd5SMatt Evans 	int bus_off, node_off = 0, devid, fn, i, n, devices;
251*c481cfd5SMatt Evans 	char nodename[256];
252*c481cfd5SMatt Evans 	struct {
253*c481cfd5SMatt Evans 		uint32_t hi;
254*c481cfd5SMatt Evans 		uint64_t addr;
255*c481cfd5SMatt Evans 		uint64_t size;
256*c481cfd5SMatt Evans 	} __attribute__((packed)) reg[PCI_NUM_REGIONS + 1],
257*c481cfd5SMatt Evans 		  assigned_addresses[PCI_NUM_REGIONS];
258*c481cfd5SMatt Evans 	uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
259*c481cfd5SMatt Evans 	struct {
260*c481cfd5SMatt Evans 		uint32_t hi;
261*c481cfd5SMatt Evans 		uint64_t child;
262*c481cfd5SMatt Evans 		uint64_t parent;
263*c481cfd5SMatt Evans 		uint64_t size;
264*c481cfd5SMatt Evans 	} __attribute__((packed)) ranges[] = {
265*c481cfd5SMatt Evans 		{
266*c481cfd5SMatt Evans 			cpu_to_be32(b_ss(1)), cpu_to_be64(0),
267*c481cfd5SMatt Evans 			cpu_to_be64(phb.io_addr),
268*c481cfd5SMatt Evans 			cpu_to_be64(phb.io_size),
269*c481cfd5SMatt Evans 		},
270*c481cfd5SMatt Evans 		{
271*c481cfd5SMatt Evans 			cpu_to_be32(b_ss(2)), cpu_to_be64(0),
272*c481cfd5SMatt Evans 			cpu_to_be64(phb.mem_addr),
273*c481cfd5SMatt Evans 			cpu_to_be64(phb.mem_size),
274*c481cfd5SMatt Evans 		},
275*c481cfd5SMatt Evans 	};
276*c481cfd5SMatt Evans 	uint64_t bus_reg[] = { cpu_to_be64(phb.buid), 0 };
277*c481cfd5SMatt Evans 	uint32_t interrupt_map_mask[] = {
278*c481cfd5SMatt Evans 		cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0};
279*c481cfd5SMatt Evans 	uint32_t interrupt_map[SPAPR_PCI_NUM_LSI][7];
280*c481cfd5SMatt Evans 
281*c481cfd5SMatt Evans 	/* Start populating the FDT */
282*c481cfd5SMatt Evans 	sprintf(nodename, "pci@%" PRIx64, phb.buid);
283*c481cfd5SMatt Evans 	bus_off = fdt_add_subnode(fdt, 0, nodename);
284*c481cfd5SMatt Evans 	if (bus_off < 0) {
285*c481cfd5SMatt Evans 		die("error making bus subnode, %s\n", fdt_strerror(bus_off));
286*c481cfd5SMatt Evans 		return bus_off;
287*c481cfd5SMatt Evans 	}
288*c481cfd5SMatt Evans 
289*c481cfd5SMatt Evans 	/* Write PHB properties */
290*c481cfd5SMatt Evans 	_FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
291*c481cfd5SMatt Evans 	_FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
292*c481cfd5SMatt Evans 	_FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
293*c481cfd5SMatt Evans 	_FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
294*c481cfd5SMatt Evans 	_FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
295*c481cfd5SMatt Evans 	_FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
296*c481cfd5SMatt Evans 	_FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
297*c481cfd5SMatt Evans 	_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
298*c481cfd5SMatt Evans 	_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
299*c481cfd5SMatt Evans 	_FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
300*c481cfd5SMatt Evans 			 &interrupt_map_mask, sizeof(interrupt_map_mask)));
301*c481cfd5SMatt Evans 
302*c481cfd5SMatt Evans 	/* Populate PCI devices and allocate IRQs */
303*c481cfd5SMatt Evans 	devices = 0;
304*c481cfd5SMatt Evans 
305*c481cfd5SMatt Evans 	for (devid = 0; devid < PCI_MAX_DEVICES; devid++) {
306*c481cfd5SMatt Evans 		uint32_t *irqmap = interrupt_map[devices];
307*c481cfd5SMatt Evans 		struct pci_device_header *hdr = pci__find_dev(devid);
308*c481cfd5SMatt Evans 
309*c481cfd5SMatt Evans 		if (!hdr)
310*c481cfd5SMatt Evans 			continue;
311*c481cfd5SMatt Evans 
312*c481cfd5SMatt Evans 		fn = 0; /* kvmtool doesn't yet do multifunction devices */
313*c481cfd5SMatt Evans 
314*c481cfd5SMatt Evans 		sprintf(nodename, "pci@%u,%u", devid, fn);
315*c481cfd5SMatt Evans 
316*c481cfd5SMatt Evans 		/* Allocate interrupt from the map */
317*c481cfd5SMatt Evans 		if (devid > SPAPR_PCI_NUM_LSI)	{
318*c481cfd5SMatt Evans 			die("Unexpected behaviour in spapr_populate_pci_devices,"
319*c481cfd5SMatt Evans 			    "wrong devid %u\n", devid);
320*c481cfd5SMatt Evans 		}
321*c481cfd5SMatt Evans 		irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn));
322*c481cfd5SMatt Evans 		irqmap[1] = 0;
323*c481cfd5SMatt Evans 		irqmap[2] = 0;
324*c481cfd5SMatt Evans 		irqmap[3] = 0;
325*c481cfd5SMatt Evans 		irqmap[4] = cpu_to_be32(xics_phandle);
326*c481cfd5SMatt Evans 		/*
327*c481cfd5SMatt Evans 		 * This is nasty; the PCI devs are set up such that their own
328*c481cfd5SMatt Evans 		 * header's irq_line indicates the direct XICS IRQ number to
329*c481cfd5SMatt Evans 		 * use.  There REALLY needs to be a hierarchical system in place
330*c481cfd5SMatt Evans 		 * to 'raise' an IRQ on the bridge which indexes/looks up which
331*c481cfd5SMatt Evans 		 * XICS IRQ to fire.
332*c481cfd5SMatt Evans 		 */
333*c481cfd5SMatt Evans 		irqmap[5] = cpu_to_be32(hdr->irq_line);
334*c481cfd5SMatt Evans 		irqmap[6] = cpu_to_be32(0x8);
335*c481cfd5SMatt Evans 
336*c481cfd5SMatt Evans 		/* Add node to FDT */
337*c481cfd5SMatt Evans 		node_off = fdt_add_subnode(fdt, bus_off, nodename);
338*c481cfd5SMatt Evans 		if (node_off < 0) {
339*c481cfd5SMatt Evans 			die("error making node subnode, %s\n", fdt_strerror(bus_off));
340*c481cfd5SMatt Evans 			return node_off;
341*c481cfd5SMatt Evans 		}
342*c481cfd5SMatt Evans 
343*c481cfd5SMatt Evans 		_FDT(fdt_setprop_cell(fdt, node_off, "vendor-id",
344*c481cfd5SMatt Evans 				      le16_to_cpu(hdr->vendor_id)));
345*c481cfd5SMatt Evans 		_FDT(fdt_setprop_cell(fdt, node_off, "device-id",
346*c481cfd5SMatt Evans 				      le16_to_cpu(hdr->device_id)));
347*c481cfd5SMatt Evans 		_FDT(fdt_setprop_cell(fdt, node_off, "revision-id",
348*c481cfd5SMatt Evans 				      hdr->revision_id));
349*c481cfd5SMatt Evans 		_FDT(fdt_setprop_cell(fdt, node_off, "class-code",
350*c481cfd5SMatt Evans 				      hdr->class[0] | (hdr->class[1] << 8) | (hdr->class[2] << 16)));
351*c481cfd5SMatt Evans 		_FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id",
352*c481cfd5SMatt Evans 				      le16_to_cpu(hdr->subsys_id)));
353*c481cfd5SMatt Evans 		_FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id",
354*c481cfd5SMatt Evans 				      le16_to_cpu(hdr->subsys_vendor_id)));
355*c481cfd5SMatt Evans 
356*c481cfd5SMatt Evans 		/* Config space region comes first */
357*c481cfd5SMatt Evans 		reg[0].hi = cpu_to_be32(
358*c481cfd5SMatt Evans 			b_n(0) |
359*c481cfd5SMatt Evans 			b_p(0) |
360*c481cfd5SMatt Evans 			b_t(0) |
361*c481cfd5SMatt Evans 			b_ss(SS_CONFIG) |
362*c481cfd5SMatt Evans 			b_bbbbbbbb(0) |
363*c481cfd5SMatt Evans 			b_ddddd(devid) |
364*c481cfd5SMatt Evans 			b_fff(fn));
365*c481cfd5SMatt Evans 		reg[0].addr = 0;
366*c481cfd5SMatt Evans 		reg[0].size = 0;
367*c481cfd5SMatt Evans 
368*c481cfd5SMatt Evans 		n = 0;
369*c481cfd5SMatt Evans 		/* Six BARs, no ROM supported, addresses are 32bit */
370*c481cfd5SMatt Evans 		for (i = 0; i < 6; ++i) {
371*c481cfd5SMatt Evans 			if (0 == hdr->bar[i]) {
372*c481cfd5SMatt Evans 				continue;
373*c481cfd5SMatt Evans 			}
374*c481cfd5SMatt Evans 
375*c481cfd5SMatt Evans 			reg[n+1].hi = cpu_to_be32(
376*c481cfd5SMatt Evans 				b_n(0) |
377*c481cfd5SMatt Evans 				b_p(0) |
378*c481cfd5SMatt Evans 				b_t(0) |
379*c481cfd5SMatt Evans 				b_ss(bar_to_ss(le32_to_cpu(hdr->bar[i]))) |
380*c481cfd5SMatt Evans 				b_bbbbbbbb(0) |
381*c481cfd5SMatt Evans 				b_ddddd(devid) |
382*c481cfd5SMatt Evans 				b_fff(fn) |
383*c481cfd5SMatt Evans 				b_rrrrrrrr(bars[i]));
384*c481cfd5SMatt Evans 			reg[n+1].addr = 0;
385*c481cfd5SMatt Evans 			reg[n+1].size = cpu_to_be64(hdr->bar_size[i]);
386*c481cfd5SMatt Evans 
387*c481cfd5SMatt Evans 			assigned_addresses[n].hi = cpu_to_be32(
388*c481cfd5SMatt Evans 				b_n(1) |
389*c481cfd5SMatt Evans 				b_p(0) |
390*c481cfd5SMatt Evans 				b_t(0) |
391*c481cfd5SMatt Evans 				b_ss(bar_to_ss(le32_to_cpu(hdr->bar[i]))) |
392*c481cfd5SMatt Evans 				b_bbbbbbbb(0) |
393*c481cfd5SMatt Evans 				b_ddddd(devid) |
394*c481cfd5SMatt Evans 				b_fff(fn) |
395*c481cfd5SMatt Evans 				b_rrrrrrrr(bars[i]));
396*c481cfd5SMatt Evans 
397*c481cfd5SMatt Evans 			/*
398*c481cfd5SMatt Evans 			 * Writing zeroes to assigned_addresses causes the guest kernel to
399*c481cfd5SMatt Evans 			 * reassign BARs
400*c481cfd5SMatt Evans 			 */
401*c481cfd5SMatt Evans 			assigned_addresses[n].addr = cpu_to_be64(bar_to_addr(le32_to_cpu(hdr->bar[i])));
402*c481cfd5SMatt Evans 			assigned_addresses[n].size = reg[n+1].size;
403*c481cfd5SMatt Evans 
404*c481cfd5SMatt Evans 			++n;
405*c481cfd5SMatt Evans 		}
406*c481cfd5SMatt Evans 		_FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1)));
407*c481cfd5SMatt Evans 		_FDT(fdt_setprop(fdt, node_off, "assigned-addresses",
408*c481cfd5SMatt Evans 				 assigned_addresses,
409*c481cfd5SMatt Evans 				 sizeof(assigned_addresses[0])*(n)));
410*c481cfd5SMatt Evans 		_FDT(fdt_setprop_cell(fdt, node_off, "interrupts",
411*c481cfd5SMatt Evans 				      hdr->irq_pin));
412*c481cfd5SMatt Evans 
413*c481cfd5SMatt Evans 		/* We don't set ibm,dma-window property as we don't have an IOMMU. */
414*c481cfd5SMatt Evans 
415*c481cfd5SMatt Evans 		++devices;
416*c481cfd5SMatt Evans 	}
417*c481cfd5SMatt Evans 
418*c481cfd5SMatt Evans 	/* Write interrupt map */
419*c481cfd5SMatt Evans 	_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
420*c481cfd5SMatt Evans 			 devices * sizeof(interrupt_map[0])));
421*c481cfd5SMatt Evans 
422*c481cfd5SMatt Evans 	return 0;
423*c481cfd5SMatt Evans }
424