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