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