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