diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index 960b7b0c3d..fddf2197a9 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -86,6 +86,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env, tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M; tlb->mas7_3 = pa & TARGET_PAGE_MASK; tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; + env->tlb_dirty = true; } static void spin_kick(void *data) @@ -178,7 +179,7 @@ static uint64_t spin_read(void *opaque, target_phys_addr_t addr, unsigned len) case 4: return ldl_p(spin_p); default: - assert(0); + hw_error("ppce500: unexpected %s with len = %u", __func__, len); } } diff --git a/hw/spapr.c b/hw/spapr.c index bfaf260d54..cca20f9a51 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -631,8 +631,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, for (i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - spapr_vty_create(spapr->vio_bus, SPAPR_VTY_BASE_ADDRESS + i, - serial_hds[i]); + spapr_vty_create(spapr->vio_bus, serial_hds[i]); } } @@ -650,14 +649,14 @@ static void ppc_spapr_init(ram_addr_t ram_size, } if (strcmp(nd->model, "ibmveth") == 0) { - spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd); + spapr_vlan_create(spapr->vio_bus, nd); } else { pci_nic_init_nofail(&nd_table[i], nd->model, NULL); } } for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) { - spapr_vscsi_create(spapr->vio_bus, 0x2000 + i); + spapr_vscsi_create(spapr->vio_bus); } if (rma_size < (MIN_RMA_SLOF << 20)) { diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 634763eefd..94bb504ca6 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -482,7 +482,7 @@ static target_ulong register_dtl(CPUPPCState *env, target_ulong addr) return H_SUCCESS; } -static target_ulong deregister_dtl(CPUPPCState *emv, target_ulong addr) +static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr) { env->dispatch_trace_log = 0; env->dtl_size = 0; diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index e18d2eb901..8313043652 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -204,12 +204,11 @@ static int spapr_vlan_init(VIOsPAPRDevice *sdev) return 0; } -void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd) +void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd) { DeviceState *dev; dev = qdev_create(&bus->bus, "spapr-vlan"); - qdev_prop_set_uint32(dev, "reg", reg); qdev_set_nic_properties(dev, nd); @@ -480,7 +479,7 @@ static target_ulong h_multicast_ctrl(CPUPPCState *env, sPAPREnvironment *spapr, } static Property spapr_vlan_properties[] = { - DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 0x10000000), + DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x10000000), DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index a564c007b4..25b400aa47 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -198,16 +198,20 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr, finish_write_pci_config(spapr, 0, addr, size, val, rets); } +static int pci_spapr_swizzle(int slot, int pin) +{ + return (slot + pin) % PCI_NUM_PINS; +} + static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num) { /* * Here we need to convert pci_dev + irq_num to some unique value - * which is less than number of IRQs on the specific bus (now it - * is 16). At the moment irq_num == device_id (number of the - * slot?) - * FIXME: we should swizzle in fn and irq_num + * which is less than number of IRQs on the specific bus (4). We + * use standard PCI swizzling, that is (slot number + pin number) + * % 4. */ - return (pci_dev->devfn >> 3) % SPAPR_PCI_NUM_LSI; + return pci_spapr_swizzle(PCI_SLOT(pci_dev->devfn), irq_num); } static void pci_spapr_set_irq(void *opaque, int irq_num, int level) @@ -304,13 +308,13 @@ static int spapr_phb_init(SysBusDevice *s) phb->busname ? phb->busname : phb->dtbusname, pci_spapr_set_irq, pci_spapr_map_irq, phb, &phb->memspace, &phb->iospace, - PCI_DEVFN(0, 0), SPAPR_PCI_NUM_LSI); + PCI_DEVFN(0, 0), PCI_NUM_PINS); phb->host_state.bus = bus; QLIST_INSERT_HEAD(&spapr->phbs, phb, list); /* Initialize the LSI table */ - for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) { + for (i = 0; i < PCI_NUM_PINS; i++) { qemu_irq qirq; uint32_t num; @@ -392,8 +396,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, uint32_t xics_phandle, void *fdt) { - PCIBus *bus = phb->host_state.bus; - int bus_off, i; + int bus_off, i, j; char nodename[256]; uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) }; struct { @@ -415,8 +418,8 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, }; uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 }; uint32_t interrupt_map_mask[] = { - cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, 0x0}; - uint32_t interrupt_map[bus->nirq][7]; + cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)}; + uint32_t interrupt_map[PCI_SLOT_MAX * PCI_NUM_PINS][7]; /* Start populating the FDT */ sprintf(nodename, "pci@%" PRIx64, phb->buid); @@ -450,19 +453,23 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, */ _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask", &interrupt_map_mask, sizeof(interrupt_map_mask))); - for (i = 0; i < 7; i++) { - uint32_t *irqmap = interrupt_map[i]; - irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0)); - irqmap[1] = 0; - irqmap[2] = 0; - irqmap[3] = 0; - irqmap[4] = cpu_to_be32(xics_phandle); - irqmap[5] = cpu_to_be32(phb->lsi_table[i % SPAPR_PCI_NUM_LSI].dt_irq); - irqmap[6] = cpu_to_be32(0x8); + for (i = 0; i < PCI_SLOT_MAX; i++) { + for (j = 0; j < PCI_NUM_PINS; j++) { + uint32_t *irqmap = interrupt_map[i*PCI_NUM_PINS + j]; + int lsi_num = pci_spapr_swizzle(i, j); + + irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0)); + irqmap[1] = 0; + irqmap[2] = 0; + irqmap[3] = cpu_to_be32(j+1); + irqmap[4] = cpu_to_be32(xics_phandle); + irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].dt_irq); + irqmap[6] = cpu_to_be32(0x8); + } } /* Write interrupt map */ _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map, - 7 * sizeof(interrupt_map[0]))); + sizeof(interrupt_map))); return 0; } diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h index 039f85bd4b..f54c2e8108 100644 --- a/hw/spapr_pci.h +++ b/hw/spapr_pci.h @@ -23,11 +23,10 @@ #if !defined(__HW_SPAPR_PCI_H__) #define __HW_SPAPR_PCI_H__ +#include "hw/pci.h" #include "hw/pci_host.h" #include "hw/xics.h" -#define SPAPR_PCI_NUM_LSI 16 - typedef struct sPAPRPHBState { SysBusDevice busdev; PCIHostState host_state; @@ -43,7 +42,7 @@ typedef struct sPAPRPHBState { struct { uint32_t dt_irq; qemu_irq qirq; - } lsi_table[SPAPR_PCI_NUM_LSI]; + } lsi_table[PCI_NUM_PINS]; QLIST_ENTRY(sPAPRPHBState) list; } sPAPRPHBState; diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index fccf48bd67..315ab8091c 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -620,28 +620,22 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, 0); } -static int spapr_vio_check_reg(VIOsPAPRDevice *sdev) +static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev) { - VIOsPAPRDevice *other_sdev; + VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus); DeviceState *qdev; - VIOsPAPRBus *sbus; - - sbus = DO_UPCAST(VIOsPAPRBus, bus, sdev->qdev.parent_bus); + VIOsPAPRDevice *other; /* - * Check two device aren't given clashing addresses by the user (or some - * other mechanism). We have to open code this because we have to check - * for matches with devices other than us. + * Check for a device other than the given one which is already + * using the requested address. We have to open code this because + * the given dev might already be in the list. */ - QTAILQ_FOREACH(qdev, &sbus->bus.children, sibling) { - other_sdev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); + QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) { + other = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); - if (other_sdev != sdev && other_sdev->reg == sdev->reg) { - fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n", - object_get_typename(OBJECT(sdev)), - object_get_typename(OBJECT(qdev)), - sdev->reg); - return -EEXIST; + if (other != dev && other->reg == dev->reg) { + return other; } } @@ -667,11 +661,30 @@ static int spapr_vio_busdev_init(DeviceState *qdev) VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); char *id; - int ret; - ret = spapr_vio_check_reg(dev); - if (ret) { - return ret; + if (dev->reg != -1) { + /* + * Explicitly assigned address, just verify that no-one else + * is using it. other mechanism). We have to open code this + * rather than using spapr_vio_find_by_reg() because sdev + * itself is already in the list. + */ + VIOsPAPRDevice *other = reg_conflict(dev); + + if (other) { + fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n", + object_get_typename(OBJECT(qdev)), + object_get_typename(OBJECT(&other->qdev)), + dev->reg); + return -1; + } + } else { + /* Need to assign an address */ + VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus); + + do { + dev->reg = bus->next_reg++; + } while (reg_conflict(dev)); } /* Don't overwrite ids assigned on the command line */ @@ -731,6 +744,7 @@ VIOsPAPRBus *spapr_vio_bus_init(void) qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio"); bus = DO_UPCAST(VIOsPAPRBus, bus, qbus); + bus->next_reg = 0x1000; /* hcall-vio */ spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 10ab3594c0..87816e456d 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -32,8 +32,6 @@ enum VIOsPAPR_TCEAccess { SPAPR_TCE_RW = 3, }; -#define SPAPR_VTY_BASE_ADDRESS 0x30000000 - #define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device" #define VIO_SPAPR_DEVICE(obj) \ OBJECT_CHECK(VIOsPAPRDevice, (obj), TYPE_VIO_SPAPR_DEVICE) @@ -82,13 +80,14 @@ struct VIOsPAPRDevice { VIOsPAPR_CRQ crq; }; -#define DEFINE_SPAPR_PROPERTIES(type, field, default_reg, default_dma_window) \ - DEFINE_PROP_UINT32("reg", type, field.reg, default_reg), \ +#define DEFINE_SPAPR_PROPERTIES(type, field, default_dma_window) \ + DEFINE_PROP_UINT32("reg", type, field.reg, -1), \ DEFINE_PROP_UINT32("dma-window", type, field.rtce_window_size, \ default_dma_window) struct VIOsPAPRBus { BusState bus; + uint32_t next_reg; int (*init)(VIOsPAPRDevice *dev); int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); }; @@ -119,9 +118,9 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq); VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg); void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len); -void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev); -void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd); -void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg); +void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev); +void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd); +void spapr_vscsi_create(VIOsPAPRBus *bus); VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 538e0b7938..037867ab4f 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -918,12 +918,11 @@ static int spapr_vscsi_init(VIOsPAPRDevice *dev) return 0; } -void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg) +void spapr_vscsi_create(VIOsPAPRBus *bus) { DeviceState *dev; dev = qdev_create(&bus->bus, "spapr-vscsi"); - qdev_prop_set_uint32(dev, "reg", reg); qdev_init_nofail(dev); } @@ -946,7 +945,7 @@ static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) } static Property spapr_vscsi_properties[] = { - DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000), + DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x10000000), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index a30c040b97..c9674f36a6 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -123,18 +123,17 @@ static target_ulong h_get_term_char(CPUPPCState *env, sPAPREnvironment *spapr, return H_SUCCESS; } -void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev) +void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev) { DeviceState *dev; dev = qdev_create(&bus->bus, "spapr-vty"); - qdev_prop_set_uint32(dev, "reg", reg); qdev_prop_set_chr(dev, "chardev", chardev); qdev_init_nofail(dev); } static Property spapr_vty_properties[] = { - DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0), + DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, 0), DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev), DEFINE_PROP_END_OF_LIST(), }; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index c610ce3e28..e97e49640d 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1466,6 +1466,53 @@ static const char *book3e_tsize_to_str[32] = { "1T", "2T" }; +static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf, + CPUPPCState *env) +{ + ppcemb_tlb_t *entry; + int i; + + if (kvm_enabled() && !env->kvm_sw_tlb) { + cpu_fprintf(f, "Cannot access KVM TLB\n"); + return; + } + + cpu_fprintf(f, "\nTLB:\n"); + cpu_fprintf(f, "Effective Physical Size PID Prot " + "Attr\n"); + + entry = &env->tlb.tlbe[0]; + for (i = 0; i < env->nb_tlb; i++, entry++) { + target_phys_addr_t ea, pa; + target_ulong mask; + uint64_t size = (uint64_t)entry->size; + char size_buf[20]; + + /* Check valid flag */ + if (!(entry->prot & PAGE_VALID)) { + continue; + } + + mask = ~(entry->size - 1); + ea = entry->EPN & mask; + pa = entry->RPN & mask; +#if (TARGET_PHYS_ADDR_BITS >= 36) + /* Extend the physical address to 36 bits */ + pa |= (target_phys_addr_t)(entry->RPN & 0xF) << 32; +#endif + size /= 1024; + if (size >= 1024) { + snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024); + } else { + snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size); + } + cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n", + (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID, + entry->prot, entry->attr); + } + +} + static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env, int tlbn, int offset, int tlbsize) @@ -1561,6 +1608,9 @@ static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf, void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) { switch (env->mmu_model) { + case POWERPC_MMU_BOOKE: + mmubooke_dump_mmu(f, cpu_fprintf, env); + break; case POWERPC_MMU_BOOKE206: mmubooke206_dump_mmu(f, cpu_fprintf, env); break; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ba4b84d86b..6f61175e7d 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4461,33 +4461,36 @@ static void init_proc_e500 (CPUPPCState *env, int version) &spr_read_spefscr, &spr_write_spefscr, &spr_read_spefscr, &spr_write_spefscr, 0x00000000); +#if !defined(CONFIG_USER_ONLY) /* Memory management */ -#if defined(CONFIG_USER_ONLY) - env->dcache_line_size = 32; - env->icache_line_size = 32; -#else /* !defined(CONFIG_USER_ONLY) */ env->nb_pids = 3; env->nb_ways = 2; env->id_tlbs = 0; switch (version) { case fsl_e500v1: - /* e500v1 */ tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256); tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); - env->dcache_line_size = 32; - env->icache_line_size = 32; break; case fsl_e500v2: - /* e500v2 */ tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512); tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); + break; + case fsl_e500mc: + tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512); + tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64); + break; + default: + cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); + } +#endif + /* Cache sizes */ + switch (version) { + case fsl_e500v1: + case fsl_e500v2: env->dcache_line_size = 32; env->icache_line_size = 32; break; case fsl_e500mc: - /* e500mc */ - tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512); - tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64); env->dcache_line_size = 64; env->icache_line_size = 64; l1cfg0 |= 0x1000000; /* 64 byte cache block size */ @@ -4495,7 +4498,6 @@ static void init_proc_e500 (CPUPPCState *env, int version) default: cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); } -#endif gen_spr_BookE206(env, 0x000000DF, tlbncfg); /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0",