Merge remote-tracking branch 'agraf/ppc-for-upstream' into staging

* agraf/ppc-for-upstream:
  linux-user: Fix invalid TARGET_ABI_BITS usage on ppc hosts
  target-ppc: Some support for dumping TLB_EMB TLBs
  ppce500_spin: Replace assert by hw_error (fixes compiler warning)
  pseries: Fix use of global CPU state
  pseries: Use the same interrupt swizzling for host bridges as p2p bridges
  pseries: Implement automatic PAPR VIO address allocation
  PPC: Fix up e500 cache size setting
  booke:Use MMU API for creating initial mapping for secondary cpus
This commit is contained in:
Anthony Liguori 2012-05-01 18:46:05 -05:00
commit 6d051a0c56
12 changed files with 146 additions and 78 deletions

View file

@ -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);
}
}

View file

@ -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)) {

View file

@ -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;

View file

@ -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(),
};

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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(),
};

View file

@ -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(),
};

View file

@ -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;

View file

@ -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",