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"
18a1166a18SWill Deacon #include "kvm/devices.h"
191299331aSWill Deacon #include "kvm/fdt.h"
20c481cfd5SMatt Evans #include "kvm/util.h"
216606883cSWill Deacon #include "kvm/of_pci.h"
22c481cfd5SMatt Evans #include "kvm/pci.h"
23c481cfd5SMatt Evans
24c481cfd5SMatt Evans #include <linux/pci_regs.h>
25c481cfd5SMatt Evans #include <linux/byteorder.h>
26c481cfd5SMatt Evans
27c481cfd5SMatt Evans
28c481cfd5SMatt Evans /* #define DEBUG_PHB yes */
29c481cfd5SMatt Evans #ifdef DEBUG_PHB
30c481cfd5SMatt Evans #define phb_dprintf(fmt, ...) \
31c481cfd5SMatt Evans do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
32c481cfd5SMatt Evans #else
33c481cfd5SMatt Evans #define phb_dprintf(fmt, ...) \
34c481cfd5SMatt Evans do { } while (0)
35c481cfd5SMatt Evans #endif
36c481cfd5SMatt Evans
37c481cfd5SMatt Evans static const uint32_t bars[] = {
38c481cfd5SMatt Evans PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1,
39c481cfd5SMatt Evans PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3,
40c481cfd5SMatt Evans PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5
41c481cfd5SMatt Evans /*, PCI_ROM_ADDRESS*/
42c481cfd5SMatt Evans };
43c481cfd5SMatt Evans
44c481cfd5SMatt Evans #define PCI_NUM_REGIONS 7
45c481cfd5SMatt Evans
46c481cfd5SMatt Evans static struct spapr_phb phb;
47c481cfd5SMatt Evans
rtas_ibm_read_pci_config(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)48c481cfd5SMatt Evans static void rtas_ibm_read_pci_config(struct kvm_cpu *vcpu,
49c481cfd5SMatt Evans uint32_t token, uint32_t nargs,
50c481cfd5SMatt Evans target_ulong args,
51c481cfd5SMatt Evans uint32_t nret, target_ulong rets)
52c481cfd5SMatt Evans {
53c481cfd5SMatt Evans uint32_t val = 0;
54c481cfd5SMatt Evans uint64_t buid = ((uint64_t)rtas_ld(vcpu->kvm, args, 1) << 32) | rtas_ld(vcpu->kvm, args, 2);
55c481cfd5SMatt Evans union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
56c481cfd5SMatt Evans struct pci_device_header *dev = pci__find_dev(addr.device_number);
57c481cfd5SMatt Evans uint32_t size = rtas_ld(vcpu->kvm, args, 3);
58c481cfd5SMatt Evans
59c481cfd5SMatt Evans if (buid != phb.buid || !dev || (size > 4)) {
60c481cfd5SMatt Evans phb_dprintf("- cfgRd buid 0x%lx cfg addr 0x%x size %d not found\n",
61c481cfd5SMatt Evans buid, addr.w, size);
62c481cfd5SMatt Evans
63c481cfd5SMatt Evans rtas_st(vcpu->kvm, rets, 0, -1);
64c481cfd5SMatt Evans return;
65c481cfd5SMatt Evans }
66c481cfd5SMatt Evans pci__config_rd(vcpu->kvm, addr, &val, size);
67c481cfd5SMatt Evans /* It appears this wants a byteswapped result... */
68c481cfd5SMatt Evans switch (size) {
69c481cfd5SMatt Evans case 4:
70c481cfd5SMatt Evans val = le32_to_cpu(val);
71c481cfd5SMatt Evans break;
72c481cfd5SMatt Evans case 2:
73c481cfd5SMatt Evans val = le16_to_cpu(val>>16);
74c481cfd5SMatt Evans break;
75c481cfd5SMatt Evans case 1:
76c481cfd5SMatt Evans val = val >> 24;
77c481cfd5SMatt Evans break;
78c481cfd5SMatt Evans }
79c481cfd5SMatt Evans phb_dprintf("- cfgRd buid 0x%lx addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
80c481cfd5SMatt Evans buid, addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
81c481cfd5SMatt Evans addr.register_number, val);
82c481cfd5SMatt Evans
83c481cfd5SMatt Evans rtas_st(vcpu->kvm, rets, 0, 0);
84c481cfd5SMatt Evans rtas_st(vcpu->kvm, rets, 1, val);
85c481cfd5SMatt Evans }
86c481cfd5SMatt Evans
rtas_read_pci_config(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)87c481cfd5SMatt Evans static void rtas_read_pci_config(struct kvm_cpu *vcpu,
88c481cfd5SMatt Evans uint32_t token, uint32_t nargs,
89c481cfd5SMatt Evans target_ulong args,
90c481cfd5SMatt Evans uint32_t nret, target_ulong rets)
91c481cfd5SMatt Evans {
92c481cfd5SMatt Evans uint32_t val;
93c481cfd5SMatt Evans union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
94c481cfd5SMatt Evans struct pci_device_header *dev = pci__find_dev(addr.device_number);
95c481cfd5SMatt Evans uint32_t size = rtas_ld(vcpu->kvm, args, 1);
96c481cfd5SMatt Evans
97c481cfd5SMatt Evans if (!dev || (size > 4)) {
98c481cfd5SMatt Evans rtas_st(vcpu->kvm, rets, 0, -1);
99c481cfd5SMatt Evans return;
100c481cfd5SMatt Evans }
101c481cfd5SMatt Evans pci__config_rd(vcpu->kvm, addr, &val, size);
102c481cfd5SMatt Evans switch (size) {
103c481cfd5SMatt Evans case 4:
104c481cfd5SMatt Evans val = le32_to_cpu(val);
105c481cfd5SMatt Evans break;
106c481cfd5SMatt Evans case 2:
107c481cfd5SMatt Evans val = le16_to_cpu(val>>16); /* We're yuck-endian. */
108c481cfd5SMatt Evans break;
109c481cfd5SMatt Evans case 1:
110c481cfd5SMatt Evans val = val >> 24;
111c481cfd5SMatt Evans break;
112c481cfd5SMatt Evans }
113c481cfd5SMatt Evans phb_dprintf("- cfgRd addr 0x%x size %d, val 0x%x\n", addr.w, size, val);
114c481cfd5SMatt Evans rtas_st(vcpu->kvm, rets, 0, 0);
115c481cfd5SMatt Evans rtas_st(vcpu->kvm, rets, 1, val);
116c481cfd5SMatt Evans }
117c481cfd5SMatt Evans
rtas_ibm_write_pci_config(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)118c481cfd5SMatt Evans static void rtas_ibm_write_pci_config(struct kvm_cpu *vcpu,
119c481cfd5SMatt Evans uint32_t token, uint32_t nargs,
120c481cfd5SMatt Evans target_ulong args,
121c481cfd5SMatt Evans uint32_t nret, target_ulong rets)
122c481cfd5SMatt Evans {
123c481cfd5SMatt Evans uint64_t buid = ((uint64_t)rtas_ld(vcpu->kvm, args, 1) << 32) | rtas_ld(vcpu->kvm, args, 2);
124c481cfd5SMatt Evans union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
125c481cfd5SMatt Evans struct pci_device_header *dev = pci__find_dev(addr.device_number);
126c481cfd5SMatt Evans uint32_t size = rtas_ld(vcpu->kvm, args, 3);
127c481cfd5SMatt Evans uint32_t val = rtas_ld(vcpu->kvm, args, 4);
128c481cfd5SMatt Evans
129c481cfd5SMatt Evans if (buid != phb.buid || !dev || (size > 4)) {
130c481cfd5SMatt Evans phb_dprintf("- cfgWr buid 0x%lx cfg addr 0x%x/%d error (val 0x%x)\n",
131c481cfd5SMatt Evans buid, addr.w, size, val);
132c481cfd5SMatt Evans
133c481cfd5SMatt Evans rtas_st(vcpu->kvm, rets, 0, -1);
134c481cfd5SMatt Evans return;
135c481cfd5SMatt Evans }
136c481cfd5SMatt Evans phb_dprintf("- cfgWr buid 0x%lx addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
137c481cfd5SMatt Evans buid, addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
138c481cfd5SMatt Evans addr.register_number, val);
139c481cfd5SMatt Evans switch (size) {
140c481cfd5SMatt Evans case 4:
141c481cfd5SMatt Evans val = le32_to_cpu(val);
142c481cfd5SMatt Evans break;
143c481cfd5SMatt Evans case 2:
144c481cfd5SMatt Evans val = le16_to_cpu(val) << 16;
145c481cfd5SMatt Evans break;
146c481cfd5SMatt Evans case 1:
147c481cfd5SMatt Evans val = val >> 24;
148c481cfd5SMatt Evans break;
149c481cfd5SMatt Evans }
150c481cfd5SMatt Evans pci__config_wr(vcpu->kvm, addr, &val, size);
151c481cfd5SMatt Evans rtas_st(vcpu->kvm, rets, 0, 0);
152c481cfd5SMatt Evans }
153c481cfd5SMatt Evans
rtas_write_pci_config(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)154c481cfd5SMatt Evans static void rtas_write_pci_config(struct kvm_cpu *vcpu,
155c481cfd5SMatt Evans uint32_t token, uint32_t nargs,
156c481cfd5SMatt Evans target_ulong args,
157c481cfd5SMatt Evans uint32_t nret, target_ulong rets)
158c481cfd5SMatt Evans {
159c481cfd5SMatt Evans union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
160c481cfd5SMatt Evans struct pci_device_header *dev = pci__find_dev(addr.device_number);
161c481cfd5SMatt Evans uint32_t size = rtas_ld(vcpu->kvm, args, 1);
162c481cfd5SMatt Evans uint32_t val = rtas_ld(vcpu->kvm, args, 2);
163c481cfd5SMatt Evans
164c481cfd5SMatt Evans if (!dev || (size > 4)) {
165c481cfd5SMatt Evans rtas_st(vcpu->kvm, rets, 0, -1);
166c481cfd5SMatt Evans return;
167c481cfd5SMatt Evans }
168c481cfd5SMatt Evans
169c481cfd5SMatt Evans phb_dprintf("- cfgWr addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
170c481cfd5SMatt Evans addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
171c481cfd5SMatt Evans addr.register_number, val);
172c481cfd5SMatt Evans switch (size) {
173c481cfd5SMatt Evans case 4:
174c481cfd5SMatt Evans val = le32_to_cpu(val);
175c481cfd5SMatt Evans break;
176c481cfd5SMatt Evans case 2:
177c481cfd5SMatt Evans val = le16_to_cpu(val) << 16;
178c481cfd5SMatt Evans break;
179c481cfd5SMatt Evans case 1:
180c481cfd5SMatt Evans val = val >> 24;
181c481cfd5SMatt Evans break;
182c481cfd5SMatt Evans }
183c481cfd5SMatt Evans pci__config_wr(vcpu->kvm, addr, &val, size);
184c481cfd5SMatt Evans rtas_st(vcpu->kvm, rets, 0, 0);
185c481cfd5SMatt Evans }
186c481cfd5SMatt Evans
spapr_create_phb(struct kvm * kvm,const char * busname,uint64_t buid,uint64_t mem_win_addr,uint64_t mem_win_size,uint64_t io_win_addr,uint64_t io_win_size)187c481cfd5SMatt Evans void spapr_create_phb(struct kvm *kvm,
188c481cfd5SMatt Evans const char *busname, uint64_t buid,
189c481cfd5SMatt Evans uint64_t mem_win_addr, uint64_t mem_win_size,
190c481cfd5SMatt Evans uint64_t io_win_addr, uint64_t io_win_size)
191c481cfd5SMatt Evans {
192c481cfd5SMatt Evans /*
193c481cfd5SMatt Evans * Since kvmtool doesn't really have any concept of buses etc.,
194c481cfd5SMatt Evans * there's nothing to register here. Just register RTAS.
195c481cfd5SMatt Evans */
196c481cfd5SMatt Evans spapr_rtas_register("read-pci-config", rtas_read_pci_config);
197c481cfd5SMatt Evans spapr_rtas_register("write-pci-config", rtas_write_pci_config);
198c481cfd5SMatt Evans spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
199c481cfd5SMatt Evans spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
200c481cfd5SMatt Evans
201c481cfd5SMatt Evans phb.buid = buid;
202c481cfd5SMatt Evans phb.mem_addr = mem_win_addr;
203c481cfd5SMatt Evans phb.mem_size = mem_win_size;
204c481cfd5SMatt Evans phb.io_addr = io_win_addr;
205c481cfd5SMatt Evans phb.io_size = io_win_size;
206c481cfd5SMatt Evans
20742ac24f9SSasha Levin kvm->arch.phb = &phb;
208c481cfd5SMatt Evans }
209c481cfd5SMatt Evans
bar_to_ss(unsigned long bar)210c481cfd5SMatt Evans static uint32_t bar_to_ss(unsigned long bar)
211c481cfd5SMatt Evans {
212c481cfd5SMatt Evans if ((bar & PCI_BASE_ADDRESS_SPACE) ==
213c481cfd5SMatt Evans PCI_BASE_ADDRESS_SPACE_IO)
2146606883cSWill Deacon return OF_PCI_SS_IO;
215c481cfd5SMatt Evans else if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64)
2166606883cSWill Deacon return OF_PCI_SS_M64;
217c481cfd5SMatt Evans else
2186606883cSWill Deacon return OF_PCI_SS_M32;
219c481cfd5SMatt Evans }
220c481cfd5SMatt Evans
bar_to_addr(unsigned long bar)221c481cfd5SMatt Evans static unsigned long bar_to_addr(unsigned long bar)
222c481cfd5SMatt Evans {
223c481cfd5SMatt Evans if ((bar & PCI_BASE_ADDRESS_SPACE) ==
224c481cfd5SMatt Evans PCI_BASE_ADDRESS_SPACE_IO)
225c481cfd5SMatt Evans return bar & PCI_BASE_ADDRESS_IO_MASK;
226c481cfd5SMatt Evans else
227c481cfd5SMatt Evans return bar & PCI_BASE_ADDRESS_MEM_MASK;
228c481cfd5SMatt Evans }
229c481cfd5SMatt Evans
spapr_populate_pci_devices(struct kvm * kvm,uint32_t xics_phandle,void * fdt)230c481cfd5SMatt Evans int spapr_populate_pci_devices(struct kvm *kvm,
231c481cfd5SMatt Evans uint32_t xics_phandle,
232c481cfd5SMatt Evans void *fdt)
233c481cfd5SMatt Evans {
234c481cfd5SMatt Evans int bus_off, node_off = 0, devid, fn, i, n, devices;
235a1166a18SWill Deacon struct device_header *dev_hdr;
236c481cfd5SMatt Evans char nodename[256];
2375568f3e3SBalbir Singh struct of_pci_unit64_address {
2385568f3e3SBalbir Singh u32 phys_hi;
2395568f3e3SBalbir Singh u64 addr;
2405568f3e3SBalbir Singh u64 size;
2415568f3e3SBalbir Singh } __attribute((packed)) reg[PCI_NUM_REGIONS + 1], assigned_addresses[PCI_NUM_REGIONS];
242c481cfd5SMatt Evans uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
2436606883cSWill Deacon struct of_pci_ranges_entry ranges[] = {
244c481cfd5SMatt Evans {
2456606883cSWill Deacon {
2466606883cSWill Deacon cpu_to_be32(of_pci_b_ss(1)),
2476606883cSWill Deacon cpu_to_be32(0),
2486606883cSWill Deacon cpu_to_be32(0),
2496606883cSWill Deacon },
250c481cfd5SMatt Evans cpu_to_be64(phb.io_addr),
251c481cfd5SMatt Evans cpu_to_be64(phb.io_size),
252c481cfd5SMatt Evans },
253c481cfd5SMatt Evans {
2546606883cSWill Deacon {
2556606883cSWill Deacon cpu_to_be32(of_pci_b_ss(2)),
2566606883cSWill Deacon cpu_to_be32(0),
2576606883cSWill Deacon cpu_to_be32(0),
2586606883cSWill Deacon },
259c481cfd5SMatt Evans cpu_to_be64(phb.mem_addr),
260c481cfd5SMatt Evans cpu_to_be64(phb.mem_size),
261c481cfd5SMatt Evans },
262c481cfd5SMatt Evans };
263c481cfd5SMatt Evans uint64_t bus_reg[] = { cpu_to_be64(phb.buid), 0 };
264c481cfd5SMatt Evans uint32_t interrupt_map_mask[] = {
2656606883cSWill Deacon cpu_to_be32(of_pci_b_ddddd(-1)|of_pci_b_fff(-1)), 0x0, 0x0, 0x0};
266c481cfd5SMatt Evans uint32_t interrupt_map[SPAPR_PCI_NUM_LSI][7];
267c481cfd5SMatt Evans
268c481cfd5SMatt Evans /* Start populating the FDT */
269c481cfd5SMatt Evans sprintf(nodename, "pci@%" PRIx64, phb.buid);
270c481cfd5SMatt Evans bus_off = fdt_add_subnode(fdt, 0, nodename);
271c481cfd5SMatt Evans if (bus_off < 0) {
272c481cfd5SMatt Evans die("error making bus subnode, %s\n", fdt_strerror(bus_off));
273c481cfd5SMatt Evans return bus_off;
274c481cfd5SMatt Evans }
275c481cfd5SMatt Evans
276c481cfd5SMatt Evans /* Write PHB properties */
277c481cfd5SMatt Evans _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
278c481cfd5SMatt Evans _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
279c481cfd5SMatt Evans _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
280c481cfd5SMatt Evans _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
281c481cfd5SMatt Evans _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
282c481cfd5SMatt Evans _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
283c481cfd5SMatt Evans _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
284c481cfd5SMatt Evans _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
285c481cfd5SMatt Evans _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
286c481cfd5SMatt Evans _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
287c481cfd5SMatt Evans &interrupt_map_mask, sizeof(interrupt_map_mask)));
288c481cfd5SMatt Evans
289c481cfd5SMatt Evans /* Populate PCI devices and allocate IRQs */
290c481cfd5SMatt Evans devices = 0;
291a1166a18SWill Deacon dev_hdr = device__first_dev(DEVICE_BUS_PCI);
292a1166a18SWill Deacon while (dev_hdr) {
293c481cfd5SMatt Evans uint32_t *irqmap = interrupt_map[devices];
294a1166a18SWill Deacon struct pci_device_header *hdr = dev_hdr->data;
295c481cfd5SMatt Evans
296c481cfd5SMatt Evans if (!hdr)
297c481cfd5SMatt Evans continue;
298c481cfd5SMatt Evans
299a1166a18SWill Deacon devid = dev_hdr->dev_num;
300c481cfd5SMatt Evans fn = 0; /* kvmtool doesn't yet do multifunction devices */
301c481cfd5SMatt Evans
302c481cfd5SMatt Evans sprintf(nodename, "pci@%u,%u", devid, fn);
303c481cfd5SMatt Evans
304c481cfd5SMatt Evans /* Allocate interrupt from the map */
305c481cfd5SMatt Evans if (devid > SPAPR_PCI_NUM_LSI) {
306c481cfd5SMatt Evans die("Unexpected behaviour in spapr_populate_pci_devices,"
307c481cfd5SMatt Evans "wrong devid %u\n", devid);
308c481cfd5SMatt Evans }
3096606883cSWill Deacon irqmap[0] = cpu_to_be32(of_pci_b_ddddd(devid)|of_pci_b_fff(fn));
310c481cfd5SMatt Evans irqmap[1] = 0;
311c481cfd5SMatt Evans irqmap[2] = 0;
312c481cfd5SMatt Evans irqmap[3] = 0;
313c481cfd5SMatt Evans irqmap[4] = cpu_to_be32(xics_phandle);
314c481cfd5SMatt Evans /*
315c481cfd5SMatt Evans * This is nasty; the PCI devs are set up such that their own
316c481cfd5SMatt Evans * header's irq_line indicates the direct XICS IRQ number to
317c481cfd5SMatt Evans * use. There REALLY needs to be a hierarchical system in place
318c481cfd5SMatt Evans * to 'raise' an IRQ on the bridge which indexes/looks up which
319c481cfd5SMatt Evans * XICS IRQ to fire.
320c481cfd5SMatt Evans */
321c481cfd5SMatt Evans irqmap[5] = cpu_to_be32(hdr->irq_line);
322c481cfd5SMatt Evans irqmap[6] = cpu_to_be32(0x8);
323c481cfd5SMatt Evans
324c481cfd5SMatt Evans /* Add node to FDT */
325c481cfd5SMatt Evans node_off = fdt_add_subnode(fdt, bus_off, nodename);
326c481cfd5SMatt Evans if (node_off < 0) {
327c481cfd5SMatt Evans die("error making node subnode, %s\n", fdt_strerror(bus_off));
328c481cfd5SMatt Evans return node_off;
329c481cfd5SMatt Evans }
330c481cfd5SMatt Evans
331c481cfd5SMatt Evans _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id",
332c481cfd5SMatt Evans le16_to_cpu(hdr->vendor_id)));
333c481cfd5SMatt Evans _FDT(fdt_setprop_cell(fdt, node_off, "device-id",
334c481cfd5SMatt Evans le16_to_cpu(hdr->device_id)));
335c481cfd5SMatt Evans _FDT(fdt_setprop_cell(fdt, node_off, "revision-id",
336c481cfd5SMatt Evans hdr->revision_id));
337c481cfd5SMatt Evans _FDT(fdt_setprop_cell(fdt, node_off, "class-code",
338c481cfd5SMatt Evans hdr->class[0] | (hdr->class[1] << 8) | (hdr->class[2] << 16)));
339c481cfd5SMatt Evans _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id",
340c481cfd5SMatt Evans le16_to_cpu(hdr->subsys_id)));
341c481cfd5SMatt Evans _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id",
342c481cfd5SMatt Evans le16_to_cpu(hdr->subsys_vendor_id)));
343c481cfd5SMatt Evans
344c481cfd5SMatt Evans /* Config space region comes first */
3455568f3e3SBalbir Singh reg[0].phys_hi = cpu_to_be32(
3466606883cSWill Deacon of_pci_b_n(0) |
3476606883cSWill Deacon of_pci_b_p(0) |
3486606883cSWill Deacon of_pci_b_t(0) |
3496606883cSWill Deacon of_pci_b_ss(OF_PCI_SS_CONFIG) |
3506606883cSWill Deacon of_pci_b_bbbbbbbb(0) |
3516606883cSWill Deacon of_pci_b_ddddd(devid) |
3526606883cSWill Deacon of_pci_b_fff(fn));
3535568f3e3SBalbir Singh reg[0].addr = 0;
3545568f3e3SBalbir Singh reg[0].size = 0;
355c481cfd5SMatt Evans
356c481cfd5SMatt Evans n = 0;
357c481cfd5SMatt Evans /* Six BARs, no ROM supported, addresses are 32bit */
358c481cfd5SMatt Evans for (i = 0; i < 6; ++i) {
359c481cfd5SMatt Evans if (0 == hdr->bar[i]) {
360c481cfd5SMatt Evans continue;
361c481cfd5SMatt Evans }
362c481cfd5SMatt Evans
3635568f3e3SBalbir Singh reg[n+1].phys_hi = cpu_to_be32(
3646606883cSWill Deacon of_pci_b_n(0) |
3656606883cSWill Deacon of_pci_b_p(0) |
3666606883cSWill Deacon of_pci_b_t(0) |
3676606883cSWill Deacon of_pci_b_ss(bar_to_ss(le32_to_cpu(hdr->bar[i]))) |
3686606883cSWill Deacon of_pci_b_bbbbbbbb(0) |
3696606883cSWill Deacon of_pci_b_ddddd(devid) |
3706606883cSWill Deacon of_pci_b_fff(fn) |
3716606883cSWill Deacon of_pci_b_rrrrrrrr(bars[i]));
372*2f6384f9SAlexandru Elisei reg[n+1].size = cpu_to_be64(pci__bar_size(hdr, i));
3735568f3e3SBalbir Singh reg[n+1].addr = 0;
374c481cfd5SMatt Evans
3755568f3e3SBalbir Singh assigned_addresses[n].phys_hi = cpu_to_be32(
3766606883cSWill Deacon of_pci_b_n(1) |
3776606883cSWill Deacon of_pci_b_p(0) |
3786606883cSWill Deacon of_pci_b_t(0) |
3796606883cSWill Deacon of_pci_b_ss(bar_to_ss(le32_to_cpu(hdr->bar[i]))) |
3806606883cSWill Deacon of_pci_b_bbbbbbbb(0) |
3816606883cSWill Deacon of_pci_b_ddddd(devid) |
3826606883cSWill Deacon of_pci_b_fff(fn) |
3836606883cSWill Deacon of_pci_b_rrrrrrrr(bars[i]));
384c481cfd5SMatt Evans
385c481cfd5SMatt Evans /*
386c481cfd5SMatt Evans * Writing zeroes to assigned_addresses causes the guest kernel to
387c481cfd5SMatt Evans * reassign BARs
388c481cfd5SMatt Evans */
3895568f3e3SBalbir Singh assigned_addresses[n].addr = cpu_to_be64(bar_to_addr(le32_to_cpu(hdr->bar[i])));
3905568f3e3SBalbir Singh assigned_addresses[n].size = reg[n+1].size;
391c481cfd5SMatt Evans
392c481cfd5SMatt Evans ++n;
393c481cfd5SMatt Evans }
394c481cfd5SMatt Evans _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1)));
395c481cfd5SMatt Evans _FDT(fdt_setprop(fdt, node_off, "assigned-addresses",
396c481cfd5SMatt Evans assigned_addresses,
397c481cfd5SMatt Evans sizeof(assigned_addresses[0])*(n)));
398c481cfd5SMatt Evans _FDT(fdt_setprop_cell(fdt, node_off, "interrupts",
399c481cfd5SMatt Evans hdr->irq_pin));
400c481cfd5SMatt Evans
401c481cfd5SMatt Evans /* We don't set ibm,dma-window property as we don't have an IOMMU. */
402c481cfd5SMatt Evans
403c481cfd5SMatt Evans ++devices;
404a1166a18SWill Deacon dev_hdr = device__next_dev(dev_hdr);
405c481cfd5SMatt Evans }
406c481cfd5SMatt Evans
407c481cfd5SMatt Evans /* Write interrupt map */
408c481cfd5SMatt Evans _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
409c481cfd5SMatt Evans devices * sizeof(interrupt_map[0])));
410c481cfd5SMatt Evans
411c481cfd5SMatt Evans return 0;
412c481cfd5SMatt Evans }
413