]>
Commit | Line | Data |
---|---|---|
3384f95c DG |
1 | /* |
2 | * QEMU sPAPR PCI host originated from Uninorth PCI host | |
3 | * | |
4 | * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation. | |
5 | * Copyright (C) 2011 David Gibson, IBM Corporation. | |
6 | * | |
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | * of this software and associated documentation files (the "Software"), to deal | |
9 | * in the Software without restriction, including without limitation the rights | |
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | * copies of the Software, and to permit persons to whom the Software is | |
12 | * furnished to do so, subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice shall be included in | |
15 | * all copies or substantial portions of the Software. | |
16 | * | |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | * THE SOFTWARE. | |
24 | */ | |
25 | #include "hw.h" | |
26 | #include "pci.h" | |
27 | #include "pci_host.h" | |
28 | #include "hw/spapr.h" | |
29 | #include "hw/spapr_pci.h" | |
30 | #include "exec-memory.h" | |
31 | #include <libfdt.h> | |
32 | ||
33 | #include "hw/pci_internals.h" | |
34 | ||
3384f95c DG |
35 | static PCIDevice *find_dev(sPAPREnvironment *spapr, |
36 | uint64_t buid, uint32_t config_addr) | |
37 | { | |
3384f95c DG |
38 | int devfn = (config_addr >> 8) & 0xFF; |
39 | sPAPRPHBState *phb; | |
40 | ||
41 | QLIST_FOREACH(phb, &spapr->phbs, list) { | |
0866aca1 AL |
42 | BusChild *kid; |
43 | ||
3384f95c DG |
44 | if (phb->buid != buid) { |
45 | continue; | |
46 | } | |
47 | ||
0866aca1 AL |
48 | QTAILQ_FOREACH(kid, &phb->host_state.bus->qbus.children, sibling) { |
49 | PCIDevice *dev = (PCIDevice *)kid->child; | |
3384f95c DG |
50 | if (dev->devfn == devfn) { |
51 | return dev; | |
52 | } | |
53 | } | |
54 | } | |
55 | ||
56 | return NULL; | |
57 | } | |
58 | ||
3f7565c9 BH |
59 | static uint32_t rtas_pci_cfgaddr(uint32_t arg) |
60 | { | |
92615a5a | 61 | /* This handles the encoding of extended config space addresses */ |
3f7565c9 BH |
62 | return ((arg >> 20) & 0xf00) | (arg & 0xff); |
63 | } | |
64 | ||
92615a5a DG |
65 | static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid, |
66 | uint32_t addr, uint32_t size, | |
67 | target_ulong rets) | |
88045ac5 | 68 | { |
92615a5a DG |
69 | PCIDevice *pci_dev; |
70 | uint32_t val; | |
71 | ||
72 | if ((size != 1) && (size != 2) && (size != 4)) { | |
73 | /* access must be 1, 2 or 4 bytes */ | |
74 | rtas_st(rets, 0, -1); | |
75 | return; | |
88045ac5 | 76 | } |
88045ac5 | 77 | |
92615a5a DG |
78 | pci_dev = find_dev(spapr, buid, addr); |
79 | addr = rtas_pci_cfgaddr(addr); | |
80 | ||
81 | if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) { | |
82 | /* Access must be to a valid device, within bounds and | |
83 | * naturally aligned */ | |
84 | rtas_st(rets, 0, -1); | |
85 | return; | |
88045ac5 | 86 | } |
92615a5a DG |
87 | |
88 | val = pci_host_config_read_common(pci_dev, addr, | |
89 | pci_config_size(pci_dev), size); | |
90 | ||
91 | rtas_st(rets, 0, 0); | |
92 | rtas_st(rets, 1, val); | |
88045ac5 AG |
93 | } |
94 | ||
3384f95c DG |
95 | static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, |
96 | uint32_t token, uint32_t nargs, | |
97 | target_ulong args, | |
98 | uint32_t nret, target_ulong rets) | |
99 | { | |
92615a5a DG |
100 | uint64_t buid; |
101 | uint32_t size, addr; | |
3384f95c | 102 | |
92615a5a | 103 | if ((nargs != 4) || (nret != 2)) { |
3384f95c DG |
104 | rtas_st(rets, 0, -1); |
105 | return; | |
106 | } | |
92615a5a DG |
107 | |
108 | buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); | |
3384f95c | 109 | size = rtas_ld(args, 3); |
92615a5a DG |
110 | addr = rtas_ld(args, 0); |
111 | ||
112 | finish_read_pci_config(spapr, buid, addr, size, rets); | |
3384f95c DG |
113 | } |
114 | ||
115 | static void rtas_read_pci_config(sPAPREnvironment *spapr, | |
116 | uint32_t token, uint32_t nargs, | |
117 | target_ulong args, | |
118 | uint32_t nret, target_ulong rets) | |
119 | { | |
92615a5a | 120 | uint32_t size, addr; |
3384f95c | 121 | |
92615a5a | 122 | if ((nargs != 2) || (nret != 2)) { |
3384f95c DG |
123 | rtas_st(rets, 0, -1); |
124 | return; | |
125 | } | |
92615a5a | 126 | |
3384f95c | 127 | size = rtas_ld(args, 1); |
92615a5a DG |
128 | addr = rtas_ld(args, 0); |
129 | ||
130 | finish_read_pci_config(spapr, 0, addr, size, rets); | |
131 | } | |
132 | ||
133 | static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid, | |
134 | uint32_t addr, uint32_t size, | |
135 | uint32_t val, target_ulong rets) | |
136 | { | |
137 | PCIDevice *pci_dev; | |
138 | ||
139 | if ((size != 1) && (size != 2) && (size != 4)) { | |
140 | /* access must be 1, 2 or 4 bytes */ | |
141 | rtas_st(rets, 0, -1); | |
142 | return; | |
143 | } | |
144 | ||
145 | pci_dev = find_dev(spapr, buid, addr); | |
146 | addr = rtas_pci_cfgaddr(addr); | |
147 | ||
148 | if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) { | |
149 | /* Access must be to a valid device, within bounds and | |
150 | * naturally aligned */ | |
151 | rtas_st(rets, 0, -1); | |
152 | return; | |
153 | } | |
154 | ||
155 | pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev), | |
156 | val, size); | |
157 | ||
3384f95c | 158 | rtas_st(rets, 0, 0); |
3384f95c DG |
159 | } |
160 | ||
161 | static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, | |
162 | uint32_t token, uint32_t nargs, | |
163 | target_ulong args, | |
164 | uint32_t nret, target_ulong rets) | |
165 | { | |
92615a5a | 166 | uint64_t buid; |
3384f95c | 167 | uint32_t val, size, addr; |
3384f95c | 168 | |
92615a5a | 169 | if ((nargs != 5) || (nret != 1)) { |
3384f95c DG |
170 | rtas_st(rets, 0, -1); |
171 | return; | |
172 | } | |
92615a5a DG |
173 | |
174 | buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); | |
3384f95c DG |
175 | val = rtas_ld(args, 4); |
176 | size = rtas_ld(args, 3); | |
92615a5a DG |
177 | addr = rtas_ld(args, 0); |
178 | ||
179 | finish_write_pci_config(spapr, buid, addr, size, val, rets); | |
3384f95c DG |
180 | } |
181 | ||
182 | static void rtas_write_pci_config(sPAPREnvironment *spapr, | |
183 | uint32_t token, uint32_t nargs, | |
184 | target_ulong args, | |
185 | uint32_t nret, target_ulong rets) | |
186 | { | |
187 | uint32_t val, size, addr; | |
3384f95c | 188 | |
92615a5a | 189 | if ((nargs != 3) || (nret != 1)) { |
3384f95c DG |
190 | rtas_st(rets, 0, -1); |
191 | return; | |
192 | } | |
92615a5a DG |
193 | |
194 | ||
3384f95c DG |
195 | val = rtas_ld(args, 2); |
196 | size = rtas_ld(args, 1); | |
92615a5a DG |
197 | addr = rtas_ld(args, 0); |
198 | ||
199 | finish_write_pci_config(spapr, 0, addr, size, val, rets); | |
3384f95c DG |
200 | } |
201 | ||
7fb0bd34 DG |
202 | static int pci_spapr_swizzle(int slot, int pin) |
203 | { | |
204 | return (slot + pin) % PCI_NUM_PINS; | |
205 | } | |
206 | ||
3384f95c DG |
207 | static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num) |
208 | { | |
209 | /* | |
210 | * Here we need to convert pci_dev + irq_num to some unique value | |
7fb0bd34 DG |
211 | * which is less than number of IRQs on the specific bus (4). We |
212 | * use standard PCI swizzling, that is (slot number + pin number) | |
213 | * % 4. | |
3384f95c | 214 | */ |
7fb0bd34 | 215 | return pci_spapr_swizzle(PCI_SLOT(pci_dev->devfn), irq_num); |
3384f95c DG |
216 | } |
217 | ||
218 | static void pci_spapr_set_irq(void *opaque, int irq_num, int level) | |
219 | { | |
220 | /* | |
221 | * Here we use the number returned by pci_spapr_map_irq to find a | |
222 | * corresponding qemu_irq. | |
223 | */ | |
224 | sPAPRPHBState *phb = opaque; | |
225 | ||
a307d594 | 226 | qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level); |
3384f95c DG |
227 | } |
228 | ||
3384f95c DG |
229 | static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr, |
230 | unsigned size) | |
231 | { | |
232 | switch (size) { | |
233 | case 1: | |
234 | return cpu_inb(addr); | |
235 | case 2: | |
236 | return cpu_inw(addr); | |
237 | case 4: | |
238 | return cpu_inl(addr); | |
239 | } | |
240 | assert(0); | |
241 | } | |
242 | ||
243 | static void spapr_io_write(void *opaque, target_phys_addr_t addr, | |
244 | uint64_t data, unsigned size) | |
245 | { | |
246 | switch (size) { | |
247 | case 1: | |
248 | cpu_outb(addr, data); | |
249 | return; | |
250 | case 2: | |
251 | cpu_outw(addr, data); | |
252 | return; | |
253 | case 4: | |
254 | cpu_outl(addr, data); | |
255 | return; | |
256 | } | |
257 | assert(0); | |
258 | } | |
259 | ||
a348f108 | 260 | static const MemoryRegionOps spapr_io_ops = { |
3384f95c DG |
261 | .endianness = DEVICE_LITTLE_ENDIAN, |
262 | .read = spapr_io_read, | |
263 | .write = spapr_io_write | |
264 | }; | |
265 | ||
298a9710 DG |
266 | /* |
267 | * PHB PCI device | |
268 | */ | |
edded454 DG |
269 | static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque, |
270 | int devfn) | |
271 | { | |
272 | sPAPRPHBState *phb = opaque; | |
273 | ||
274 | return phb->dma; | |
275 | } | |
276 | ||
298a9710 | 277 | static int spapr_phb_init(SysBusDevice *s) |
3384f95c | 278 | { |
231903bf | 279 | sPAPRPHBState *phb = DO_UPCAST(sPAPRPHBState, host_state.busdev, s); |
298a9710 DG |
280 | char *namebuf; |
281 | int i; | |
3384f95c | 282 | PCIBus *bus; |
edded454 | 283 | uint32_t liobn; |
3384f95c | 284 | |
298a9710 DG |
285 | phb->dtbusname = g_strdup_printf("pci@%" PRIx64, phb->buid); |
286 | namebuf = alloca(strlen(phb->dtbusname) + 32); | |
3384f95c | 287 | |
298a9710 DG |
288 | /* Initialize memory regions */ |
289 | sprintf(namebuf, "%s.mmio", phb->dtbusname); | |
3384f95c DG |
290 | memory_region_init(&phb->memspace, namebuf, INT64_MAX); |
291 | ||
298a9710 | 292 | sprintf(namebuf, "%s.mmio-alias", phb->dtbusname); |
3384f95c | 293 | memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace, |
298a9710 DG |
294 | SPAPR_PCI_MEM_WIN_BUS_OFFSET, phb->mem_win_size); |
295 | memory_region_add_subregion(get_system_memory(), phb->mem_win_addr, | |
3384f95c DG |
296 | &phb->memwindow); |
297 | ||
3384f95c DG |
298 | /* On ppc, we only have MMIO no specific IO space from the CPU |
299 | * perspective. In theory we ought to be able to embed the PCI IO | |
300 | * memory region direction in the system memory space. However, | |
301 | * if any of the IO BAR subregions use the old_portio mechanism, | |
302 | * that won't be processed properly unless accessed from the | |
303 | * system io address space. This hack to bounce things via | |
304 | * system_io works around the problem until all the users of | |
305 | * old_portion are updated */ | |
298a9710 | 306 | sprintf(namebuf, "%s.io", phb->dtbusname); |
3384f95c DG |
307 | memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE); |
308 | /* FIXME: fix to support multiple PHBs */ | |
309 | memory_region_add_subregion(get_system_io(), 0, &phb->iospace); | |
310 | ||
298a9710 | 311 | sprintf(namebuf, "%s.io-alias", phb->dtbusname); |
3384f95c DG |
312 | memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb, |
313 | namebuf, SPAPR_PCI_IO_WIN_SIZE); | |
298a9710 | 314 | memory_region_add_subregion(get_system_memory(), phb->io_win_addr, |
3384f95c DG |
315 | &phb->iowindow); |
316 | ||
231903bf | 317 | bus = pci_register_bus(&phb->host_state.busdev.qdev, |
298a9710 DG |
318 | phb->busname ? phb->busname : phb->dtbusname, |
319 | pci_spapr_set_irq, pci_spapr_map_irq, phb, | |
320 | &phb->memspace, &phb->iospace, | |
7fb0bd34 | 321 | PCI_DEVFN(0, 0), PCI_NUM_PINS); |
298a9710 DG |
322 | phb->host_state.bus = bus; |
323 | ||
edded454 DG |
324 | liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16); |
325 | phb->dma = spapr_tce_new_dma_context(liobn, 0x40000000); | |
326 | pci_setup_iommu(bus, spapr_pci_dma_context_fn, phb); | |
327 | ||
298a9710 DG |
328 | QLIST_INSERT_HEAD(&spapr->phbs, phb, list); |
329 | ||
330 | /* Initialize the LSI table */ | |
7fb0bd34 | 331 | for (i = 0; i < PCI_NUM_PINS; i++) { |
a307d594 | 332 | uint32_t irq; |
298a9710 | 333 | |
a307d594 AK |
334 | irq = spapr_allocate_lsi(0); |
335 | if (!irq) { | |
298a9710 DG |
336 | return -1; |
337 | } | |
338 | ||
a307d594 | 339 | phb->lsi_table[i].irq = irq; |
298a9710 DG |
340 | } |
341 | ||
342 | return 0; | |
343 | } | |
344 | ||
345 | static Property spapr_phb_properties[] = { | |
346 | DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, 0), | |
347 | DEFINE_PROP_STRING("busname", sPAPRPHBState, busname), | |
348 | DEFINE_PROP_HEX64("mem_win_addr", sPAPRPHBState, mem_win_addr, 0), | |
349 | DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, 0x20000000), | |
350 | DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, 0), | |
351 | DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, 0x10000), | |
352 | DEFINE_PROP_END_OF_LIST(), | |
353 | }; | |
354 | ||
355 | static void spapr_phb_class_init(ObjectClass *klass, void *data) | |
356 | { | |
357 | SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); | |
358 | DeviceClass *dc = DEVICE_CLASS(klass); | |
359 | ||
360 | sdc->init = spapr_phb_init; | |
361 | dc->props = spapr_phb_properties; | |
298a9710 | 362 | } |
3384f95c | 363 | |
298a9710 DG |
364 | static TypeInfo spapr_phb_info = { |
365 | .name = "spapr-pci-host-bridge", | |
366 | .parent = TYPE_SYS_BUS_DEVICE, | |
367 | .instance_size = sizeof(sPAPRPHBState), | |
368 | .class_init = spapr_phb_class_init, | |
369 | }; | |
370 | ||
371 | void spapr_create_phb(sPAPREnvironment *spapr, | |
372 | const char *busname, uint64_t buid, | |
373 | uint64_t mem_win_addr, uint64_t mem_win_size, | |
374 | uint64_t io_win_addr) | |
375 | { | |
376 | DeviceState *dev; | |
377 | ||
378 | dev = qdev_create(NULL, spapr_phb_info.name); | |
3384f95c | 379 | |
298a9710 DG |
380 | if (busname) { |
381 | qdev_prop_set_string(dev, "busname", g_strdup(busname)); | |
382 | } | |
383 | qdev_prop_set_uint64(dev, "buid", buid); | |
384 | qdev_prop_set_uint64(dev, "mem_win_addr", mem_win_addr); | |
385 | qdev_prop_set_uint64(dev, "mem_win_size", mem_win_size); | |
386 | qdev_prop_set_uint64(dev, "io_win_addr", io_win_addr); | |
387 | ||
388 | qdev_init_nofail(dev); | |
3384f95c DG |
389 | } |
390 | ||
391 | /* Macros to operate with address in OF binding to PCI */ | |
392 | #define b_x(x, p, l) (((x) & ((1<<(l))-1)) << (p)) | |
393 | #define b_n(x) b_x((x), 31, 1) /* 0 if relocatable */ | |
394 | #define b_p(x) b_x((x), 30, 1) /* 1 if prefetchable */ | |
395 | #define b_t(x) b_x((x), 29, 1) /* 1 if the address is aliased */ | |
396 | #define b_ss(x) b_x((x), 24, 2) /* the space code */ | |
397 | #define b_bbbbbbbb(x) b_x((x), 16, 8) /* bus number */ | |
398 | #define b_ddddd(x) b_x((x), 11, 5) /* device number */ | |
399 | #define b_fff(x) b_x((x), 8, 3) /* function number */ | |
400 | #define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */ | |
401 | ||
e0fdbd7c AK |
402 | int spapr_populate_pci_dt(sPAPRPHBState *phb, |
403 | uint32_t xics_phandle, | |
404 | void *fdt) | |
3384f95c | 405 | { |
7fb0bd34 | 406 | int bus_off, i, j; |
3384f95c | 407 | char nodename[256]; |
3384f95c DG |
408 | uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) }; |
409 | struct { | |
410 | uint32_t hi; | |
411 | uint64_t child; | |
412 | uint64_t parent; | |
413 | uint64_t size; | |
c4889f54 | 414 | } QEMU_PACKED ranges[] = { |
3384f95c DG |
415 | { |
416 | cpu_to_be32(b_ss(1)), cpu_to_be64(0), | |
417 | cpu_to_be64(phb->io_win_addr), | |
418 | cpu_to_be64(memory_region_size(&phb->iospace)), | |
419 | }, | |
420 | { | |
421 | cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET), | |
422 | cpu_to_be64(phb->mem_win_addr), | |
423 | cpu_to_be64(memory_region_size(&phb->memwindow)), | |
424 | }, | |
425 | }; | |
426 | uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 }; | |
427 | uint32_t interrupt_map_mask[] = { | |
7fb0bd34 DG |
428 | cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)}; |
429 | uint32_t interrupt_map[PCI_SLOT_MAX * PCI_NUM_PINS][7]; | |
3384f95c DG |
430 | |
431 | /* Start populating the FDT */ | |
432 | sprintf(nodename, "pci@%" PRIx64, phb->buid); | |
433 | bus_off = fdt_add_subnode(fdt, 0, nodename); | |
434 | if (bus_off < 0) { | |
435 | return bus_off; | |
436 | } | |
437 | ||
438 | #define _FDT(exp) \ | |
439 | do { \ | |
440 | int ret = (exp); \ | |
441 | if (ret < 0) { \ | |
442 | return ret; \ | |
443 | } \ | |
444 | } while (0) | |
445 | ||
446 | /* Write PHB properties */ | |
447 | _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci")); | |
448 | _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB")); | |
449 | _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3)); | |
450 | _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2)); | |
451 | _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1)); | |
452 | _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0)); | |
453 | _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range))); | |
454 | _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges))); | |
455 | _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg))); | |
3f7565c9 | 456 | _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1)); |
3384f95c | 457 | |
4d8d5467 BH |
458 | /* Build the interrupt-map, this must matches what is done |
459 | * in pci_spapr_map_irq | |
460 | */ | |
461 | _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask", | |
462 | &interrupt_map_mask, sizeof(interrupt_map_mask))); | |
7fb0bd34 DG |
463 | for (i = 0; i < PCI_SLOT_MAX; i++) { |
464 | for (j = 0; j < PCI_NUM_PINS; j++) { | |
465 | uint32_t *irqmap = interrupt_map[i*PCI_NUM_PINS + j]; | |
466 | int lsi_num = pci_spapr_swizzle(i, j); | |
467 | ||
468 | irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0)); | |
469 | irqmap[1] = 0; | |
470 | irqmap[2] = 0; | |
471 | irqmap[3] = cpu_to_be32(j+1); | |
472 | irqmap[4] = cpu_to_be32(xics_phandle); | |
a307d594 | 473 | irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq); |
7fb0bd34 DG |
474 | irqmap[6] = cpu_to_be32(0x8); |
475 | } | |
3384f95c | 476 | } |
3384f95c DG |
477 | /* Write interrupt map */ |
478 | _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map, | |
7fb0bd34 | 479 | sizeof(interrupt_map))); |
3384f95c | 480 | |
edded454 DG |
481 | spapr_dma_dt(fdt, bus_off, "ibm,dma-window", phb->dma); |
482 | ||
3384f95c DG |
483 | return 0; |
484 | } | |
298a9710 | 485 | |
fa28f71b AK |
486 | void spapr_pci_rtas_init(void) |
487 | { | |
488 | spapr_rtas_register("read-pci-config", rtas_read_pci_config); | |
489 | spapr_rtas_register("write-pci-config", rtas_write_pci_config); | |
490 | spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config); | |
491 | spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config); | |
492 | } | |
493 | ||
298a9710 DG |
494 | static void register_types(void) |
495 | { | |
496 | type_register_static(&spapr_phb_info); | |
497 | } | |
498 | type_init(register_types) |