mirror of https://github.com/xemu-project/xemu.git
PPC: Qdev'ify e500 pci
The e500 PCI controller isn't qdev'ified yet. This leads to severe issues when running with -drive. To be able to use a virtio disk with an e500 VM, let's convert the PCI controller over to qdev. Reviewed-by: Paul Brook <paul@codesourcery.com> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
5389055a91
commit
be13cc7a35
22
hw/ppce500.h
22
hw/ppce500.h
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* QEMU PowerPC E500 emulation shared definitions
|
|
||||||
*
|
|
||||||
* Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Author: Yu Liu, <yu.liu@freescale.com>
|
|
||||||
*
|
|
||||||
* This file is derived from hw/ppc440.h
|
|
||||||
* the copyright for that material belongs to the original owners.
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if !defined(PPC_E500_H)
|
|
||||||
#define PPC_E500_H
|
|
||||||
|
|
||||||
PCIBus *ppce500_pci_init(qemu_irq *pic, target_phys_addr_t registers);
|
|
||||||
|
|
||||||
#endif /* !defined(PPC_E500_H) */
|
|
|
@ -29,9 +29,9 @@
|
||||||
#include "device_tree.h"
|
#include "device_tree.h"
|
||||||
#include "openpic.h"
|
#include "openpic.h"
|
||||||
#include "ppc.h"
|
#include "ppc.h"
|
||||||
#include "ppce500.h"
|
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
#include "sysbus.h"
|
||||||
|
|
||||||
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
|
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
|
||||||
#define UIMAGE_LOAD_BASE 0
|
#define UIMAGE_LOAD_BASE 0
|
||||||
|
@ -222,7 +222,8 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||||
target_long initrd_size=0;
|
target_long initrd_size=0;
|
||||||
int i=0;
|
int i=0;
|
||||||
unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
|
unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
|
||||||
qemu_irq *irqs, *mpic, *pci_irqs;
|
qemu_irq *irqs, *mpic;
|
||||||
|
DeviceState *dev;
|
||||||
struct boot_info *boot_info;
|
struct boot_info *boot_info;
|
||||||
|
|
||||||
/* Setup CPU */
|
/* Setup CPU */
|
||||||
|
@ -270,12 +271,11 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PCI */
|
/* PCI */
|
||||||
pci_irqs = qemu_malloc(sizeof(qemu_irq) * 4);
|
dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
|
||||||
pci_irqs[0] = mpic[pci_irq_nrs[0]];
|
mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
|
||||||
pci_irqs[1] = mpic[pci_irq_nrs[1]];
|
mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
|
||||||
pci_irqs[2] = mpic[pci_irq_nrs[2]];
|
NULL);
|
||||||
pci_irqs[3] = mpic[pci_irq_nrs[3]];
|
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
|
||||||
pci_bus = ppce500_pci_init(pci_irqs, MPC8544_PCI_REGS_BASE);
|
|
||||||
if (!pci_bus)
|
if (!pci_bus)
|
||||||
printf("couldn't create PCI controller!\n");
|
printf("couldn't create PCI controller!\n");
|
||||||
|
|
||||||
|
|
134
hw/ppce500_pci.c
134
hw/ppce500_pci.c
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
#include "ppce500.h"
|
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
#include "pci_host.h"
|
#include "pci_host.h"
|
||||||
#include "bswap.h"
|
#include "bswap.h"
|
||||||
|
@ -29,7 +28,8 @@
|
||||||
#define PCIE500_CFGADDR 0x0
|
#define PCIE500_CFGADDR 0x0
|
||||||
#define PCIE500_CFGDATA 0x4
|
#define PCIE500_CFGDATA 0x4
|
||||||
#define PCIE500_REG_BASE 0xC00
|
#define PCIE500_REG_BASE 0xC00
|
||||||
#define PCIE500_REG_SIZE (0x1000 - PCIE500_REG_BASE)
|
#define PCIE500_ALL_SIZE 0x1000
|
||||||
|
#define PCIE500_REG_SIZE (PCIE500_ALL_SIZE - PCIE500_REG_BASE)
|
||||||
|
|
||||||
#define PPCE500_PCI_CONFIG_ADDR 0x0
|
#define PPCE500_PCI_CONFIG_ADDR 0x0
|
||||||
#define PPCE500_PCI_CONFIG_DATA 0x4
|
#define PPCE500_PCI_CONFIG_DATA 0x4
|
||||||
|
@ -73,11 +73,15 @@ struct pci_inbound {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PPCE500PCIState {
|
struct PPCE500PCIState {
|
||||||
|
PCIHostState pci_state;
|
||||||
struct pci_outbound pob[PPCE500_PCI_NR_POBS];
|
struct pci_outbound pob[PPCE500_PCI_NR_POBS];
|
||||||
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
|
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
|
||||||
uint32_t gasket_time;
|
uint32_t gasket_time;
|
||||||
PCIHostState pci_state;
|
qemu_irq irq[4];
|
||||||
PCIDevice *pci_dev;
|
/* mmio maps */
|
||||||
|
int cfgaddr;
|
||||||
|
int cfgdata;
|
||||||
|
int reg;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct PPCE500PCIState PPCE500PCIState;
|
typedef struct PPCE500PCIState PPCE500PCIState;
|
||||||
|
@ -250,7 +254,6 @@ static const VMStateDescription vmstate_ppce500_pci = {
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.minimum_version_id_old = 1,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPCE500PCIState),
|
|
||||||
VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
|
VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
|
||||||
vmstate_pci_outbound, struct pci_outbound),
|
vmstate_pci_outbound, struct pci_outbound),
|
||||||
VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
|
VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
|
||||||
|
@ -260,60 +263,73 @@ static const VMStateDescription vmstate_ppce500_pci = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
|
static void e500_pci_map(SysBusDevice *dev, target_phys_addr_t base)
|
||||||
{
|
{
|
||||||
PPCE500PCIState *controller;
|
PCIHostState *h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
|
||||||
PCIDevice *d;
|
PPCE500PCIState *s = DO_UPCAST(PPCE500PCIState, pci_state, h);
|
||||||
int index;
|
|
||||||
static int ppce500_pci_id;
|
|
||||||
|
|
||||||
controller = qemu_mallocz(sizeof(PPCE500PCIState));
|
cpu_register_physical_memory(base + PCIE500_CFGADDR, 4, s->cfgaddr);
|
||||||
|
cpu_register_physical_memory(base + PCIE500_CFGDATA, 4, s->cfgdata);
|
||||||
controller->pci_state.bus = pci_register_bus(NULL, "pci",
|
cpu_register_physical_memory(base + PCIE500_REG_BASE, PCIE500_REG_SIZE,
|
||||||
mpc85xx_pci_set_irq,
|
s->reg);
|
||||||
mpc85xx_pci_map_irq,
|
|
||||||
pci_irqs, PCI_DEVFN(0x11, 0),
|
|
||||||
4);
|
|
||||||
d = pci_register_device(controller->pci_state.bus,
|
|
||||||
"host bridge", sizeof(PCIDevice),
|
|
||||||
0, NULL, NULL);
|
|
||||||
|
|
||||||
pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_FREESCALE);
|
|
||||||
pci_config_set_device_id(d->config, PCI_DEVICE_ID_MPC8533E);
|
|
||||||
pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_POWERPC);
|
|
||||||
|
|
||||||
controller->pci_dev = d;
|
|
||||||
|
|
||||||
/* CFGADDR */
|
|
||||||
index = pci_host_conf_register_mmio(&controller->pci_state,
|
|
||||||
DEVICE_BIG_ENDIAN);
|
|
||||||
if (index < 0)
|
|
||||||
goto free;
|
|
||||||
cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index);
|
|
||||||
|
|
||||||
/* CFGDATA */
|
|
||||||
index = pci_host_data_register_mmio(&controller->pci_state,
|
|
||||||
DEVICE_BIG_ENDIAN);
|
|
||||||
if (index < 0)
|
|
||||||
goto free;
|
|
||||||
cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index);
|
|
||||||
|
|
||||||
index = cpu_register_io_memory(e500_pci_reg_read,
|
|
||||||
e500_pci_reg_write, controller,
|
|
||||||
DEVICE_NATIVE_ENDIAN);
|
|
||||||
if (index < 0)
|
|
||||||
goto free;
|
|
||||||
cpu_register_physical_memory(registers + PCIE500_REG_BASE,
|
|
||||||
PCIE500_REG_SIZE, index);
|
|
||||||
|
|
||||||
/* XXX load/save code not tested. */
|
|
||||||
vmstate_register(&d->qdev, ppce500_pci_id++, &vmstate_ppce500_pci,
|
|
||||||
controller);
|
|
||||||
|
|
||||||
return controller->pci_state.bus;
|
|
||||||
|
|
||||||
free:
|
|
||||||
printf("%s error\n", __func__);
|
|
||||||
qemu_free(controller);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int e500_pcihost_initfn(SysBusDevice *dev)
|
||||||
|
{
|
||||||
|
PCIHostState *h;
|
||||||
|
PPCE500PCIState *s;
|
||||||
|
PCIBus *b;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
|
||||||
|
s = DO_UPCAST(PPCE500PCIState, pci_state, h);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
|
||||||
|
sysbus_init_irq(dev, &s->irq[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq,
|
||||||
|
mpc85xx_pci_map_irq, s->irq, PCI_DEVFN(0x11, 0), 4);
|
||||||
|
s->pci_state.bus = b;
|
||||||
|
|
||||||
|
pci_create_simple(b, 0, "e500-host-bridge");
|
||||||
|
|
||||||
|
s->cfgaddr = pci_host_conf_register_mmio(&s->pci_state, DEVICE_BIG_ENDIAN);
|
||||||
|
s->cfgdata = pci_host_data_register_mmio(&s->pci_state,
|
||||||
|
DEVICE_LITTLE_ENDIAN);
|
||||||
|
s->reg = cpu_register_io_memory(e500_pci_reg_read, e500_pci_reg_write, s,
|
||||||
|
DEVICE_BIG_ENDIAN);
|
||||||
|
sysbus_init_mmio_cb(dev, PCIE500_ALL_SIZE, e500_pci_map);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int e500_host_bridge_initfn(PCIDevice *dev)
|
||||||
|
{
|
||||||
|
pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_FREESCALE);
|
||||||
|
pci_config_set_device_id(dev->config, PCI_DEVICE_ID_MPC8533E);
|
||||||
|
pci_config_set_class(dev->config, PCI_CLASS_PROCESSOR_POWERPC);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PCIDeviceInfo e500_host_bridge_info = {
|
||||||
|
.qdev.name = "e500-host-bridge",
|
||||||
|
.qdev.desc = "Host bridge",
|
||||||
|
.qdev.size = sizeof(PCIDevice),
|
||||||
|
.init = e500_host_bridge_initfn,
|
||||||
|
};
|
||||||
|
|
||||||
|
static SysBusDeviceInfo e500_pcihost_info = {
|
||||||
|
.init = e500_pcihost_initfn,
|
||||||
|
.qdev.name = "e500-pcihost",
|
||||||
|
.qdev.size = sizeof(PPCE500PCIState),
|
||||||
|
.qdev.vmsd = &vmstate_ppce500_pci,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void e500_pci_register(void)
|
||||||
|
{
|
||||||
|
sysbus_register_withprop(&e500_pcihost_info);
|
||||||
|
pci_qdev_register(&e500_host_bridge_info);
|
||||||
|
}
|
||||||
|
device_init(e500_pci_register);
|
||||||
|
|
Loading…
Reference in New Issue