aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorFathi Boudra <fathi.boudra@linaro.org>2012-12-25 16:58:44 +0200
committerFathi Boudra <fathi.boudra@linaro.org>2012-12-25 16:58:44 +0200
commitdd55a01d2af35f5e9dabb2b745770afd008c9e24 (patch)
tree2bcab272d5cd94aab77f89220f1b8a3bff3109ac /hw
parent07d16a97127c9f56263ed5d8c697ff98a748e480 (diff)
Imported Upstream version 1.2.0-2012.09upstream/1.2.0-2012.09
Diffstat (limited to 'hw')
-rw-r--r--hw/Makefile.objs30
-rw-r--r--hw/acpi.c2
-rw-r--r--hw/acpi_piix4.c6
-rw-r--r--hw/alpha_pci.c1
-rw-r--r--hw/alpha_typhoon.c26
-rw-r--r--hw/apic_common.c4
-rw-r--r--hw/arm/Makefile.objs15
-rw-r--r--hw/arm_gic.c1
-rw-r--r--hw/armv7m.c5
-rw-r--r--hw/armv7m_nvic.c21
-rw-r--r--hw/boards.h3
-rw-r--r--hw/bonito.c152
-rw-r--r--hw/cirrus_vga.c2
-rw-r--r--hw/dec_pci.c31
-rw-r--r--hw/dec_pci.h2
-rw-r--r--hw/esp.c16
-rw-r--r--hw/framebuffer.c2
-rw-r--r--hw/grackle_pci.c65
-rw-r--r--hw/gt64xxx.c67
-rw-r--r--hw/i82378.c1
-rw-r--r--hw/ide/ahci.c44
-rw-r--r--hw/ide/internal.h1
-rw-r--r--hw/ivshmem.c22
-rw-r--r--hw/kvm/i8254.c52
-rw-r--r--hw/megasas.c9
-rw-r--r--hw/mips_malta.c1
-rw-r--r--hw/msix.c21
-rw-r--r--hw/null-machine.c40
-rw-r--r--hw/openpic.c17
-rw-r--r--hw/pc.c32
-rw-r--r--hw/pc.h4
-rw-r--r--hw/pc_piix.c12
-rw-r--r--hw/pci_host.c12
-rw-r--r--hw/pci_host.h5
-rw-r--r--hw/petalogix_ml605_mmu.c24
-rw-r--r--hw/piix_pci.c22
-rw-r--r--hw/ppc/Makefile.objs4
-rw-r--r--hw/ppc/e500.c (renamed from hw/ppce500_mpc8544ds.c)141
-rw-r--r--hw/ppc/e500.h21
-rw-r--r--hw/ppc/e500plat.c60
-rw-r--r--hw/ppc/mpc8544ds.c61
-rw-r--r--hw/ppc440_bamboo.c3
-rw-r--r--hw/ppc4xx.h2
-rw-r--r--hw/ppc4xx_pci.c27
-rw-r--r--hw/ppc_mac.h1
-rw-r--r--hw/ppc_newworld.c2
-rw-r--r--hw/ppc_oldworld.c2
-rw-r--r--hw/ppc_prep.c5
-rw-r--r--hw/ppce500_pci.c24
-rw-r--r--hw/prep_pci.c33
-rw-r--r--hw/puv3.c131
-rw-r--r--hw/puv3.h49
-rw-r--r--hw/puv3_dma.c109
-rw-r--r--hw/puv3_gpio.c141
-rw-r--r--hw/puv3_intc.c135
-rw-r--r--hw/puv3_ost.c151
-rw-r--r--hw/puv3_pm.c149
-rw-r--r--hw/qdev-monitor.c4
-rw-r--r--hw/qdev.c2
-rw-r--r--hw/scsi-bus.c2
-rw-r--r--hw/scsi-disk.c113
-rw-r--r--hw/scsi-generic.c3
-rw-r--r--hw/sd.c74
-rw-r--r--hw/sd.h8
-rw-r--r--hw/shpc.c1
-rw-r--r--hw/spapr.c112
-rw-r--r--hw/spapr.h17
-rw-r--r--hw/spapr_iommu.c58
-rw-r--r--hw/spapr_llan.c2
-rw-r--r--hw/spapr_pci.c392
-rw-r--r--hw/spapr_pci.h41
-rw-r--r--hw/spapr_vio.c14
-rw-r--r--hw/spapr_vio.h8
-rw-r--r--hw/spapr_vty.c2
-rw-r--r--hw/ssd0323.c4
-rw-r--r--hw/stream.c23
-rw-r--r--hw/stream.h31
-rw-r--r--hw/sun4u.c1
-rw-r--r--hw/unicore32/Makefile.objs6
-rw-r--r--hw/unin_pci.c185
-rw-r--r--hw/usb.h4
-rw-r--r--hw/usb/core.c39
-rw-r--r--hw/usb/dev-uas.c5
-rw-r--r--hw/usb/hcd-ehci.c151
-rw-r--r--hw/usb/hcd-musb.c3
-rw-r--r--hw/usb/hcd-ohci.c4
-rw-r--r--hw/usb/hcd-uhci.c20
-rw-r--r--hw/usb/hcd-xhci.c2
-rw-r--r--hw/usb/host-linux.c1
-rw-r--r--hw/versatilepb.c2
-rw-r--r--hw/vga-pci.c2
-rw-r--r--hw/vga-pci.h12
-rw-r--r--hw/virtio-blk.c30
-rw-r--r--hw/virtio-blk.h8
-rw-r--r--hw/virtio-pci.c3
-rw-r--r--hw/virtio-scsi.c17
-rw-r--r--hw/virtio-scsi.h9
-rw-r--r--hw/xen_platform.c3
-rw-r--r--hw/xics.c12
-rw-r--r--hw/xics.h5
-rw-r--r--hw/xilinx.h22
-rw-r--r--hw/xilinx_axidma.c74
-rw-r--r--hw/xilinx_axidma.h39
-rw-r--r--hw/xilinx_axienet.c32
104 files changed, 2761 insertions, 862 deletions
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 5c6ef2f..f277df2 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -65,6 +65,34 @@ hw-obj-$(CONFIG_XILINX) += xilinx_timer.o
hw-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
+hw-obj-$(CONFIG_XILINX_AXI) += stream.o
+
+# PKUnity SoC devices
+hw-obj-$(CONFIG_PUV3) += puv3_intc.o
+hw-obj-$(CONFIG_PUV3) += puv3_ost.o
+hw-obj-$(CONFIG_PUV3) += puv3_gpio.o
+hw-obj-$(CONFIG_PUV3) += puv3_pm.o
+hw-obj-$(CONFIG_PUV3) += puv3_dma.o
+
+# ARM devices
+hw-obj-$(CONFIG_ARM_TIMER) += arm_timer.o
+hw-obj-$(CONFIG_PL011) += pl011.o
+hw-obj-$(CONFIG_PL022) += pl022.o
+hw-obj-$(CONFIG_PL031) += pl031.o
+hw-obj-$(CONFIG_PL041) += pl041.o lm4549.o
+hw-obj-$(CONFIG_PL050) += pl050.o
+hw-obj-$(CONFIG_PL061) += pl061.o
+hw-obj-$(CONFIG_PL080) += pl080.o
+hw-obj-$(CONFIG_PL110) += pl110.o
+hw-obj-$(CONFIG_PL181) += pl181.o
+hw-obj-$(CONFIG_PL190) += pl190.o
+hw-obj-$(CONFIG_PL310) += arm_l2x0.o
+hw-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o
+hw-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
+hw-obj-$(CONFIG_CADENCE) += cadence_uart.o
+hw-obj-$(CONFIG_CADENCE) += cadence_ttc.o
+hw-obj-$(CONFIG_CADENCE) += cadence_gem.o
+hw-obj-$(CONFIG_XGMAC) += xgmac.o
# PCI watchdog devices
hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
@@ -106,6 +134,8 @@ hw-obj-$(CONFIG_DP8393X) += dp8393x.o
hw-obj-$(CONFIG_DS1225Y) += ds1225y.o
hw-obj-$(CONFIG_MIPSNET) += mipsnet.o
+hw-obj-y += null-machine.o
+
# Sound
sound-obj-y =
sound-obj-$(CONFIG_SB16) += sb16.o
diff --git a/hw/acpi.c b/hw/acpi.c
index effc7ec..f7950be 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -22,6 +22,7 @@
#include "hw.h"
#include "pc.h"
#include "acpi.h"
+#include "monitor.h"
struct acpi_table_header {
uint16_t _length; /* our length, not actual part of the hdr */
@@ -386,6 +387,7 @@ void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4)
break;
default:
if (sus_typ == s4) { /* S4 request */
+ monitor_protocol_event(QEVENT_SUSPEND_DISK, NULL);
qemu_system_shutdown_request();
}
break;
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 0aace60..c56220b 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -305,7 +305,6 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
if (pc->no_hotplug) {
slot_free = false;
} else {
- object_unparent(OBJECT(dev));
qdev_free(qdev);
}
}
@@ -353,6 +352,9 @@ static void piix4_reset(void *opaque)
pci_conf[0x5a] = 0;
pci_conf[0x5b] = 0;
+ pci_conf[0x40] = 0x01; /* PM io base read only bit */
+ pci_conf[0x80] = 0;
+
if (s->kvm_enabled) {
/* Mark SMM as already inited (until KVM supports SMM). */
pci_conf[0x5B] = 0x02;
@@ -392,8 +394,6 @@ static int piix4_pm_initfn(PCIDevice *dev)
pci_conf[0x09] = 0x00;
pci_conf[0x3d] = 0x01; // interrupt pin 1
- pci_conf[0x40] = 0x01; /* PM io base read only bit */
-
/* APM */
apm_init(&s->apm, apm_ctrl_changed, s);
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
index 6735577..ea546f8 100644
--- a/hw/alpha_pci.c
+++ b/hw/alpha_pci.c
@@ -11,6 +11,7 @@
#include "qemu-log.h"
#include "sysemu.h"
#include "vmware_vga.h"
+#include "vga-pci.h"
/* PCI IO reads/writes, to byte-word addressable memory. */
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 872e112..b7cf4e2 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -15,6 +15,8 @@
#include "exec-memory.h"
+#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
+
typedef struct TyphoonCchip {
MemoryRegion region;
uint64_t misc;
@@ -40,8 +42,12 @@ typedef struct TyphoonPchip {
TyphoonWindow win[4];
} TyphoonPchip;
+#define TYPHOON_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE)
+
typedef struct TyphoonState {
- PCIHostState host;
+ PCIHostState parent_obj;
+
TyphoonCchip cchip;
TyphoonPchip pchip;
MemoryRegion dchip_region;
@@ -700,16 +706,16 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
MemoryRegion *addr_space = get_system_memory();
MemoryRegion *addr_space_io = get_system_io();
DeviceState *dev;
- PCIHostState *p;
TyphoonState *s;
+ PCIHostState *phb;
PCIBus *b;
int i;
- dev = qdev_create(NULL, "typhoon-pcihost");
+ dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
- p = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
- s = container_of(p, TyphoonState, host);
+ s = TYPHOON_PCI_HOST_BRIDGE(dev);
+ phb = PCI_HOST_BRIDGE(dev);
/* Remember the CPUs so that we can deliver interrupts to them. */
for (i = 0; i < 4; i++) {
@@ -763,10 +769,10 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
memory_region_add_subregion(addr_space, 0x801fc000000ULL,
&s->pchip.reg_io);
- b = pci_register_bus(&s->host.busdev.qdev, "pci",
+ b = pci_register_bus(dev, "pci",
typhoon_set_irq, sys_map_irq, s,
&s->pchip.reg_mem, addr_space_io, 0, 64);
- s->host.bus = b;
+ phb->bus = b;
/* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */
memory_region_init_io(&s->pchip.reg_iack, &alpha_pci_iack_ops, b,
@@ -817,9 +823,9 @@ static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo typhoon_pcihost_info = {
- .name = "typhoon-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo typhoon_pcihost_info = {
+ .name = TYPE_TYPHOON_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(TyphoonState),
.class_init = typhoon_pcihost_class_init,
};
diff --git a/hw/apic_common.c b/hw/apic_common.c
index 58e63b0..371f95d 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -299,7 +299,9 @@ static int apic_init_common(SysBusDevice *dev)
sysbus_init_mmio(dev, &s->io_memory);
- if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK) {
+ /* Note: We need at least 1M to map the VAPIC option ROM */
+ if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
+ ram_size >= 1024 * 1024) {
vapic = sysbus_create_simple("kvmvapic", -1, NULL);
}
s->vapic = vapic;
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 01ab3aa..87ca004 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -1,10 +1,5 @@
-obj-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
-obj-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
-obj-y += versatile_pci.o
-obj-y += versatile_i2c.o
-obj-y += cadence_uart.o
-obj-y += cadence_ttc.o
-obj-y += cadence_gem.o
+obj-y = integratorcp.o versatilepb.o arm_pic.o
+obj-y += arm_boot.o
obj-y += xilinx_zynq.o zynq_slcr.o
obj-y += arm_gic.o arm_gic_common.o
obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
@@ -12,12 +7,9 @@ obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
obj-y += exynos4210_rtc.o exynos4210_i2c.o
-obj-y += arm_l2x0.o
obj-y += arm_mptimer.o a15mpcore.o
-obj-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
+obj-y += armv7m.o armv7m_nvic.o stellaris.o stellaris_enet.o
obj-y += highbank.o
-obj-y += pl061.o
-obj-y += xgmac.o
obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
obj-y += gumstix.o
@@ -39,7 +31,6 @@ obj-y += strongarm.o
obj-y += collie.o
obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
obj-y += kzm.o
-obj-y += pl041.o lm4549.o
obj-$(CONFIG_FDT) += ../device_tree.o
obj-$(CONFIG_KVM) += kvm/arm_gic.o
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 186ac66..55871fa 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -703,6 +703,7 @@ static TypeInfo arm_gic_info = {
.parent = TYPE_ARM_GIC_COMMON,
.instance_size = sizeof(gic_state),
.class_init = arm_gic_class_init,
+ .class_size = sizeof(ARMGICClass),
};
static void arm_gic_register_types(void)
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 8cec78d..9f66667 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -227,6 +227,11 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
big_endian = 0;
#endif
+ if (!kernel_filename) {
+ fprintf(stderr, "Guest image must be specified (using -kernel)\n");
+ exit(1);
+ }
+
image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
NULL, big_endian, ELF_MACHINE, 1);
if (image_size < 0) {
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 4867c1d..6a0832e 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -467,7 +467,7 @@ static int armv7m_nvic_init(SysBusDevice *dev)
s->gic.num_cpu = 1;
/* Tell the common code we're an NVIC */
s->gic.revision = 0xffffffff;
- s->gic.num_irq = s->num_irq;
+ s->num_irq = s->gic.num_irq;
nc->parent_init(dev);
gic_init_irqs_and_distributor(&s->gic, s->num_irq);
/* The NVIC and system controller register area looks like this:
@@ -498,14 +498,21 @@ static int armv7m_nvic_init(SysBusDevice *dev)
return 0;
}
-static Property armv7m_nvic_properties[] = {
+static void armv7m_nvic_instance_init(Object *obj)
+{
+ /* We have a different default value for the num-irq property
+ * than our superclass. This function runs after qdev init
+ * has set the defaults from the Property array and before
+ * any user-specified property setting, so just modify the
+ * value in the gic_state struct.
+ */
+ gic_state *s = ARM_GIC_COMMON(obj);
/* The ARM v7m may have anything from 0 to 496 external interrupt
* IRQ lines. We default to 64. Other boards may differ and should
- * set this property appropriately.
+ * set the num-irq property appropriately.
*/
- DEFINE_PROP_UINT32("num-irq", nvic_state, num_irq, 64),
- DEFINE_PROP_END_OF_LIST(),
-};
+ s->num_irq = 64;
+}
static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
{
@@ -518,12 +525,12 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
sdc->init = armv7m_nvic_init;
dc->vmsd = &vmstate_nvic;
dc->reset = armv7m_nvic_reset;
- dc->props = armv7m_nvic_properties;
}
static TypeInfo armv7m_nvic_info = {
.name = TYPE_NVIC,
.parent = TYPE_ARM_GIC_COMMON,
+ .instance_init = armv7m_nvic_instance_init,
.instance_size = sizeof(nvic_state),
.class_init = armv7m_nvic_class_init,
.class_size = sizeof(NVICClass),
diff --git a/hw/boards.h b/hw/boards.h
index 59c01d0..a2e0a54 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -12,11 +12,14 @@ typedef void QEMUMachineInitFunc(ram_addr_t ram_size,
const char *initrd_filename,
const char *cpu_model);
+typedef void QEMUMachineResetFunc(void);
+
typedef struct QEMUMachine {
const char *name;
const char *alias;
const char *desc;
QEMUMachineInitFunc *init;
+ QEMUMachineResetFunc *reset;
int use_scsi;
int max_cpus;
unsigned int no_serial:1,
diff --git a/hw/bonito.c b/hw/bonito.c
index 77786f8..6084ac4 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -180,11 +180,14 @@
#define PCI_ADDR(busno,devno,funno,regno) \
((((busno)<<16)&0xff0000) + (((devno)<<11)&0xf800) + (((funno)<<8)&0x700) + (regno))
-typedef PCIHostState BonitoState;
+#define TYPE_BONITO_PCI_HOST_BRIDGE "Bonito-pcihost"
+
+typedef struct BonitoState BonitoState;
typedef struct PCIBonitoState
{
PCIDevice dev;
+
BonitoState *pcihost;
uint32_t regs[BONITO_REGS];
@@ -218,7 +221,16 @@ typedef struct PCIBonitoState
} PCIBonitoState;
-PCIBonitoState * bonito_state;
+#define BONITO_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(BonitoState, (obj), TYPE_BONITO_PCI_HOST_BRIDGE)
+
+struct BonitoState {
+ PCIHostState parent_obj;
+
+ qemu_irq *pic;
+
+ PCIBonitoState *pci_dev;
+};
static void bonito_writel(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned size)
@@ -314,9 +326,10 @@ static void bonito_pciconf_writel(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned size)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
- s->dev.config_write(&s->dev, addr, val, 4);
+ d->config_write(d, addr, val, 4);
}
static uint64_t bonito_pciconf_readl(void *opaque, target_phys_addr_t addr,
@@ -324,9 +337,10 @@ static uint64_t bonito_pciconf_readl(void *opaque, target_phys_addr_t addr,
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
DPRINTF("bonito_pciconf_readl "TARGET_FMT_plx"\n", addr);
- return s->dev.config_read(&s->dev, addr, 4);
+ return d->config_read(d, addr, 4);
}
/* north bridge PCI configure space. 0x1fe0 0000 - 0x1fe0 00ff */
@@ -402,6 +416,7 @@ static const MemoryRegionOps bonito_cop_ops = {
static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr)
{
PCIBonitoState *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t cfgaddr;
uint32_t idsel;
uint32_t devno;
@@ -423,13 +438,13 @@ static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr)
regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET;
if (idsel == 0) {
- fprintf(stderr, "error in bonito pci config address" TARGET_FMT_plx
+ fprintf(stderr, "error in bonito pci config address " TARGET_FMT_plx
",pcimap_cfg=%x\n", addr, s->regs[BONITO_PCIMAP_CFG]);
exit(1);
}
- pciaddr = PCI_ADDR(pci_bus_num(s->pcihost->bus), devno, funno, regno);
+ pciaddr = PCI_ADDR(pci_bus_num(phb->bus), devno, funno, regno);
DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n",
- cfgaddr, pciaddr, pci_bus_num(s->pcihost->bus), devno, funno, regno);
+ cfgaddr, pciaddr, pci_bus_num(phb->bus), devno, funno, regno);
return pciaddr;
}
@@ -438,6 +453,8 @@ static void bonito_spciconf_writeb(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
@@ -449,24 +466,26 @@ static void bonito_spciconf_writeb(void *opaque, target_phys_addr_t addr,
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
- pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val & 0xff, 1);
+ phb->config_reg = (pciaddr) | (1u << 31);
+ pci_data_write(phb->bus, phb->config_reg, val & 0xff, 1);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
}
static void bonito_spciconf_writew(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x\n", addr, val);
- assert((addr&0x1)==0);
+ assert((addr & 0x1) == 0);
pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -475,24 +494,26 @@ static void bonito_spciconf_writew(void *opaque, target_phys_addr_t addr,
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
- pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val, 2);
+ phb->config_reg = (pciaddr) | (1u << 31);
+ pci_data_write(phb->bus, phb->config_reg, val, 2);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
}
static void bonito_spciconf_writel(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
- assert((addr&0x3)==0);
+ assert((addr & 0x3) == 0);
pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -501,18 +522,20 @@ static void bonito_spciconf_writel(void *opaque, target_phys_addr_t addr,
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
- pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val, 4);
+ phb->config_reg = (pciaddr) | (1u << 31);
+ pci_data_write(phb->bus, phb->config_reg, val, 4);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
}
static uint32_t bonito_spciconf_readb(void *opaque, target_phys_addr_t addr)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
@@ -524,24 +547,26 @@ static uint32_t bonito_spciconf_readb(void *opaque, target_phys_addr_t addr)
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
+ phb->config_reg = (pciaddr) | (1u << 31);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
- return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 1);
+ return pci_data_read(phb->bus, phb->config_reg, 1);
}
static uint32_t bonito_spciconf_readw(void *opaque, target_phys_addr_t addr)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"\n", addr);
- assert((addr&0x1)==0);
+ assert((addr & 0x1) == 0);
pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -550,24 +575,26 @@ static uint32_t bonito_spciconf_readw(void *opaque, target_phys_addr_t addr)
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
+ phb->config_reg = (pciaddr) | (1u << 31);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
- return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 2);
+ return pci_data_read(phb->bus, phb->config_reg, 2);
}
static uint32_t bonito_spciconf_readl(void *opaque, target_phys_addr_t addr)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"\n", addr);
- assert((addr&0x3) == 0);
+ assert((addr & 0x3) == 0);
pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -576,14 +603,14 @@ static uint32_t bonito_spciconf_readl(void *opaque, target_phys_addr_t addr)
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
+ phb->config_reg = (pciaddr) | (1u << 31);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
- return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 4);
+ return pci_data_read(phb->bus, phb->config_reg, 4);
}
/* south bridge PCI configure space. 0x1fe8 0000 - 0x1fef ffff */
@@ -607,13 +634,15 @@ static const MemoryRegionOps bonito_spciconf_ops = {
static void pci_bonito_set_irq(void *opaque, int irq_num, int level)
{
- qemu_irq *pic = opaque;
+ BonitoState *s = opaque;
+ qemu_irq *pic = s->pic;
+ PCIBonitoState *bonito_state = s->pci_dev;
int internal_irq = irq_num - BONITO_IRQ_BASE;
- if (bonito_state->regs[BONITO_INTEDGE] & (1<<internal_irq)) {
+ if (bonito_state->regs[BONITO_INTEDGE] & (1 << internal_irq)) {
qemu_irq_pulse(*pic);
} else { /* level triggered */
- if (bonito_state->regs[BONITO_INTPOL] & (1<<internal_irq)) {
+ if (bonito_state->regs[BONITO_INTPOL] & (1 << internal_irq)) {
qemu_irq_raise(*pic);
} else {
qemu_irq_lower(*pic);
@@ -673,13 +702,21 @@ static const VMStateDescription vmstate_bonito = {
static int bonito_pcihost_initfn(SysBusDevice *dev)
{
+ PCIHostState *phb = PCI_HOST_BRIDGE(dev);
+
+ phb->bus = pci_register_bus(DEVICE(dev), "pci",
+ pci_bonito_set_irq, pci_bonito_map_irq, dev,
+ get_system_memory(), get_system_io(),
+ 0x28, 32);
+
return 0;
}
static int bonito_initfn(PCIDevice *dev)
{
PCIBonitoState *s = DO_UPCAST(PCIBonitoState, dev, dev);
- SysBusDevice *sysbus = &s->pcihost->busdev;
+ SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
/* Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */
pci_config_set_prog_interface(dev->config, 0x00);
@@ -691,15 +728,15 @@ static int bonito_initfn(PCIDevice *dev)
sysbus_mmio_map(sysbus, 0, BONITO_INTERNAL_REG_BASE);
/* set the north bridge pci configure mapping */
- memory_region_init_io(&s->pcihost->conf_mem, &bonito_pciconf_ops, s,
+ memory_region_init_io(&phb->conf_mem, &bonito_pciconf_ops, s,
"north-bridge-pci-config", BONITO_PCICONFIG_SIZE);
- sysbus_init_mmio(sysbus, &s->pcihost->conf_mem);
+ sysbus_init_mmio(sysbus, &phb->conf_mem);
sysbus_mmio_map(sysbus, 1, BONITO_PCICONFIG_BASE);
/* set the south bridge pci configure mapping */
- memory_region_init_io(&s->pcihost->data_mem, &bonito_spciconf_ops, s,
+ memory_region_init_io(&phb->data_mem, &bonito_spciconf_ops, s,
"south-bridge-pci-config", BONITO_SPCICONFIG_SIZE);
- sysbus_init_mmio(sysbus, &s->pcihost->data_mem);
+ sysbus_init_mmio(sysbus, &phb->data_mem);
sysbus_mmio_map(sysbus, 2, BONITO_SPCICONFIG_BASE);
memory_region_init_io(&s->iomem_ldma, &bonito_ldma_ops, s,
@@ -742,28 +779,25 @@ static int bonito_initfn(PCIDevice *dev)
PCIBus *bonito_init(qemu_irq *pic)
{
DeviceState *dev;
- PCIBus *b;
BonitoState *pcihost;
+ PCIHostState *phb;
PCIBonitoState *s;
PCIDevice *d;
- dev = qdev_create(NULL, "Bonito-pcihost");
- pcihost = FROM_SYSBUS(BonitoState, sysbus_from_qdev(dev));
- b = pci_register_bus(&pcihost->busdev.qdev, "pci", pci_bonito_set_irq,
- pci_bonito_map_irq, pic, get_system_memory(),
- get_system_io(),
- 0x28, 32);
- pcihost->bus = b;
+ dev = qdev_create(NULL, TYPE_BONITO_PCI_HOST_BRIDGE);
+ phb = PCI_HOST_BRIDGE(dev);
+ pcihost = BONITO_PCI_HOST_BRIDGE(dev);
+ pcihost->pic = pic;
qdev_init_nofail(dev);
/* set the pcihost pointer before bonito_initfn is called */
- d = pci_create(b, PCI_DEVFN(0, 0), "Bonito");
+ d = pci_create(phb->bus, PCI_DEVFN(0, 0), "Bonito");
s = DO_UPCAST(PCIBonitoState, dev, d);
s->pcihost = pcihost;
- bonito_state = s;
- qdev_init_nofail(&d->qdev);
+ pcihost->pci_dev = s;
+ qdev_init_nofail(DEVICE(d));
- return b;
+ return phb->bus;
}
static void bonito_class_init(ObjectClass *klass, void *data)
@@ -781,7 +815,7 @@ static void bonito_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_bonito;
}
-static TypeInfo bonito_info = {
+static const TypeInfo bonito_info = {
.name = "Bonito",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIBonitoState),
@@ -797,9 +831,9 @@ static void bonito_pcihost_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo bonito_pcihost_info = {
- .name = "Bonito-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo bonito_pcihost_info = {
+ .name = TYPE_BONITO_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(BonitoState),
.class_init = bonito_pcihost_class_init,
};
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 623dd68..e8dcc6b 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -27,8 +27,8 @@
* available at http://home.worldonline.dk/~finth/
*/
#include "hw.h"
-#include "pc.h"
#include "pci.h"
+#include "vga-pci.h"
#include "console.h"
#include "vga_int.h"
#include "loader.h"
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index 37337bf..c30ade3 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -40,9 +40,10 @@
#define DEC_DPRINTF(fmt, ...)
#endif
+#define DEC_21154(obj) OBJECT_CHECK(DECState, (obj), TYPE_DEC_21154)
+
typedef struct DECState {
- SysBusDevice busdev;
- PCIHostState host_state;
+ PCIHostState parent_obj;
} DECState;
static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
@@ -66,7 +67,7 @@ static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_pci_device;
}
-static TypeInfo dec_21154_pci_bridge_info = {
+static const TypeInfo dec_21154_pci_bridge_info = {
.name = "dec-21154-p2p-bridge",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIBridge),
@@ -88,16 +89,16 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
static int pci_dec_21154_device_init(SysBusDevice *dev)
{
- DECState *s;
+ PCIHostState *phb;
- s = FROM_SYSBUS(DECState, dev);
+ phb = PCI_HOST_BRIDGE(dev);
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
- &s->host_state, "pci-data-idx", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ memory_region_init_io(&phb->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&phb->data_mem, &pci_host_data_le_ops,
+ dev, "pci-data-idx", 0x1000);
+ sysbus_init_mmio(dev, &phb->conf_mem);
+ sysbus_init_mmio(dev, &phb->data_mem);
return 0;
}
@@ -119,7 +120,7 @@ static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data)
k->is_bridge = 1;
}
-static TypeInfo dec_21154_pci_host_info = {
+static const TypeInfo dec_21154_pci_host_info = {
.name = "dec-21154",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -133,9 +134,9 @@ static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
sdc->init = pci_dec_21154_device_init;
}
-static TypeInfo pci_dec_21154_device_info = {
- .name = "dec-21154-sysbus",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo pci_dec_21154_device_info = {
+ .name = TYPE_DEC_21154,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(DECState),
.class_init = pci_dec_21154_device_class_init,
};
diff --git a/hw/dec_pci.h b/hw/dec_pci.h
index 79264ba..17dc0c2 100644
--- a/hw/dec_pci.h
+++ b/hw/dec_pci.h
@@ -3,6 +3,8 @@
#include "qemu-common.h"
+#define TYPE_DEC_21154 "dec-21154-sysbus"
+
PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn);
#endif
diff --git a/hw/esp.c b/hw/esp.c
index 52c46e6..84a4e74 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -87,7 +87,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
target = s->wregs[ESP_WBUSID] & BUSID_DID;
if (s->dma) {
- dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
+ dmalen = s->rregs[ESP_TCLO];
+ dmalen |= s->rregs[ESP_TCMID] << 8;
+ dmalen |= s->rregs[ESP_TCHI] << 16;
s->dma_memory_read(s->dma_opaque, buf, dmalen);
} else {
dmalen = s->ti_size;
@@ -226,6 +228,7 @@ static void esp_dma_done(ESPState *s)
s->rregs[ESP_RFLAGS] = 0;
s->rregs[ESP_TCLO] = 0;
s->rregs[ESP_TCMID] = 0;
+ s->rregs[ESP_TCHI] = 0;
esp_raise_irq(s);
}
@@ -328,7 +331,9 @@ static void handle_ti(ESPState *s)
return;
}
- dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
+ dmalen = s->rregs[ESP_TCLO];
+ dmalen |= s->rregs[ESP_TCMID] << 8;
+ dmalen |= s->rregs[ESP_TCHI] << 16;
if (dmalen==0) {
dmalen=0x10000;
}
@@ -429,6 +434,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
switch (saddr) {
case ESP_TCLO:
case ESP_TCMID:
+ case ESP_TCHI:
s->rregs[ESP_RSTAT] &= ~STAT_TC;
break;
case ESP_FIFO:
@@ -448,6 +454,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
/* Reload DMA counter. */
s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
+ s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI];
} else {
s->dma = 0;
}
@@ -530,13 +537,12 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
case ESP_WBUSID ... ESP_WSYNO:
break;
case ESP_CFG1:
+ case ESP_CFG2: case ESP_CFG3:
+ case ESP_RES3: case ESP_RES4:
s->rregs[saddr] = val;
break;
case ESP_WCCF ... ESP_WTEST:
break;
- case ESP_CFG2 ... ESP_RES4:
- s->rregs[saddr] = val;
- break;
default:
trace_esp_error_invalid_write(val, saddr);
return;
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
index f4747cd..85a00a5 100644
--- a/hw/framebuffer.c
+++ b/hw/framebuffer.c
@@ -28,7 +28,7 @@ void framebuffer_update_display(
MemoryRegion *address_space,
target_phys_addr_t base,
int cols, /* Width in pixels. */
- int rows, /* Leight in pixels. */
+ int rows, /* Height in pixels. */
int src_width, /* Length of source line, in bytes. */
int dest_row_pitch, /* Bytes between adjacent horizontal output pixels. */
int dest_col_pitch, /* Bytes between adjacent vertical output pixels. */
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 81ff3a3..67da307 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -23,10 +23,9 @@
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "pci_host.h"
#include "ppc_mac.h"
#include "pci.h"
-#include "pci_host.h"
/* debug Grackle */
//#define DEBUG_GRACKLE
@@ -38,9 +37,12 @@
#define GRACKLE_DPRINTF(fmt, ...)
#endif
+#define GRACKLE_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(GrackleState, (obj), TYPE_GRACKLE_PCI_HOST_BRIDGE)
+
typedef struct GrackleState {
- SysBusDevice busdev;
- PCIHostState host_state;
+ PCIHostState parent_obj;
+
MemoryRegion pci_mmio;
MemoryRegion pci_hole;
} GrackleState;
@@ -59,22 +61,20 @@ static void pci_grackle_set_irq(void *opaque, int irq_num, int level)
qemu_set_irq(pic[irq_num + 0x15], level);
}
-static void pci_grackle_reset(void *opaque)
-{
-}
-
PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io)
{
DeviceState *dev;
SysBusDevice *s;
+ PCIHostState *phb;
GrackleState *d;
- dev = qdev_create(NULL, "grackle-pcihost");
+ dev = qdev_create(NULL, TYPE_GRACKLE_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
- d = FROM_SYSBUS(GrackleState, s);
+ s = SYS_BUS_DEVICE(dev);
+ phb = PCI_HOST_BRIDGE(dev);
+ d = GRACKLE_PCI_HOST_BRIDGE(dev);
memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
@@ -82,36 +82,35 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole);
- d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
- pci_grackle_set_irq,
- pci_grackle_map_irq,
- pic,
- &d->pci_mmio,
- address_space_io,
- 0, 4);
+ phb->bus = pci_register_bus(dev, "pci",
+ pci_grackle_set_irq,
+ pci_grackle_map_irq,
+ pic,
+ &d->pci_mmio,
+ address_space_io,
+ 0, 4);
- pci_create_simple(d->host_state.bus, 0, "grackle");
+ pci_create_simple(phb->bus, 0, "grackle");
sysbus_mmio_map(s, 0, base);
sysbus_mmio_map(s, 1, base + 0x00200000);
- return d->host_state.bus;
+ return phb->bus;
}
static int pci_grackle_init_device(SysBusDevice *dev)
{
- GrackleState *s;
+ PCIHostState *phb;
- s = FROM_SYSBUS(GrackleState, dev);
+ phb = PCI_HOST_BRIDGE(dev);
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
- &s->host_state, "pci-data-idx", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ memory_region_init_io(&phb->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&phb->data_mem, &pci_host_data_le_ops,
+ dev, "pci-data-idx", 0x1000);
+ sysbus_init_mmio(dev, &phb->conf_mem);
+ sysbus_init_mmio(dev, &phb->data_mem);
- qemu_register_reset(pci_grackle_reset, &s->host_state);
return 0;
}
@@ -134,7 +133,7 @@ static void grackle_pci_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo grackle_pci_info = {
+static const TypeInfo grackle_pci_info = {
.name = "grackle",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -150,9 +149,9 @@ static void pci_grackle_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo grackle_pci_host_info = {
- .name = "grackle-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo grackle_pci_host_info = {
+ .name = TYPE_GRACKLE_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(GrackleState),
.class_init = pci_grackle_class_init,
};
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index a2d0e5a..e95e664 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -229,9 +229,14 @@
target_phys_addr_t regname ##_length; \
MemoryRegion regname ##_mem
+#define TYPE_GT64120_PCI_HOST_BRIDGE "gt64120"
+
+#define GT64120_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(GT64120State, (obj), TYPE_GT64120_PCI_HOST_BRIDGE)
+
typedef struct GT64120State {
- SysBusDevice busdev;
- PCIHostState pci;
+ PCIHostState parent_obj;
+
uint32_t regs[GT_REGS];
PCI_MAPPING_ENTRY(PCI0IO);
PCI_MAPPING_ENTRY(ISD);
@@ -310,6 +315,7 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned size)
{
GT64120State *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
uint32_t saddr;
if (!(s->regs[GT_CPU] & 0x00001000))
@@ -530,13 +536,15 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
/* not implemented */
break;
case GT_PCI0_CFGADDR:
- s->pci.config_reg = val & 0x80fffffc;
+ phb->config_reg = val & 0x80fffffc;
break;
case GT_PCI0_CFGDATA:
- if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800))
+ if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
val = bswap32(val);
- if (s->pci.config_reg & (1u << 31))
- pci_data_write(s->pci.bus, s->pci.config_reg, val, 4);
+ }
+ if (phb->config_reg & (1u << 31)) {
+ pci_data_write(phb->bus, phb->config_reg, val, 4);
+ }
break;
/* Interrupts */
@@ -589,6 +597,7 @@ static uint64_t gt64120_readl (void *opaque,
target_phys_addr_t addr, unsigned size)
{
GT64120State *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
uint32_t val;
uint32_t saddr;
@@ -770,15 +779,17 @@ static uint64_t gt64120_readl (void *opaque,
/* PCI Internal */
case GT_PCI0_CFGADDR:
- val = s->pci.config_reg;
+ val = phb->config_reg;
break;
case GT_PCI0_CFGDATA:
- if (!(s->pci.config_reg & (1 << 31)))
+ if (!(phb->config_reg & (1 << 31))) {
val = 0xffffffff;
- else
- val = pci_data_read(s->pci.bus, s->pci.config_reg, 4);
- if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800))
+ } else {
+ val = pci_data_read(phb->bus, phb->config_reg, 4);
+ }
+ if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
val = bswap32(val);
+ }
break;
case GT_PCI0_CMD:
@@ -1083,31 +1094,31 @@ static void gt64120_reset(void *opaque)
PCIBus *gt64120_register(qemu_irq *pic)
{
- SysBusDevice *s;
GT64120State *d;
+ PCIHostState *phb;
DeviceState *dev;
- dev = qdev_create(NULL, "gt64120");
+ dev = qdev_create(NULL, TYPE_GT64120_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
- d = FROM_SYSBUS(GT64120State, s);
- d->pci.bus = pci_register_bus(&d->busdev.qdev, "pci",
- gt64120_pci_set_irq, gt64120_pci_map_irq,
- pic,
- get_system_memory(),
- get_system_io(),
- PCI_DEVFN(18, 0), 4);
+ d = GT64120_PCI_HOST_BRIDGE(dev);
+ phb = PCI_HOST_BRIDGE(dev);
+ phb->bus = pci_register_bus(dev, "pci",
+ gt64120_pci_set_irq, gt64120_pci_map_irq,
+ pic,
+ get_system_memory(),
+ get_system_io(),
+ PCI_DEVFN(18, 0), 4);
memory_region_init_io(&d->ISD_mem, &isd_mem_ops, d, "isd-mem", 0x1000);
- pci_create_simple(d->pci.bus, PCI_DEVFN(0, 0), "gt64120_pci");
- return d->pci.bus;
+ pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci");
+ return phb->bus;
}
static int gt64120_init(SysBusDevice *dev)
{
GT64120State *s;
- s = FROM_SYSBUS(GT64120State, dev);
+ s = GT64120_PCI_HOST_BRIDGE(dev);
/* FIXME: This value is computed from registers during reset, but some
devices (e.g. VGA card) need to know it when they are registered.
@@ -1147,7 +1158,7 @@ static void gt64120_pci_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
-static TypeInfo gt64120_pci_info = {
+static const TypeInfo gt64120_pci_info = {
.name = "gt64120_pci",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -1161,9 +1172,9 @@ static void gt64120_class_init(ObjectClass *klass, void *data)
sdc->init = gt64120_init;
}
-static TypeInfo gt64120_info = {
- .name = "gt64120",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo gt64120_info = {
+ .name = TYPE_GT64120_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(GT64120State),
.class_init = gt64120_class_init,
};
diff --git a/hw/i82378.c b/hw/i82378.c
index 9b11d90..2123c14 100644
--- a/hw/i82378.c
+++ b/hw/i82378.c
@@ -225,7 +225,6 @@ static int pci_i82378_init(PCIDevice *dev)
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io);
memory_region_init_io(&s->mem, &i82378_mem_ops, s, "i82378-mem", 0x01000000);
- memory_region_set_coalescing(&s->mem);
pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
/* Make I/O address read only */
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index efea93f..5ea3cad 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -636,7 +636,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
}
}
-static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
+static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
{
AHCICmdHdr *cmd = ad->cur_cmd;
uint32_t opts = le32_to_cpu(cmd->opts);
@@ -647,6 +647,10 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
uint8_t *prdt;
int i;
int r = 0;
+ int sum = 0;
+ int off_idx = -1;
+ int off_pos = -1;
+ int tbl_entry_size;
if (!sglist_alloc_hint) {
DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
@@ -669,10 +673,31 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
/* Get entries in the PRDT, init a qemu sglist accordingly */
if (sglist_alloc_hint > 0) {
AHCI_SG *tbl = (AHCI_SG *)prdt;
-
- qemu_sglist_init(sglist, sglist_alloc_hint, ad->hba->dma);
+ sum = 0;
for (i = 0; i < sglist_alloc_hint; i++) {
/* flags_size is zero-based */
+ tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);
+ if (offset <= (sum + tbl_entry_size)) {
+ off_idx = i;
+ off_pos = offset - sum;
+ break;
+ }
+ sum += tbl_entry_size;
+ }
+ if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {
+ DPRINTF(ad->port_no, "%s: Incorrect offset! "
+ "off_idx: %d, off_pos: %d\n",
+ __func__, off_idx, off_pos);
+ r = -1;
+ goto out;
+ }
+
+ qemu_sglist_init(sglist, (sglist_alloc_hint - off_idx), ad->hba->dma);
+ qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),
+ le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);
+
+ for (i = off_idx + 1; i < sglist_alloc_hint; i++) {
+ /* flags_size is zero-based */
qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
le32_to_cpu(tbl[i].flags_size) + 1);
}
@@ -745,7 +770,7 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
s->dev[port].port.ifs[0].nb_sectors - 1);
- ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist);
+ ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist, 0);
ncq_tfs->tag = tag;
switch(ncq_fis->command) {
@@ -970,7 +995,7 @@ static int ahci_start_transfer(IDEDMA *dma)
goto out;
}
- if (!ahci_populate_sglist(ad, &s->sg)) {
+ if (!ahci_populate_sglist(ad, &s->sg, 0)) {
has_sglist = 1;
}
@@ -1015,6 +1040,7 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s,
DPRINTF(ad->port_no, "\n");
ad->dma_cb = dma_cb;
ad->dma_status |= BM_STATUS_DMAING;
+ s->io_buffer_offset = 0;
dma_cb(s, 0);
}
@@ -1023,7 +1049,7 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
IDEState *s = &ad->port.ifs[0];
- ahci_populate_sglist(ad, &s->sg);
+ ahci_populate_sglist(ad, &s->sg, 0);
s->io_buffer_size = s->sg.size;
DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
@@ -1037,7 +1063,7 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
uint8_t *p = s->io_buffer + s->io_buffer_index;
int l = s->io_buffer_size - s->io_buffer_index;
- if (ahci_populate_sglist(ad, &s->sg)) {
+ if (ahci_populate_sglist(ad, &s->sg, s->io_buffer_offset)) {
return 0;
}
@@ -1047,9 +1073,13 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
dma_buf_write(p, l, &s->sg);
}
+ /* free sglist that was created in ahci_populate_sglist() */
+ qemu_sglist_destroy(&s->sg);
+
/* update number of transferred bytes */
ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l);
s->io_buffer_index += l;
+ s->io_buffer_offset += l;
DPRINTF(ad->port_no, "len=%#x\n", l);
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 7170bd9..bf7d313 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -393,6 +393,7 @@ struct IDEState {
struct iovec iov;
QEMUIOVector qiov;
/* ATA DMA state */
+ int io_buffer_offset;
int io_buffer_size;
QEMUSGList sg;
/* PIO transfer handling */
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 0c58161..62fe53a 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -366,6 +366,10 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
{
int i, guest_curr_max;
+ if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+ return;
+ }
+
guest_curr_max = s->peers[posn].nb_eventfds;
memory_region_transaction_begin();
@@ -381,17 +385,6 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
s->peers[posn].nb_eventfds = 0;
}
-static void setup_ioeventfds(IVShmemState *s) {
-
- int i, j;
-
- for (i = 0; i <= s->max_peer; i++) {
- for (j = 0; j < s->peers[i].nb_eventfds; j++) {
- ivshmem_add_eventfd(s, i, j);
- }
- }
-}
-
/* this function increase the dynamic storage need to store data about other
* guests */
static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
@@ -677,7 +670,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
}
if (s->role_val == IVSHMEM_PEER) {
- error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, "ivshmem", "peer mode");
+ error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
+ "peer mode", "ivshmem");
migrate_add_blocker(s->migration_blocker);
}
@@ -691,10 +685,6 @@ static int pci_ivshmem_init(PCIDevice *dev)
memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
"ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
- if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
- setup_ioeventfds(s);
- }
-
/* region for registers*/
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
&s->ivshmem_mmio);
diff --git a/hw/kvm/i8254.c b/hw/kvm/i8254.c
index c5d3711..53d13e3 100644
--- a/hw/kvm/i8254.c
+++ b/hw/kvm/i8254.c
@@ -35,7 +35,8 @@
typedef struct KVMPITState {
PITCommonState pit;
LostTickPolicy lost_tick_policy;
- bool state_valid;
+ bool vm_stopped;
+ int64_t kernel_clock_offset;
} KVMPITState;
static int64_t abs64(int64_t v)
@@ -43,19 +44,11 @@ static int64_t abs64(int64_t v)
return v < 0 ? -v : v;
}
-static void kvm_pit_get(PITCommonState *pit)
+static void kvm_pit_update_clock_offset(KVMPITState *s)
{
- KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
- struct kvm_pit_state2 kpit;
- struct kvm_pit_channel_state *kchan;
- struct PITChannelState *sc;
int64_t offset, clock_offset;
struct timespec ts;
- int i, ret;
-
- if (s->state_valid) {
- return;
- }
+ int i;
/*
* Measure the delta between CLOCK_MONOTONIC, the base used for
@@ -72,6 +65,21 @@ static void kvm_pit_get(PITCommonState *pit)
clock_offset = offset;
}
}
+ s->kernel_clock_offset = clock_offset;
+}
+
+static void kvm_pit_get(PITCommonState *pit)
+{
+ KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
+ struct kvm_pit_state2 kpit;
+ struct kvm_pit_channel_state *kchan;
+ struct PITChannelState *sc;
+ int i, ret;
+
+ /* No need to re-read the state if VM is stopped. */
+ if (s->vm_stopped) {
+ return;
+ }
if (kvm_has_pit_state2()) {
ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
@@ -106,7 +114,7 @@ static void kvm_pit_get(PITCommonState *pit)
sc->mode = kchan->mode;
sc->bcd = kchan->bcd;
sc->gate = kchan->gate;
- sc->count_load_time = kchan->count_load_time + clock_offset;
+ sc->count_load_time = kchan->count_load_time + s->kernel_clock_offset;
}
sc = &pit->channels[0];
@@ -114,17 +122,23 @@ static void kvm_pit_get(PITCommonState *pit)
pit_get_next_transition_time(sc, sc->count_load_time);
}
-static void kvm_pit_put(PITCommonState *s)
+static void kvm_pit_put(PITCommonState *pit)
{
+ KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
struct kvm_pit_state2 kpit;
struct kvm_pit_channel_state *kchan;
struct PITChannelState *sc;
int i, ret;
- kpit.flags = s->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
+ /* The offset keeps changing as long as the VM is stopped. */
+ if (s->vm_stopped) {
+ kvm_pit_update_clock_offset(s);
+ }
+
+ kpit.flags = pit->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
for (i = 0; i < 3; i++) {
kchan = &kpit.channels[i];
- sc = &s->channels[i];
+ sc = &pit->channels[i];
kchan->count = sc->count;
kchan->latched_count = sc->latched_count;
kchan->count_latched = sc->count_latched;
@@ -137,7 +151,7 @@ static void kvm_pit_put(PITCommonState *s)
kchan->mode = sc->mode;
kchan->bcd = sc->bcd;
kchan->gate = sc->gate;
- kchan->count_load_time = sc->count_load_time;
+ kchan->count_load_time = sc->count_load_time - s->kernel_clock_offset;
}
ret = kvm_vm_ioctl(kvm_state,
@@ -211,10 +225,12 @@ static void kvm_pit_vm_state_change(void *opaque, int running,
KVMPITState *s = opaque;
if (running) {
- s->state_valid = false;
+ kvm_pit_update_clock_offset(s);
+ s->vm_stopped = false;
} else {
+ kvm_pit_update_clock_offset(s);
kvm_pit_get(&s->pit);
- s->state_valid = true;
+ s->vm_stopped = true;
}
}
diff --git a/hw/megasas.c b/hw/megasas.c
index c35a15d..c728aea 100644
--- a/hw/megasas.c
+++ b/hw/megasas.c
@@ -38,6 +38,7 @@
#define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */
#define MEGASAS_MAX_ARRAYS 128
+#define MEGASAS_HBA_SERIAL "QEMU123456"
#define NAA_LOCALLY_ASSIGNED_ID 0x3ULL
#define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400
@@ -93,6 +94,7 @@ typedef struct MegasasState {
int boot_event;
uint64_t sas_addr;
+ char *hba_serial;
uint64_t reply_queue_pa;
void *reply_queue;
@@ -698,8 +700,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
}
memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
- snprintf(info.serial_number, 32, "QEMU%08lx",
- (unsigned long)s & 0xFFFFFFFF);
+ snprintf(info.serial_number, 32, "%s", s->hba_serial);
snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION);
memcpy(info.image_component[0].name, "APP", 3);
memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9);
@@ -2132,6 +2133,9 @@ static int megasas_scsi_init(PCIDevice *dev)
s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
s->sas_addr |= PCI_FUNC(dev->devfn);
}
+ if (!s->hba_serial) {
+ s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
+ }
if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
} else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {
@@ -2166,6 +2170,7 @@ static Property megasas_properties[] = {
MEGASAS_DEFAULT_SGE),
DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
MEGASAS_DEFAULT_FRAMES),
+ DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
DEFINE_PROP_HEX64("sas_address", MegasasState, sas_addr, 0),
#ifdef USE_MSIX
DEFINE_PROP_BIT("use_msix", MegasasState, flags,
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 351c88e..ad23f26 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -48,6 +48,7 @@
#include "blockdev.h"
#include "exec-memory.h"
#include "sysbus.h" /* SysBusDevice */
+#include "vga-pci.h"
//#define DEBUG_BOARD_INIT
diff --git a/hw/msix.c b/hw/msix.c
index 800fc32..d812094 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -307,13 +307,9 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
return -EINVAL;
}
- if (asprintf(&name, "%s-msix", dev->name) == -1) {
- return -ENOMEM;
- }
-
+ name = g_strdup_printf("%s-msix", dev->name);
memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE);
-
- free(name);
+ g_free(name);
ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar,
@@ -340,6 +336,15 @@ static void msix_free_irq_entries(PCIDevice *dev)
}
}
+static void msix_clear_all_vectors(PCIDevice *dev)
+{
+ int vector;
+
+ for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
+ msix_clr_pending(dev, vector);
+ }
+}
+
/* Clean up resources for the device. */
void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar)
{
@@ -394,7 +399,7 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
return;
}
- msix_free_irq_entries(dev);
+ msix_clear_all_vectors(dev);
qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE);
qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8);
msix_update_function_masked(dev);
@@ -440,7 +445,7 @@ void msix_reset(PCIDevice *dev)
if (!msix_present(dev)) {
return;
}
- msix_free_irq_entries(dev);
+ msix_clear_all_vectors(dev);
dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE);
diff --git a/hw/null-machine.c b/hw/null-machine.c
new file mode 100644
index 0000000..69910d3
--- /dev/null
+++ b/hw/null-machine.c
@@ -0,0 +1,40 @@
+/*
+ * Empty machine
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static void machine_none_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+}
+
+static QEMUMachine machine_none = {
+ .name = "none",
+ .desc = "empty machine",
+ .init = machine_none_init,
+ .max_cpus = 0,
+};
+
+static void register_machines(void)
+{
+ qemu_register_machine(&machine_none);
+}
+
+machine_init(register_machines);
+
diff --git a/hw/openpic.c b/hw/openpic.c
index 58ef871..b9d8568 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -130,6 +130,17 @@ enum {
#define MPIC_CPU_REG_START 0x20000
#define MPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
+/*
+ * Block Revision Register1 (BRR1): QEMU does not fully emulate
+ * any version on MPIC. So to start with, set the IP version to 0.
+ *
+ * NOTE: This is Freescale MPIC specific register. Keep it here till
+ * this code is refactored for different variants of OPENPIC and MPIC.
+ */
+#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */
+#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */
+#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */
+
enum mpic_ide_bits {
IDR_EP = 31,
IDR_CI0 = 30,
@@ -595,6 +606,8 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v
if (addr & 0xF)
return;
switch (addr) {
+ case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
+ break;
case 0x40:
case 0x50:
case 0x60:
@@ -671,6 +684,7 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
case 0x1090: /* PINT */
retval = 0x00000000;
break;
+ case 0x00: /* Block Revision Register1 (BRR1) */
case 0x40:
case 0x50:
case 0x60:
@@ -893,6 +907,9 @@ static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
dst = &opp->dst[idx];
addr &= 0xFF0;
switch (addr) {
+ case 0x00: /* Block Revision Register1 (BRR1) */
+ retval = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN;
+ break;
case 0x80: /* PCTP */
retval = dst->pctp;
break;
diff --git a/hw/pc.c b/hw/pc.c
index e8bcfc0..112739a 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -51,6 +51,7 @@
#include "exec-memory.h"
#include "arch_init.h"
#include "bitmap.h"
+#include "vga-pci.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
@@ -337,32 +338,37 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
/* various important CMOS locations needed by PC/Bochs bios */
/* memory size */
- val = 640; /* base memory in K */
+ /* base memory (first MiB) */
+ val = MIN(ram_size / 1024, 640);
rtc_set_memory(s, 0x15, val);
rtc_set_memory(s, 0x16, val >> 8);
-
- val = (ram_size / 1024) - 1024;
+ /* extended memory (next 64MiB) */
+ if (ram_size > 1024 * 1024) {
+ val = (ram_size - 1024 * 1024) / 1024;
+ } else {
+ val = 0;
+ }
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x17, val);
rtc_set_memory(s, 0x18, val >> 8);
rtc_set_memory(s, 0x30, val);
rtc_set_memory(s, 0x31, val >> 8);
-
- if (above_4g_mem_size) {
- rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16);
- rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24);
- rtc_set_memory(s, 0x5d, (uint64_t)above_4g_mem_size >> 32);
- }
-
- if (ram_size > (16 * 1024 * 1024))
- val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
- else
+ /* memory between 16MiB and 4GiB */
+ if (ram_size > 16 * 1024 * 1024) {
+ val = (ram_size - 16 * 1024 * 1024) / 65536;
+ } else {
val = 0;
+ }
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x34, val);
rtc_set_memory(s, 0x35, val >> 8);
+ /* memory above 4GiB */
+ val = above_4g_mem_size / 65536;
+ rtc_set_memory(s, 0x5b, val);
+ rtc_set_memory(s, 0x5c, val >> 8);
+ rtc_set_memory(s, 0x5d, val >> 16);
/* set the number of CPU */
rtc_set_memory(s, 0x5f, smp_cpus - 1);
diff --git a/hw/pc.h b/hw/pc.h
index 54554b0..e17145f 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -195,14 +195,10 @@ static inline DeviceState *isa_vga_init(ISABus *bus)
return &dev->qdev;
}
-DeviceState *pci_vga_init(PCIBus *bus);
int isa_vga_mm_init(target_phys_addr_t vram_base,
target_phys_addr_t ctrl_base, int it_shift,
MemoryRegion *address_space);
-/* cirrus_vga.c */
-DeviceState *pci_cirrus_vga_init(PCIBus *bus);
-
/* ne2000.c */
static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
{
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 0c0096f..88ff041 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -360,6 +360,14 @@ static QEMUMachine pc_machine_v1_2 = {
#define PC_COMPAT_1_1 \
{\
+ .driver = "virtio-scsi-pci",\
+ .property = "hotplug",\
+ .value = "off",\
+ },{\
+ .driver = "virtio-scsi-pci",\
+ .property = "param_change",\
+ .value = "off",\
+ },{\
.driver = "VGA",\
.property = "vgamem_mb",\
.value = stringify(8),\
@@ -375,6 +383,10 @@ static QEMUMachine pc_machine_v1_2 = {
.driver = "qxl",\
.property = "vgamem_mb",\
.value = stringify(8),\
+ },{\
+ .driver = "virtio-blk-pci",\
+ .property = "config-wce",\
+ .value = "off",\
}
static QEMUMachine pc_machine_v1_1 = {
diff --git a/hw/pci_host.c b/hw/pci_host.c
index 8041778..3950e94 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -165,4 +165,16 @@ const MemoryRegionOps pci_host_data_be_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
+static const TypeInfo pci_host_type_info = {
+ .name = TYPE_PCI_HOST_BRIDGE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .abstract = true,
+ .instance_size = sizeof(PCIHostState),
+};
+
+static void pci_host_register_types(void)
+{
+ type_register_static(&pci_host_type_info);
+}
+type_init(pci_host_register_types)
diff --git a/hw/pci_host.h b/hw/pci_host.h
index 359e38f..4b9c300 100644
--- a/hw/pci_host.h
+++ b/hw/pci_host.h
@@ -30,8 +30,13 @@
#include "sysbus.h"
+#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge"
+#define PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE)
+
struct PCIHostState {
SysBusDevice busdev;
+
MemoryRegion conf_mem;
MemoryRegion data_mem;
MemoryRegion mmcfg;
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index 6a7d0c0..dced648 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -39,7 +39,8 @@
#include "microblaze_boot.h"
#include "microblaze_pic_cpu.h"
-#include "xilinx_axidma.h"
+
+#include "stream.h"
#define LMB_BRAM_SIZE (128 * 1024)
#define FLASH_SIZE (32 * 1024 * 1024)
@@ -76,7 +77,7 @@ petalogix_ml605_init(ram_addr_t ram_size,
const char *initrd_filename, const char *cpu_model)
{
MemoryRegion *address_space_mem = get_system_memory();
- DeviceState *dev;
+ DeviceState *dev, *dma, *eth0;
MicroBlazeCPU *cpu;
CPUMBState *env;
DriveInfo *dinfo;
@@ -125,15 +126,18 @@ petalogix_ml605_init(ram_addr_t ram_size,
/* 2 timers at irq 2 @ 100 Mhz. */
xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000);
- /* axi ethernet and dma initialization. TODO: Dynamically connect them. */
- {
- static struct XilinxDMAConnection dmach;
+ /* axi ethernet and dma initialization. */
+ dma = qdev_create(NULL, "xlnx.axi-dma");
- xilinx_axiethernet_create(&dmach, &nd_table[0], 0x82780000,
- irq[3], 0x1000, 0x1000);
- xilinx_axiethernetdma_create(&dmach, 0x84600000,
- irq[1], irq[0], 100 * 1000000);
- }
+ /* FIXME: attach to the sysbus instead */
+ object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
+ "xilinx-dma", OBJECT(dma), NULL);
+
+ eth0 = xilinx_axiethernet_create(&nd_table[0], STREAM_SLAVE(dma),
+ 0x82780000, irq[3], 0x1000, 0x1000);
+
+ xilinx_axiethernetdma_init(dma, STREAM_SLAVE(eth0),
+ 0x84600000, irq[1], irq[0], 100 * 1000000);
microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE,
machine_cpu_reset);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index c497a01..537fc19 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -36,7 +36,9 @@
* http://download.intel.com/design/chipsets/datashts/29054901.pdf
*/
-typedef PCIHostState I440FXState;
+typedef struct I440FXState {
+ PCIHostState parent_obj;
+} I440FXState;
#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */
#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */
@@ -225,7 +227,7 @@ static const VMStateDescription vmstate_i440fx = {
static int i440fx_pcihost_initfn(SysBusDevice *dev)
{
- I440FXState *s = FROM_SYSBUS(I440FXState, dev);
+ PCIHostState *s = PCI_HOST_BRIDGE(dev);
memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
"pci-conf-idx", 4);
@@ -267,14 +269,14 @@ static PCIBus *i440fx_common_init(const char *device_name,
DeviceState *dev;
PCIBus *b;
PCIDevice *d;
- I440FXState *s;
+ PCIHostState *s;
PIIX3State *piix3;
PCII440FXState *f;
dev = qdev_create(NULL, "i440FX-pcihost");
- s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev));
+ s = PCI_HOST_BRIDGE(dev);
s->address_space = address_space_mem;
- b = pci_bus_new(&s->busdev.qdev, NULL, pci_address_space,
+ b = pci_bus_new(dev, NULL, pci_address_space,
address_space_io, 0);
s->bus = b;
object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
@@ -537,7 +539,7 @@ static void piix3_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_ISA;
}
-static TypeInfo piix3_info = {
+static const TypeInfo piix3_info = {
.name = "PIIX3",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PIIX3State),
@@ -560,7 +562,7 @@ static void piix3_xen_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_ISA;
};
-static TypeInfo piix3_xen_info = {
+static const TypeInfo piix3_xen_info = {
.name = "PIIX3-xen",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PIIX3State),
@@ -584,7 +586,7 @@ static void i440fx_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_i440fx;
}
-static TypeInfo i440fx_info = {
+static const TypeInfo i440fx_info = {
.name = "i440FX",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCII440FXState),
@@ -601,9 +603,9 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo i440fx_pcihost_info = {
+static const TypeInfo i440fx_pcihost_info = {
.name = "i440FX-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(I440FXState),
.class_init = i440fx_pcihost_class_init,
};
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index aa4bbeb..951e407 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -15,7 +15,7 @@ obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o
obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
obj-y += ppc440_bamboo.o
# PowerPC E500 boards
-obj-$(CONFIG_FDT) += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
+obj-$(CONFIG_FDT) += mpc8544_guts.o ppce500_spin.o
# PowerPC 440 Xilinx ML507 reference board.
obj-y += virtex_ml507.o
# PowerPC OpenPIC
@@ -26,3 +26,5 @@ obj-$(CONFIG_FDT) += ../device_tree.o
obj-y += xilinx_ethlite.o
obj-y := $(addprefix ../,$(obj-y))
+
+obj-$(CONFIG_FDT) += e500.o mpc8544ds.o e500plat.o
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppc/e500.c
index 8b9fd83..6f0de6d 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppc/e500.c
@@ -1,5 +1,5 @@
/*
- * QEMU PowerPC MPC8544DS board emulation
+ * QEMU PowerPC e500-based platforms
*
* Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
*
@@ -16,20 +16,21 @@
#include "config.h"
#include "qemu-common.h"
+#include "e500.h"
#include "net.h"
-#include "hw.h"
-#include "pc.h"
-#include "pci.h"
-#include "boards.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/pci.h"
+#include "hw/boards.h"
#include "sysemu.h"
#include "kvm.h"
#include "kvm_ppc.h"
#include "device_tree.h"
-#include "openpic.h"
-#include "ppc.h"
-#include "loader.h"
+#include "hw/openpic.h"
+#include "hw/ppc.h"
+#include "hw/loader.h"
#include "elf.h"
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "exec-memory.h"
#include "host-utils.h"
@@ -42,6 +43,7 @@
#define RAM_SIZES_ALIGN (64UL << 20)
+/* TODO: parameterize */
#define MPC8544_CCSRBAR_BASE 0xE0000000ULL
#define MPC8544_CCSRBAR_SIZE 0x00100000ULL
#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000ULL)
@@ -66,18 +68,18 @@ static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
int i;
const uint32_t tmp[] = {
/* IDSEL 0x11 J17 Slot 1 */
- 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, 0x0, 0x0,
- 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, 0x0, 0x0,
- 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, 0x0, 0x0,
- 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
+ 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1,
+ 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1,
+ 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1,
+ 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
/* IDSEL 0x12 J16 Slot 2 */
- 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, 0x0, 0x0,
- 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, 0x0, 0x0,
- 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, 0x0, 0x0,
- 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
+ 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1,
+ 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
+ 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1,
+ 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
};
- for (i = 0; i < ARRAY_SIZE(tmp); i++) {
+ for (i = 0; i < (7 * 8); i++) {
pci_map[i] = cpu_to_be32(tmp[i]);
}
}
@@ -95,7 +97,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
- qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2, 0, 0);
+ qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2);
qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);
@@ -104,31 +106,28 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
}
}
-static int mpc8544_load_device_tree(CPUPPCState *env,
+static int ppce500_load_device_tree(CPUPPCState *env,
+ PPCE500Params *params,
target_phys_addr_t addr,
- target_phys_addr_t ramsize,
target_phys_addr_t initrd_base,
- target_phys_addr_t initrd_size,
- const char *kernel_cmdline)
+ target_phys_addr_t initrd_size)
{
int ret = -1;
- uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) };
+ uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) };
int fdt_size;
void *fdt;
uint8_t hypercall[16];
uint32_t clock_freq = 400000000;
uint32_t tb_freq = 400000000;
int i;
- const char *compatible = "MPC8544DS\0MPC85xxDS";
- int compatible_len = sizeof("MPC8544DS\0MPC85xxDS");
+ const char *toplevel_compat = NULL; /* user override */
char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
- char model[] = "MPC8544DS";
char soc[128];
char mpic[128];
uint32_t mpic_ph;
char gutil[128];
char pci[128];
- uint32_t pci_map[9 * 8];
+ uint32_t pci_map[7 * 8];
uint32_t pci_ranges[14] =
{
0x2000000, 0x0, 0xc0000000,
@@ -145,14 +144,9 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
if (machine_opts) {
- const char *tmp;
dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
dtb_file = qemu_opt_get(machine_opts, "dtb");
- tmp = qemu_opt_get(machine_opts, "dt_compatible");
- if (tmp) {
- compatible = tmp;
- compatible_len = strlen(compatible) + 1;
- }
+ toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
}
if (dtb_file) {
@@ -175,8 +169,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
}
/* Manipulate device tree in memory. */
- qemu_devtree_setprop_string(fdt, "/", "model", model);
- qemu_devtree_setprop(fdt, "/", "compatible", compatible, compatible_len);
qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);
@@ -201,7 +193,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
}
ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
- kernel_cmdline);
+ params->kernel_cmdline);
if (ret < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n");
@@ -282,18 +274,15 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, mpic);
qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
- qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
+ qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
MPC8544_CCSRBAR_BASE, 0x40000);
qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
- qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 4);
+ qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
mpic_ph = qemu_devtree_alloc_phandle(fdt);
qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
- qemu_devtree_setprop(fdt, mpic, "big-endian", NULL, 0);
- qemu_devtree_setprop(fdt, mpic, "single-cpu-affinity", NULL, 0);
- qemu_devtree_setprop_cell(fdt, mpic, "last-interrupt-source", 255);
/*
* We have to generate ser1 first, because Linux takes the first
@@ -323,7 +312,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
- qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0);
+ qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
for (i = 0; i < 14; i++) {
pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
@@ -337,6 +326,13 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
+ params->fixup_devtree(params, fdt);
+
+ if (toplevel_compat) {
+ qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat,
+ strlen(toplevel_compat) + 1);
+ }
+
done:
if (dumpdtb) {
/* Dump the dtb to a file and quit */
@@ -388,7 +384,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env)
env->tlb_dirty = true;
}
-static void mpc8544ds_cpu_reset_sec(void *opaque)
+static void ppce500_cpu_reset_sec(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
@@ -401,7 +397,7 @@ static void mpc8544ds_cpu_reset_sec(void *opaque)
env->exception_index = EXCP_HLT;
}
-static void mpc8544ds_cpu_reset(void *opaque)
+static void ppce500_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
@@ -417,12 +413,7 @@ static void mpc8544ds_cpu_reset(void *opaque)
mmubooke_create_initial_mapping(env);
}
-static void mpc8544ds_init(ram_addr_t ram_size,
- const char *boot_device,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename,
- const char *cpu_model)
+void ppce500_init(PPCE500Params *params)
{
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -443,8 +434,8 @@ static void mpc8544ds_init(ram_addr_t ram_size,
CPUPPCState *firstenv = NULL;
/* Setup CPUs */
- if (cpu_model == NULL) {
- cpu_model = "e500v2_v30";
+ if (params->cpu_model == NULL) {
+ params->cpu_model = "e500v2_v30";
}
irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
@@ -453,7 +444,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
PowerPCCPU *cpu;
qemu_irq *input;
- cpu = cpu_ppc_init(cpu_model);
+ cpu = cpu_ppc_init(params->cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to initialize CPU!\n");
exit(1);
@@ -478,11 +469,11 @@ static void mpc8544ds_init(ram_addr_t ram_size,
/* Primary CPU */
struct boot_info *boot_info;
boot_info = g_malloc0(sizeof(struct boot_info));
- qemu_register_reset(mpc8544ds_cpu_reset, cpu);
+ qemu_register_reset(ppce500_cpu_reset, cpu);
env->load_info = boot_info;
} else {
/* Secondary CPUs */
- qemu_register_reset(mpc8544ds_cpu_reset_sec, cpu);
+ qemu_register_reset(ppce500_cpu_reset_sec, cpu);
}
}
@@ -542,43 +533,45 @@ static void mpc8544ds_init(ram_addr_t ram_size,
sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
/* Load kernel. */
- if (kernel_filename) {
- kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
+ if (params->kernel_filename) {
+ kernel_size = load_uimage(params->kernel_filename, &entry,
+ &loadaddr, NULL);
if (kernel_size < 0) {
- kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
- &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+ kernel_size = load_elf(params->kernel_filename, NULL, NULL,
+ &elf_entry, &elf_lowaddr, NULL, 1,
+ ELF_MACHINE, 0);
entry = elf_entry;
loadaddr = elf_lowaddr;
}
/* XXX try again as binary */
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
+ params->kernel_filename);
exit(1);
}
}
/* Load initrd. */
- if (initrd_filename) {
+ if (params->initrd_filename) {
initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ initrd_size = load_image_targphys(params->initrd_filename, initrd_base,
ram_size - initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- initrd_filename);
+ params->initrd_filename);
exit(1);
}
}
/* If we're loading a kernel directly, we must load the device tree too. */
- if (kernel_filename) {
+ if (params->kernel_filename) {
struct boot_info *boot_info;
int dt_size;
dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
- dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base,
- initrd_size, kernel_cmdline);
+ dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base,
+ initrd_size);
if (dt_size < 0) {
fprintf(stderr, "couldn't load device tree\n");
exit(1);
@@ -594,17 +587,3 @@ static void mpc8544ds_init(ram_addr_t ram_size,
kvmppc_init();
}
}
-
-static QEMUMachine mpc8544ds_machine = {
- .name = "mpc8544ds",
- .desc = "mpc8544ds",
- .init = mpc8544ds_init,
- .max_cpus = 15,
-};
-
-static void mpc8544ds_machine_init(void)
-{
- qemu_register_machine(&mpc8544ds_machine);
-}
-
-machine_init(mpc8544ds_machine_init);
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
new file mode 100644
index 0000000..7ae87f4
--- /dev/null
+++ b/hw/ppc/e500.h
@@ -0,0 +1,21 @@
+#ifndef PPCE500_H
+#define PPCE500_H
+
+typedef struct PPCE500Params {
+ /* Standard QEMU machine init params */
+ ram_addr_t ram_size;
+ const char *boot_device;
+ const char *kernel_filename;
+ const char *kernel_cmdline;
+ const char *initrd_filename;
+ const char *cpu_model;
+
+ /* e500-specific params */
+
+ /* required -- must at least add toplevel board compatible */
+ void (*fixup_devtree)(struct PPCE500Params *params, void *fdt);
+} PPCE500Params;
+
+void ppce500_init(PPCE500Params *params);
+
+#endif
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
new file mode 100644
index 0000000..60a5cb3
--- /dev/null
+++ b/hw/ppc/e500plat.c
@@ -0,0 +1,60 @@
+/*
+ * Generic device-tree-driven paravirt PPC e500 platform
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "e500.h"
+#include "../boards.h"
+#include "device_tree.h"
+
+static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
+{
+ const char model[] = "QEMU ppce500";
+ const char compatible[] = "fsl,qemu-e500";
+
+ qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model));
+ qemu_devtree_setprop(fdt, "/", "compatible", compatible,
+ sizeof(compatible));
+}
+
+static void e500plat_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ PPCE500Params params = {
+ .ram_size = ram_size,
+ .boot_device = boot_device,
+ .kernel_filename = kernel_filename,
+ .kernel_cmdline = kernel_cmdline,
+ .initrd_filename = initrd_filename,
+ .cpu_model = cpu_model,
+ .fixup_devtree = e500plat_fixup_devtree,
+ };
+
+ ppce500_init(&params);
+}
+
+static QEMUMachine e500plat_machine = {
+ .name = "ppce500",
+ .desc = "generic paravirt e500 platform",
+ .init = e500plat_init,
+ .max_cpus = 15,
+};
+
+static void e500plat_machine_init(void)
+{
+ qemu_register_machine(&e500plat_machine);
+}
+
+machine_init(e500plat_machine_init);
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
new file mode 100644
index 0000000..984d21c
--- /dev/null
+++ b/hw/ppc/mpc8544ds.c
@@ -0,0 +1,61 @@
+/*
+ * Support for the PPC e500-based mpc8544ds board
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "e500.h"
+#include "../boards.h"
+#include "device_tree.h"
+
+static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt)
+{
+ const char model[] = "MPC8544DS";
+ const char compatible[] = "MPC8544DS\0MPC85xxDS";
+
+ qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model));
+ qemu_devtree_setprop(fdt, "/", "compatible", compatible,
+ sizeof(compatible));
+}
+
+static void mpc8544ds_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ PPCE500Params params = {
+ .ram_size = ram_size,
+ .boot_device = boot_device,
+ .kernel_filename = kernel_filename,
+ .kernel_cmdline = kernel_cmdline,
+ .initrd_filename = initrd_filename,
+ .cpu_model = cpu_model,
+ .fixup_devtree = mpc8544ds_fixup_devtree,
+ };
+
+ ppce500_init(&params);
+}
+
+
+static QEMUMachine ppce500_machine = {
+ .name = "mpc8544ds",
+ .desc = "mpc8544ds",
+ .init = mpc8544ds_init,
+ .max_cpus = 15,
+};
+
+static void ppce500_machine_init(void)
+{
+ qemu_register_machine(&ppce500_machine);
+}
+
+machine_init(ppce500_machine_init);
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 0dd4dab..c198071 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -216,7 +216,8 @@ static void bamboo_init(ram_addr_t ram_size,
ram_bases, ram_sizes, 1);
/* PCI */
- dev = sysbus_create_varargs("ppc4xx-pcihost", PPC440EP_PCI_CONFIG,
+ dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
+ PPC440EP_PCI_CONFIG,
pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
NULL);
diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h
index b511020..5cd78b6 100644
--- a/hw/ppc4xx.h
+++ b/hw/ppc4xx.h
@@ -53,6 +53,8 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
target_phys_addr_t *ram_sizes,
int do_init);
+#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost"
+
PCIBus *ppc4xx_pci_init(CPUPPCState *env, qemu_irq pci_irqs[4],
target_phys_addr_t config_space,
target_phys_addr_t int_ack,
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 203c3cd..a14fd42 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -45,11 +45,14 @@ struct PCITargetMap {
uint32_t la;
};
+#define PPC4xx_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(PPC4xxPCIState, (obj), TYPE_PPC4xx_PCI_HOST_BRIDGE)
+
#define PPC4xx_PCI_NR_PMMS 3
#define PPC4xx_PCI_NR_PTMS 2
struct PPC4xxPCIState {
- PCIHostState pci_state;
+ PCIHostState parent_obj;
struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
@@ -93,16 +96,18 @@ static uint64_t pci4xx_cfgaddr_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
PPC4xxPCIState *ppc4xx_pci = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci);
- return ppc4xx_pci->pci_state.config_reg;
+ return phb->config_reg;
}
static void pci4xx_cfgaddr_write(void *opaque, target_phys_addr_t addr,
uint64_t value, unsigned size)
{
PPC4xxPCIState *ppc4xx_pci = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci);
- ppc4xx_pci->pci_state.config_reg = value & ~0x3;
+ phb->config_reg = value & ~0x3;
}
static const MemoryRegionOps pci4xx_cfgaddr_ops = {
@@ -335,17 +340,17 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
PCIBus *b;
int i;
- h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
- s = DO_UPCAST(PPC4xxPCIState, pci_state, h);
+ h = PCI_HOST_BRIDGE(dev);
+ s = PPC4xx_PCI_HOST_BRIDGE(dev);
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, ppc4xx_pci_set_irq,
+ b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq,
ppc4xx_pci_map_irq, s->irq, get_system_memory(),
get_system_io(), 0, 4);
- s->pci_state.bus = b;
+ h->bus = b;
pci_create_simple(b, 0, "ppc4xx-host-bridge");
@@ -377,7 +382,7 @@ static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_OTHER;
}
-static TypeInfo ppc4xx_host_bridge_info = {
+static const TypeInfo ppc4xx_host_bridge_info = {
.name = "ppc4xx-host-bridge",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -393,9 +398,9 @@ static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_ppc4xx_pci;
}
-static TypeInfo ppc4xx_pcihost_info = {
- .name = "ppc4xx-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo ppc4xx_pcihost_info = {
+ .name = TYPE_PPC4xx_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PPC4xxPCIState),
.class_init = ppc4xx_pcihost_class_init,
};
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index af75e45..7d08418 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -55,6 +55,7 @@ qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
int nb_cpus, qemu_irq **irqs);
/* Grackle PCI */
+#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost"
PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 4e2a6e6..e95cfe8 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -52,7 +52,6 @@
#include "adb.h"
#include "mac_dbdma.h"
#include "nvram.h"
-#include "pc.h"
#include "pci.h"
#include "net.h"
#include "sysemu.h"
@@ -68,6 +67,7 @@
#include "hw/usb.h"
#include "blockdev.h"
#include "exec-memory.h"
+#include "vga-pci.h"
#define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index f2c6908..1dcd8a6 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -29,7 +29,6 @@
#include "adb.h"
#include "mac_dbdma.h"
#include "nvram.h"
-#include "pc.h"
#include "sysemu.h"
#include "net.h"
#include "isa.h"
@@ -44,6 +43,7 @@
#include "kvm_ppc.h"
#include "blockdev.h"
#include "exec-memory.h"
+#include "vga-pci.h"
#define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index be2b268..592b7b2 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -39,6 +39,7 @@
#include "blockdev.h"
#include "arch_init.h"
#include "exec-memory.h"
+#include "vga-pci.h"
//#define HARD_DEBUG_PPC_IO
//#define DEBUG_PPC_IO
@@ -470,7 +471,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
uint32_t kernel_base, initrd_base;
long kernel_size, initrd_size;
DeviceState *dev;
- SysBusDevice *sys;
PCIHostState *pcihost;
PCIBus *pci_bus;
PCIDevice *pci;
@@ -583,8 +583,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
}
dev = qdev_create(NULL, "raven-pcihost");
- sys = sysbus_from_qdev(dev);
- pcihost = DO_UPCAST(PCIHostState, busdev, sys);
+ pcihost = PCI_HOST_BRIDGE(dev);
pcihost->address_space = get_system_memory();
object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL);
qdev_init_nofail(dev);
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index 0f60b24..92b1dc0 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -72,8 +72,14 @@ struct pci_inbound {
uint32_t piwar;
};
+#define TYPE_PPC_E500_PCI_HOST_BRIDGE "e500-pcihost"
+
+#define PPC_E500_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(PPCE500PCIState, (obj), TYPE_PPC_E500_PCI_HOST_BRIDGE)
+
struct PPCE500PCIState {
- PCIHostState pci_state;
+ PCIHostState parent_obj;
+
struct pci_outbound pob[PPCE500_PCI_NR_POBS];
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
uint32_t gasket_time;
@@ -310,17 +316,17 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *address_space_io = get_system_io();
- h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
- s = DO_UPCAST(PPCE500PCIState, pci_state, h);
+ h = PCI_HOST_BRIDGE(dev);
+ s = PPC_E500_PCI_HOST_BRIDGE(dev);
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,
+ b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
mpc85xx_pci_map_irq, s->irq, address_space_mem,
address_space_io, PCI_DEVFN(0x11, 0), 4);
- s->pci_state.bus = b;
+ h->bus = b;
pci_create_simple(b, 0, "e500-host-bridge");
@@ -350,7 +356,7 @@ static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
dc->desc = "Host bridge";
}
-static TypeInfo e500_host_bridge_info = {
+static const TypeInfo e500_host_bridge_info = {
.name = "e500-host-bridge",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -366,9 +372,9 @@ static void e500_pcihost_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_ppce500_pci;
}
-static TypeInfo e500_pcihost_info = {
- .name = "e500-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo e500_pcihost_info = {
+ .name = TYPE_PPC_E500_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PPCE500PCIState),
.class_init = e500_pcihost_class_init,
};
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 38dbff4..cc44e61 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -28,8 +28,14 @@
#include "pc.h"
#include "exec-memory.h"
+#define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost"
+
+#define RAVEN_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(PREPPCIState, (obj), TYPE_RAVEN_PCI_HOST_BRIDGE)
+
typedef struct PRePPCIState {
- PCIHostState host_state;
+ PCIHostState parent_obj;
+
MemoryRegion intack;
qemu_irq irq[4];
} PREPPCIState;
@@ -42,9 +48,10 @@ static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
{
int i;
- for(i = 0; i < 11; i++) {
- if ((addr & (1 << (11 + i))) != 0)
+ for (i = 0; i < 11; i++) {
+ if ((addr & (1 << (11 + i))) != 0) {
break;
+ }
}
return (addr & 0x7ff) | (i << 11);
}
@@ -53,14 +60,16 @@ static void ppc_pci_io_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
PREPPCIState *s = opaque;
- pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, size);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
+ pci_data_write(phb->bus, PPC_PCIIO_config(addr), val, size);
}
static uint64_t ppc_pci_io_read(void *opaque, target_phys_addr_t addr,
unsigned int size)
{
PREPPCIState *s = opaque;
- return pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), size);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
+ return pci_data_read(phb->bus, PPC_PCIIO_config(addr), size);
}
static const MemoryRegionOps PPC_PCIIO_ops = {
@@ -96,8 +105,8 @@ static void prep_set_irq(void *opaque, int irq_num, int level)
static int raven_pcihost_init(SysBusDevice *dev)
{
- PCIHostState *h = FROM_SYSBUS(PCIHostState, dev);
- PREPPCIState *s = DO_UPCAST(PREPPCIState, host_state, h);
+ PCIHostState *h = PCI_HOST_BRIDGE(dev);
+ PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *address_space_io = get_system_io();
PCIBus *bus;
@@ -107,7 +116,7 @@ static int raven_pcihost_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq[i]);
}
- bus = pci_register_bus(&h->busdev.qdev, NULL,
+ bus = pci_register_bus(DEVICE(dev), NULL,
prep_set_irq, prep_map_irq, s->irq,
address_space_mem, address_space_io, 0, 4);
h->bus = bus;
@@ -166,7 +175,7 @@ static void raven_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo raven_info = {
+static const TypeInfo raven_info = {
.name = "raven",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(RavenPCIState),
@@ -183,9 +192,9 @@ static void raven_pcihost_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo raven_pcihost_info = {
- .name = "raven-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo raven_pcihost_info = {
+ .name = TYPE_RAVEN_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PREPPCIState),
.class_init = raven_pcihost_class_init,
};
diff --git a/hw/puv3.c b/hw/puv3.c
new file mode 100644
index 0000000..43f7216
--- /dev/null
+++ b/hw/puv3.c
@@ -0,0 +1,131 @@
+/*
+ * Generic PKUnity SoC machine and board descriptor
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "console.h"
+#include "elf.h"
+#include "exec-memory.h"
+#include "sysbus.h"
+#include "boards.h"
+#include "loader.h"
+#include "pc.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+#define KERNEL_LOAD_ADDR 0x03000000
+#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */
+
+static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
+{
+ CPUUniCore32State *env = opaque;
+
+ assert(irq == 0);
+ if (level) {
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ } else {
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+}
+
+static void puv3_soc_init(CPUUniCore32State *env)
+{
+ qemu_irq *cpu_intc, irqs[PUV3_IRQS_NR];
+ DeviceState *dev;
+ MemoryRegion *i8042 = g_new(MemoryRegion, 1);
+ int i;
+
+ /* Initialize interrupt controller */
+ cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, env, 1);
+ dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc);
+ for (i = 0; i < PUV3_IRQS_NR; i++) {
+ irqs[i] = qdev_get_gpio_in(dev, i);
+ }
+
+ /* Initialize minimal necessary devices for kernel booting */
+ sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL);
+ sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL);
+ sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]);
+ sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE,
+ irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1],
+ irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3],
+ irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5],
+ irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7],
+ irqs[PUV3_IRQS_GPIOHIGH], NULL);
+
+ /* Keyboard (i8042), mouse disabled for nographic */
+ i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4);
+ memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042);
+}
+
+static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size)
+{
+ MemoryRegion *ram_memory = g_new(MemoryRegion, 1);
+
+ /* SDRAM at address zero. */
+ memory_region_init_ram(ram_memory, "puv3.ram", ram_size);
+ vmstate_register_ram_global(ram_memory);
+ memory_region_add_subregion(get_system_memory(), 0, ram_memory);
+}
+
+static void puv3_load_kernel(const char *kernel_filename)
+{
+ int size;
+
+ assert(kernel_filename != NULL);
+
+ /* only zImage format supported */
+ size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
+ KERNEL_MAX_SIZE);
+ if (size < 0) {
+ hw_error("Load kernel error: '%s'\n", kernel_filename);
+ }
+
+ /* cheat curses that we have a graphic console, only under ocd console */
+ graphic_console_init(NULL, NULL, NULL, NULL, NULL);
+}
+
+static void puv3_init(ram_addr_t ram_size, const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ CPUUniCore32State *env;
+
+ if (initrd_filename) {
+ hw_error("Please use kernel built-in initramdisk.\n");
+ }
+
+ if (!cpu_model) {
+ cpu_model = "UniCore-II";
+ }
+
+ env = cpu_init(cpu_model);
+ if (!env) {
+ hw_error("Unable to find CPU definition\n");
+ }
+
+ puv3_soc_init(env);
+ puv3_board_init(env, ram_size);
+ puv3_load_kernel(kernel_filename);
+}
+
+static QEMUMachine puv3_machine = {
+ .name = "puv3",
+ .desc = "PKUnity Version-3 based on UniCore32",
+ .init = puv3_init,
+ .is_default = 1,
+ .use_scsi = 0,
+};
+
+static void puv3_machine_init(void)
+{
+ qemu_register_machine(&puv3_machine);
+}
+
+machine_init(puv3_machine_init)
diff --git a/hw/puv3.h b/hw/puv3.h
new file mode 100644
index 0000000..f37adcb
--- /dev/null
+++ b/hw/puv3.h
@@ -0,0 +1,49 @@
+/*
+ * Misc PKUnity SoC declarations
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef QEMU_HW_PUV3_H
+#define QEMU_HW_PUV3_H
+
+#define PUV3_REGS_OFFSET (0x1000) /* 4K is reasonable */
+
+/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */
+#define PUV3_DMA_BASE (0xc0200000) /* AHB-4 */
+
+/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */
+#define PUV3_GPIO_BASE (0xee500000) /* APB-5 */
+#define PUV3_INTC_BASE (0xee600000) /* APB-6 */
+#define PUV3_OST_BASE (0xee800000) /* APB-8 */
+#define PUV3_PM_BASE (0xeea00000) /* APB-10 */
+#define PUV3_PS2_BASE (0xeeb00000) /* APB-11 */
+
+/* Hardware interrupts */
+#define PUV3_IRQS_NR (32)
+
+#define PUV3_IRQS_GPIOLOW0 (0)
+#define PUV3_IRQS_GPIOLOW1 (1)
+#define PUV3_IRQS_GPIOLOW2 (2)
+#define PUV3_IRQS_GPIOLOW3 (3)
+#define PUV3_IRQS_GPIOLOW4 (4)
+#define PUV3_IRQS_GPIOLOW5 (5)
+#define PUV3_IRQS_GPIOLOW6 (6)
+#define PUV3_IRQS_GPIOLOW7 (7)
+#define PUV3_IRQS_GPIOHIGH (8)
+#define PUV3_IRQS_PS2_KBD (22)
+#define PUV3_IRQS_PS2_AUX (23)
+#define PUV3_IRQS_OST0 (26)
+
+/* All puv3_*.c use DPRINTF for debug. */
+#ifdef DEBUG_PUV3
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#endif /* !QEMU_HW_PUV3_H */
diff --git a/hw/puv3_dma.c b/hw/puv3_dma.c
new file mode 100644
index 0000000..85b97bf
--- /dev/null
+++ b/hw/puv3_dma.c
@@ -0,0 +1,109 @@
+/*
+ * DMA device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+#define PUV3_DMA_CH_NR (6)
+#define PUV3_DMA_CH_MASK (0xff)
+#define PUV3_DMA_CH(offset) ((offset) >> 8)
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ uint32_t reg_CFG[PUV3_DMA_CH_NR];
+} PUV3DMAState;
+
+static uint64_t puv3_dma_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3DMAState *s = opaque;
+ uint32_t ret = 0;
+
+ assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
+
+ switch (offset & PUV3_DMA_CH_MASK) {
+ case 0x10:
+ ret = s->reg_CFG[PUV3_DMA_CH(offset)];
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+ return ret;
+}
+
+static void puv3_dma_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3DMAState *s = opaque;
+
+ assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
+
+ switch (offset & PUV3_DMA_CH_MASK) {
+ case 0x10:
+ s->reg_CFG[PUV3_DMA_CH(offset)] = value;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+}
+
+static const MemoryRegionOps puv3_dma_ops = {
+ .read = puv3_dma_read,
+ .write = puv3_dma_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_dma_init(SysBusDevice *dev)
+{
+ PUV3DMAState *s = FROM_SYSBUS(PUV3DMAState, dev);
+ int i;
+
+ for (i = 0; i < PUV3_DMA_CH_NR; i++) {
+ s->reg_CFG[i] = 0x0;
+ }
+
+ memory_region_init_io(&s->iomem, &puv3_dma_ops, s, "puv3_dma",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_dma_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_dma_init;
+}
+
+static const TypeInfo puv3_dma_info = {
+ .name = "puv3_dma",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3DMAState),
+ .class_init = puv3_dma_class_init,
+};
+
+static void puv3_dma_register_type(void)
+{
+ type_register_static(&puv3_dma_info);
+}
+
+type_init(puv3_dma_register_type)
diff --git a/hw/puv3_gpio.c b/hw/puv3_gpio.c
new file mode 100644
index 0000000..9436e6c
--- /dev/null
+++ b/hw/puv3_gpio.c
@@ -0,0 +1,141 @@
+/*
+ * GPIO device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq irq[9];
+
+ uint32_t reg_GPLR;
+ uint32_t reg_GPDR;
+ uint32_t reg_GPIR;
+} PUV3GPIOState;
+
+static uint64_t puv3_gpio_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3GPIOState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x00:
+ ret = s->reg_GPLR;
+ break;
+ case 0x04:
+ ret = s->reg_GPDR;
+ break;
+ case 0x20:
+ ret = s->reg_GPIR;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+ return ret;
+}
+
+static void puv3_gpio_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3GPIOState *s = opaque;
+
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+ switch (offset) {
+ case 0x04:
+ s->reg_GPDR = value;
+ break;
+ case 0x08:
+ if (s->reg_GPDR & value) {
+ s->reg_GPLR |= value;
+ } else {
+ DPRINTF("Write gpio input port error!");
+ }
+ break;
+ case 0x0c:
+ if (s->reg_GPDR & value) {
+ s->reg_GPLR &= ~value;
+ } else {
+ DPRINTF("Write gpio input port error!");
+ }
+ break;
+ case 0x10: /* GRER */
+ case 0x14: /* GFER */
+ case 0x18: /* GEDR */
+ break;
+ case 0x20: /* GPIR */
+ s->reg_GPIR = value;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+}
+
+static const MemoryRegionOps puv3_gpio_ops = {
+ .read = puv3_gpio_read,
+ .write = puv3_gpio_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_gpio_init(SysBusDevice *dev)
+{
+ PUV3GPIOState *s = FROM_SYSBUS(PUV3GPIOState, dev);
+
+ s->reg_GPLR = 0;
+ s->reg_GPDR = 0;
+
+ /* FIXME: these irqs not handled yet */
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW0]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW1]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW2]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW3]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW4]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW5]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW6]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW7]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOHIGH]);
+
+ memory_region_init_io(&s->iomem, &puv3_gpio_ops, s, "puv3_gpio",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_gpio_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_gpio_init;
+}
+
+static const TypeInfo puv3_gpio_info = {
+ .name = "puv3_gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3GPIOState),
+ .class_init = puv3_gpio_class_init,
+};
+
+static void puv3_gpio_register_type(void)
+{
+ type_register_static(&puv3_gpio_info);
+}
+
+type_init(puv3_gpio_register_type)
diff --git a/hw/puv3_intc.c b/hw/puv3_intc.c
new file mode 100644
index 0000000..9e0b975
--- /dev/null
+++ b/hw/puv3_intc.c
@@ -0,0 +1,135 @@
+/*
+ * INTC device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq parent_irq;
+
+ uint32_t reg_ICMR;
+ uint32_t reg_ICPR;
+} PUV3INTCState;
+
+/* Update interrupt status after enabled or pending bits have been changed. */
+static void puv3_intc_update(PUV3INTCState *s)
+{
+ if (s->reg_ICMR & s->reg_ICPR) {
+ qemu_irq_raise(s->parent_irq);
+ } else {
+ qemu_irq_lower(s->parent_irq);
+ }
+}
+
+/* Process a change in an external INTC input. */
+static void puv3_intc_handler(void *opaque, int irq, int level)
+{
+ PUV3INTCState *s = opaque;
+
+ DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
+ if (level) {
+ s->reg_ICPR |= (1 << irq);
+ } else {
+ s->reg_ICPR &= ~(1 << irq);
+ }
+ puv3_intc_update(s);
+}
+
+static uint64_t puv3_intc_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3INTCState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x04: /* INTC_ICMR */
+ ret = s->reg_ICMR;
+ break;
+ case 0x0c: /* INTC_ICIP */
+ ret = s->reg_ICPR; /* the same value with ICPR */
+ break;
+ default:
+ DPRINTF("Bad offset %x\n", (int)offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+ return ret;
+}
+
+static void puv3_intc_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3INTCState *s = opaque;
+
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+ switch (offset) {
+ case 0x00: /* INTC_ICLR */
+ case 0x14: /* INTC_ICCR */
+ break;
+ case 0x04: /* INTC_ICMR */
+ s->reg_ICMR = value;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", (int)offset);
+ return;
+ }
+ puv3_intc_update(s);
+}
+
+static const MemoryRegionOps puv3_intc_ops = {
+ .read = puv3_intc_read,
+ .write = puv3_intc_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_intc_init(SysBusDevice *dev)
+{
+ PUV3INTCState *s = FROM_SYSBUS(PUV3INTCState, dev);
+
+ qdev_init_gpio_in(&s->busdev.qdev, puv3_intc_handler, PUV3_IRQS_NR);
+ sysbus_init_irq(&s->busdev, &s->parent_irq);
+
+ s->reg_ICMR = 0;
+ s->reg_ICPR = 0;
+
+ memory_region_init_io(&s->iomem, &puv3_intc_ops, s, "puv3_intc",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_intc_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_intc_init;
+}
+
+static const TypeInfo puv3_intc_info = {
+ .name = "puv3_intc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3INTCState),
+ .class_init = puv3_intc_class_init,
+};
+
+static void puv3_intc_register_type(void)
+{
+ type_register_static(&puv3_intc_info);
+}
+
+type_init(puv3_intc_register_type)
diff --git a/hw/puv3_ost.c b/hw/puv3_ost.c
new file mode 100644
index 0000000..dd30cad
--- /dev/null
+++ b/hw/puv3_ost.c
@@ -0,0 +1,151 @@
+/*
+ * OSTimer device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "sysbus.h"
+#include "ptimer.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+/* puv3 ostimer implementation. */
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ QEMUBH *bh;
+ qemu_irq irq;
+ ptimer_state *ptimer;
+
+ uint32_t reg_OSMR0;
+ uint32_t reg_OSCR;
+ uint32_t reg_OSSR;
+ uint32_t reg_OIER;
+} PUV3OSTState;
+
+static uint64_t puv3_ost_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3OSTState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x10: /* Counter Register */
+ ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer);
+ break;
+ case 0x14: /* Status Register */
+ ret = s->reg_OSSR;
+ break;
+ case 0x1c: /* Interrupt Enable Register */
+ ret = s->reg_OIER;
+ break;
+ default:
+ DPRINTF("Bad offset %x\n", (int)offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+ return ret;
+}
+
+static void puv3_ost_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3OSTState *s = opaque;
+
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+ switch (offset) {
+ case 0x00: /* Match Register 0 */
+ s->reg_OSMR0 = value;
+ if (s->reg_OSMR0 > s->reg_OSCR) {
+ ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR);
+ } else {
+ ptimer_set_count(s->ptimer, s->reg_OSMR0 +
+ (0xffffffff - s->reg_OSCR));
+ }
+ ptimer_run(s->ptimer, 2);
+ break;
+ case 0x14: /* Status Register */
+ assert(value == 0);
+ if (s->reg_OSSR) {
+ s->reg_OSSR = value;
+ qemu_irq_lower(s->irq);
+ }
+ break;
+ case 0x1c: /* Interrupt Enable Register */
+ s->reg_OIER = value;
+ break;
+ default:
+ DPRINTF("Bad offset %x\n", (int)offset);
+ }
+}
+
+static const MemoryRegionOps puv3_ost_ops = {
+ .read = puv3_ost_read,
+ .write = puv3_ost_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void puv3_ost_tick(void *opaque)
+{
+ PUV3OSTState *s = opaque;
+
+ DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n",
+ s->reg_OSCR, s->reg_OSMR0);
+
+ s->reg_OSCR = s->reg_OSMR0;
+ if (s->reg_OIER) {
+ s->reg_OSSR = 1;
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static int puv3_ost_init(SysBusDevice *dev)
+{
+ PUV3OSTState *s = FROM_SYSBUS(PUV3OSTState, dev);
+
+ s->reg_OIER = 0;
+ s->reg_OSSR = 0;
+ s->reg_OSMR0 = 0;
+ s->reg_OSCR = 0;
+
+ sysbus_init_irq(dev, &s->irq);
+
+ s->bh = qemu_bh_new(puv3_ost_tick, s);
+ s->ptimer = ptimer_init(s->bh);
+ ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
+
+ memory_region_init_io(&s->iomem, &puv3_ost_ops, s, "puv3_ost",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_ost_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_ost_init;
+}
+
+static const TypeInfo puv3_ost_info = {
+ .name = "puv3_ost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3OSTState),
+ .class_init = puv3_ost_class_init,
+};
+
+static void puv3_ost_register_type(void)
+{
+ type_register_static(&puv3_ost_info);
+}
+
+type_init(puv3_ost_register_type)
diff --git a/hw/puv3_pm.c b/hw/puv3_pm.c
new file mode 100644
index 0000000..621c968
--- /dev/null
+++ b/hw/puv3_pm.c
@@ -0,0 +1,149 @@
+/*
+ * Power Management device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+
+ uint32_t reg_PMCR;
+ uint32_t reg_PCGR;
+ uint32_t reg_PLL_SYS_CFG;
+ uint32_t reg_PLL_DDR_CFG;
+ uint32_t reg_PLL_VGA_CFG;
+ uint32_t reg_DIVCFG;
+} PUV3PMState;
+
+static uint64_t puv3_pm_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3PMState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x14:
+ ret = s->reg_PCGR;
+ break;
+ case 0x18:
+ ret = s->reg_PLL_SYS_CFG;
+ break;
+ case 0x1c:
+ ret = s->reg_PLL_DDR_CFG;
+ break;
+ case 0x20:
+ ret = s->reg_PLL_VGA_CFG;
+ break;
+ case 0x24:
+ ret = s->reg_DIVCFG;
+ break;
+ case 0x28: /* PLL SYS STATUS */
+ ret = 0x00002401;
+ break;
+ case 0x2c: /* PLL DDR STATUS */
+ ret = 0x00100c00;
+ break;
+ case 0x30: /* PLL VGA STATUS */
+ ret = 0x00003801;
+ break;
+ case 0x34: /* DIV STATUS */
+ ret = 0x22f52015;
+ break;
+ case 0x38: /* SW RESET */
+ ret = 0x0;
+ break;
+ case 0x44: /* PLL DFC DONE */
+ ret = 0x7;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+ return ret;
+}
+
+static void puv3_pm_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3PMState *s = opaque;
+
+ switch (offset) {
+ case 0x0:
+ s->reg_PMCR = value;
+ break;
+ case 0x14:
+ s->reg_PCGR = value;
+ break;
+ case 0x18:
+ s->reg_PLL_SYS_CFG = value;
+ break;
+ case 0x1c:
+ s->reg_PLL_DDR_CFG = value;
+ break;
+ case 0x20:
+ s->reg_PLL_VGA_CFG = value;
+ break;
+ case 0x24:
+ case 0x38:
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+}
+
+static const MemoryRegionOps puv3_pm_ops = {
+ .read = puv3_pm_read,
+ .write = puv3_pm_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_pm_init(SysBusDevice *dev)
+{
+ PUV3PMState *s = FROM_SYSBUS(PUV3PMState, dev);
+
+ s->reg_PCGR = 0x0;
+
+ memory_region_init_io(&s->iomem, &puv3_pm_ops, s, "puv3_pm",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_pm_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_pm_init;
+}
+
+static const TypeInfo puv3_pm_info = {
+ .name = "puv3_pm",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3PMState),
+ .class_init = puv3_pm_class_init,
+};
+
+static void puv3_pm_register_type(void)
+{
+ type_register_static(&puv3_pm_info);
+}
+
+type_init(puv3_pm_register_type)
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index b22a37a..33b7f79 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -443,7 +443,7 @@ DeviceState *qdev_device_add(QemuOpts *opts)
bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_type);
if (!bus) {
qerror_report(QERR_NO_BUS_FOR_DEVICE,
- driver, k->bus_type);
+ k->bus_type, driver);
return NULL;
}
}
@@ -543,7 +543,7 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
qdev_print_props(mon, dev, DEVICE_CLASS(class)->props, indent);
class = object_class_get_parent(class);
} while (class != object_class_by_name(TYPE_DEVICE));
- bus_print_dev(dev->parent_bus, mon, dev, indent + 2);
+ bus_print_dev(dev->parent_bus, mon, dev, indent);
QLIST_FOREACH(child, &dev->child_bus, sibling) {
qbus_print(mon, child, indent);
}
diff --git a/hw/qdev.c b/hw/qdev.c
index b5b74b9..b5a52ac 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -159,7 +159,6 @@ int qdev_init(DeviceState *dev)
rc = dc->init(dev);
if (rc < 0) {
- object_unparent(OBJECT(dev));
qdev_free(dev);
return rc;
}
@@ -243,7 +242,6 @@ void qbus_reset_all_fn(void *opaque)
int qdev_simple_unplug_cb(DeviceState *dev)
{
/* just zap it */
- object_unparent(OBJECT(dev));
qdev_free(dev);
return 0;
}
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index b8a857d..4981a02 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -761,6 +761,7 @@ static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf)
switch (length) {
case 0:
case 3: /* USB-specific. */
+ default:
xfer = 0;
break;
case 1:
@@ -784,6 +785,7 @@ static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf)
switch (length) {
case 0:
case 3: /* USB-specific. */
+ default:
xfer = 0;
break;
case 1:
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index c8d5edd..1585683 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -175,6 +175,8 @@ static void scsi_aio_complete(void *opaque, int ret)
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
@@ -238,10 +240,9 @@ static void scsi_dma_complete(void *opaque, int ret)
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- bdrv_acct_done(s->qdev.conf.bs, &r->acct);
- }
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
@@ -270,10 +271,9 @@ static void scsi_read_complete(void * opaque, int ret)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
int n;
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- bdrv_acct_done(s->qdev.conf.bs, &r->acct);
- }
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
@@ -637,7 +637,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
{
buflen = 8;
outbuf[4] = 0;
- outbuf[5] = 0x60; /* write_same 10/16 supported */
+ outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */
outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
outbuf[7] = 0;
break;
@@ -1449,6 +1449,89 @@ invalid_field:
return;
}
+typedef struct UnmapCBData {
+ SCSIDiskReq *r;
+ uint8_t *inbuf;
+ int count;
+} UnmapCBData;
+
+static void scsi_unmap_complete(void *opaque, int ret)
+{
+ UnmapCBData *data = opaque;
+ SCSIDiskReq *r = data->r;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ uint64_t sector_num;
+ uint32_t nb_sectors;
+
+ r->req.aiocb = NULL;
+ if (ret < 0) {
+ if (scsi_handle_rw_error(r, -ret)) {
+ goto done;
+ }
+ }
+
+ if (data->count > 0 && !r->req.io_canceled) {
+ sector_num = ldq_be_p(&data->inbuf[0]);
+ nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
+ if (sector_num > sector_num + nb_sectors ||
+ sector_num + nb_sectors - 1 > s->qdev.max_lba) {
+ scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
+ goto done;
+ }
+
+ r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
+ sector_num * (s->qdev.blocksize / 512),
+ nb_sectors * (s->qdev.blocksize / 512),
+ scsi_unmap_complete, data);
+ data->count--;
+ data->inbuf += 16;
+ return;
+ }
+
+done:
+ if (data->count == 0) {
+ scsi_req_complete(&r->req, GOOD);
+ }
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
+ g_free(data);
+}
+
+static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
+{
+ uint8_t *p = inbuf;
+ int len = r->req.cmd.xfer;
+ UnmapCBData *data;
+
+ if (len < 8) {
+ goto invalid_param_len;
+ }
+ if (len < lduw_be_p(&p[0]) + 2) {
+ goto invalid_param_len;
+ }
+ if (len < lduw_be_p(&p[2]) + 8) {
+ goto invalid_param_len;
+ }
+ if (lduw_be_p(&p[2]) & 15) {
+ goto invalid_param_len;
+ }
+
+ data = g_new0(UnmapCBData, 1);
+ data->r = r;
+ data->inbuf = &p[8];
+ data->count = lduw_be_p(&p[2]) >> 4;
+
+ /* The matching unref is in scsi_unmap_complete, before data is freed. */
+ scsi_req_ref(&r->req);
+ scsi_unmap_complete(data, 0);
+ return;
+
+invalid_param_len:
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
+ return;
+}
+
static void scsi_disk_emulate_write_data(SCSIRequest *req)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -1468,6 +1551,10 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
scsi_disk_emulate_mode_select(r, r->iov.iov_base);
break;
+ case UNMAP:
+ scsi_disk_emulate_unmap(r, r->iov.iov_base);
+ break;
+
default:
abort();
}
@@ -1702,6 +1789,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
case MODE_SELECT_10:
DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
break;
+ case UNMAP:
+ DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
+ break;
case WRITE_SAME_10:
nb_sectors = lduw_be_p(&req->cmd.buf[7]);
goto write_same;
@@ -1712,7 +1802,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
return 0;
}
- if (r->req.cmd.lba > s->qdev.max_lba) {
+ if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors ||
+ r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) {
goto illegal_lba;
}
@@ -2067,6 +2158,7 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
[SEEK_10] = &scsi_disk_emulate_reqops,
[MODE_SELECT] = &scsi_disk_emulate_reqops,
[MODE_SELECT_10] = &scsi_disk_emulate_reqops,
+ [UNMAP] = &scsi_disk_emulate_reqops,
[WRITE_SAME_10] = &scsi_disk_emulate_reqops,
[WRITE_SAME_16] = &scsi_disk_emulate_reqops,
@@ -2329,6 +2421,7 @@ static TypeInfo scsi_cd_info = {
#ifdef __linux__
static Property scsi_block_properties[] = {
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.bs),
+ DEFINE_PROP_INT32("bootindex", SCSIDiskState, qdev.conf.bootindex, -1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 8d51060..a5eb663 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -479,7 +479,8 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
}
static Property scsi_generic_properties[] = {
- DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
+ DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs),
+ DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/sd.c b/hw/sd.c
index a14b50a..29d03e8 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -33,6 +33,7 @@
#include "hw.h"
#include "block.h"
#include "sd.h"
+#include "bitmap.h"
//#define DEBUG_SD 1
@@ -82,8 +83,8 @@ struct SDState {
uint32_t card_status;
uint8_t sd_status[64];
uint32_t vhs;
- int wp_switch;
- int *wp_groups;
+ bool wp_switch;
+ unsigned long *wp_groups;
uint64_t size;
int blk_len;
uint32_t erase_start;
@@ -92,12 +93,12 @@ struct SDState {
int pwd_len;
int function_group[6];
- int spi, mmc;
+ bool spi, mmc;
int current_cmd;
/* True if we will handle the next command as an ACMD. Note that this does
* *not* track the APP_CMD status bit!
*/
- int expecting_acmd;
+ bool expecting_acmd;
int blk_written;
uint64_t data_start;
uint32_t data_offset;
@@ -107,7 +108,7 @@ struct SDState {
BlockDriverState *bdrv;
uint8_t *buf;
- int enable;
+ bool enable;
int buswidth, highspeed;
};
@@ -431,6 +432,11 @@ static void sd_response_r7_make(SDState *sd, uint8_t *response)
response[3] = (sd->vhs >> 0) & 0xff;
}
+static inline uint64_t sd_addr_to_wpnum(uint64_t addr)
+{
+ return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+}
+
void sd_reset(SDState *sd)
{
uint64_t size;
@@ -443,7 +449,7 @@ void sd_reset(SDState *sd)
}
size = sect << 9;
- sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+ sect = sd_addr_to_wpnum(size) + 1;
sd->state = sd_idle_state;
sd->rca = 0x0000;
@@ -456,15 +462,15 @@ void sd_reset(SDState *sd)
if (sd->wp_groups)
g_free(sd->wp_groups);
- sd->wp_switch = sd->bdrv ? bdrv_is_read_only(sd->bdrv) : 0;
- sd->wp_groups = (int *) g_malloc0(sizeof(int) * sect);
+ sd->wp_switch = sd->bdrv ? bdrv_is_read_only(sd->bdrv) : false;
+ sd->wp_groups = bitmap_new(sect);
memset(sd->function_group, 0, sizeof(int) * 6);
sd->erase_start = 0;
sd->erase_end = 0;
sd->size = size;
sd->blk_len = 0x200;
sd->pwd_len = 0;
- sd->expecting_acmd = 0;
+ sd->expecting_acmd = false;
}
static void sd_cardchange(void *opaque, bool load)
@@ -486,7 +492,7 @@ static const BlockDevOps sd_block_ops = {
whether card should be in SSI or MMC/SD mode. It is also up to the
board to ensure that ssi transfers only occur when the chip select
is asserted. */
-SDState *sd_init(BlockDriverState *bs, int is_spi, int is_mmc)
+SDState *sd_init(BlockDriverState *bs, bool is_spi, bool is_mmc)
{
SDState *sd;
@@ -494,7 +500,7 @@ SDState *sd_init(BlockDriverState *bs, int is_spi, int is_mmc)
sd->buf = qemu_blockalign(bs, 512);
sd->spi = is_spi;
sd->mmc = is_mmc;
- sd->enable = 1;
+ sd->enable = true;
sd->bdrv = bs;
sd_reset(sd);
if (sd->bdrv) {
@@ -520,17 +526,17 @@ static void sd_erase(SDState *sd)
return;
}
- start = sd->erase_start >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
- end = sd->erase_end >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+ start = sd_addr_to_wpnum(sd->erase_start);
+ end = sd_addr_to_wpnum(sd->erase_end);
sd->erase_start = 0;
sd->erase_end = 0;
sd->csd[14] |= 0x40;
- for (i = start; i <= end; i ++)
- if (sd->wp_groups[i])
+ for (i = start; i <= end; i++) {
+ if (test_bit(i, sd->wp_groups)) {
sd->card_status |= WP_ERASE_SKIP;
+ }
+ }
}
static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
@@ -538,11 +544,13 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
uint32_t i, wpnum;
uint32_t ret = 0;
- wpnum = addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+ wpnum = sd_addr_to_wpnum(addr);
- for (i = 0; i < 32; i ++, wpnum ++, addr += WPGROUP_SIZE)
- if (addr < sd->size && sd->wp_groups[wpnum])
+ for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) {
+ if (addr < sd->size && test_bit(wpnum, sd->wp_groups)) {
ret |= (1 << i);
+ }
+ }
return ret;
}
@@ -618,10 +626,9 @@ static void mmc_function_switch(SDState *sd, uint32_t arg)
}
}
-static inline int sd_wp_addr(SDState *sd, uint32_t addr)
+static inline bool sd_wp_addr(SDState *sd, uint64_t addr)
{
- return sd->wp_groups[addr >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)];
+ return test_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
}
static void sd_lock_command(SDState *sd)
@@ -644,8 +651,7 @@ static void sd_lock_command(SDState *sd)
sd->card_status |= LOCK_UNLOCK_FAILED;
return;
}
- memset(sd->wp_groups, 0, sizeof(int) * (sd->size >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)));
+ bitmap_zero(sd->wp_groups, sd_addr_to_wpnum(sd->size) + 1);
sd->csd[14] &= ~0x10;
sd->card_status &= ~CARD_IS_LOCKED;
sd->pwd_len = 0;
@@ -1151,8 +1157,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
}
sd->state = sd_programming_state;
- sd->wp_groups[addr >> (HWBLOCK_SHIFT +
- SECTOR_SHIFT + WPGROUP_SHIFT)] = 1;
+ set_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
/* Bzzzzzzztt .... Operation complete. */
sd->state = sd_transfer_state;
return sd_r1b;
@@ -1171,8 +1176,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
}
sd->state = sd_programming_state;
- sd->wp_groups[addr >> (HWBLOCK_SHIFT +
- SECTOR_SHIFT + WPGROUP_SHIFT)] = 0;
+ clear_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
/* Bzzzzzzztt .... Operation complete. */
sd->state = sd_transfer_state;
return sd_r1b;
@@ -1290,7 +1294,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
if (sd->rca != rca)
return sd_r0;
- sd->expecting_acmd = 1;
+ sd->expecting_acmd = true;
sd->card_status |= APP_CMD;
return sd_r1;
@@ -1472,7 +1476,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
if (sd->card_status & CARD_IS_LOCKED) {
if (!cmd_valid_while_locked(sd, req)) {
sd->card_status |= ILLEGAL_COMMAND;
- sd->expecting_acmd = 0;
+ sd->expecting_acmd = false;
fprintf(stderr, "SD: Card is locked\n");
rtype = sd_illegal;
goto send_response;
@@ -1483,7 +1487,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
sd_set_mode(sd);
if (sd->expecting_acmd) {
- sd->expecting_acmd = 0;
+ sd->expecting_acmd = false;
rtype = sd_app_command(sd, *req);
} else {
rtype = sd_normal_command(sd, *req);
@@ -1881,17 +1885,17 @@ uint8_t sd_read_data(SDState *sd)
return ret;
}
-int sd_data_ready(SDState *sd)
+bool sd_data_ready(SDState *sd)
{
return sd->state == sd_sendingdata_state;
}
-void sd_enable(SDState *sd, int enable)
+void sd_enable(SDState *sd, bool enable)
{
sd->enable = enable;
}
-int sd_is_mmc(SDState *sd)
+bool sd_is_mmc(SDState *sd)
{
return sd->mmc;
}
diff --git a/hw/sd.h b/hw/sd.h
index 96450f2..dae2d1f 100644
--- a/hw/sd.h
+++ b/hw/sd.h
@@ -67,15 +67,15 @@ typedef struct {
typedef struct SDState SDState;
-SDState *sd_init(BlockDriverState *bs, int is_spi, int is_mmc);
+SDState *sd_init(BlockDriverState *bs, bool is_spi, bool is_mmc);
void sd_reset(SDState *sd);
int sd_do_command(SDState *sd, SDRequest *req,
uint8_t *response);
void sd_write_data(SDState *sd, uint8_t value);
uint8_t sd_read_data(SDState *sd);
void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
-int sd_data_ready(SDState *sd);
-void sd_enable(SDState *sd, int enable);
-int sd_is_mmc(SDState *sd);
+bool sd_data_ready(SDState *sd);
+void sd_enable(SDState *sd, bool enable);
+bool sd_is_mmc(SDState *sd);
#endif /* __hw_sd_h */
diff --git a/hw/shpc.c b/hw/shpc.c
index 6b9884d..a5baf24 100644
--- a/hw/shpc.c
+++ b/hw/shpc.c
@@ -253,7 +253,6 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
++devfn) {
PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
if (affected_dev) {
- object_unparent(OBJECT(affected_dev));
qdev_free(&affected_dev->qdev);
}
}
diff --git a/hw/spapr.c b/hw/spapr.c
index 81c9343..c34b767 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -41,12 +41,15 @@
#include "hw/spapr_vio.h"
#include "hw/spapr_pci.h"
#include "hw/xics.h"
+#include "hw/msi.h"
#include "kvm.h"
#include "kvm_ppc.h"
#include "pci.h"
+#include "vga-pci.h"
#include "exec-memory.h"
+#include "hw/usb.h"
#include <libfdt.h>
@@ -78,16 +81,15 @@
#define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000)
#define SPAPR_PCI_MEM_WIN_SIZE 0x20000000
#define SPAPR_PCI_IO_WIN_ADDR (0x10000000000ULL + 0x80000000)
+#define SPAPR_PCI_MSI_WIN_ADDR (0x10000000000ULL + 0x90000000)
#define PHANDLE_XICP 0x00001111
sPAPREnvironment *spapr;
-qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
- enum xics_irq_type type)
+int spapr_allocate_irq(int hint, enum xics_irq_type type)
{
- uint32_t irq;
- qemu_irq qirq;
+ int irq;
if (hint) {
irq = hint;
@@ -96,16 +98,40 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
irq = spapr->next_irq++;
}
- qirq = xics_assign_irq(spapr->icp, irq, type);
- if (!qirq) {
- return NULL;
+ /* Configure irq type */
+ if (!xics_get_qirq(spapr->icp, irq)) {
+ return 0;
}
- if (irq_num) {
- *irq_num = irq;
+ xics_set_irq_type(spapr->icp, irq, type);
+
+ return irq;
+}
+
+/* Allocate block of consequtive IRQs, returns a number of the first */
+int spapr_allocate_irq_block(int num, enum xics_irq_type type)
+{
+ int first = -1;
+ int i;
+
+ for (i = 0; i < num; ++i) {
+ int irq;
+
+ irq = spapr_allocate_irq(0, type);
+ if (!irq) {
+ return -1;
+ }
+
+ if (0 == i) {
+ first = irq;
+ }
+
+ /* If the above doesn't create a consecutive block then that's
+ * an internal bug */
+ assert(irq == (first + i));
}
- return qirq;
+ return first;
}
static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr)
@@ -257,6 +283,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
_FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
}
_FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
+ _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width)));
+ _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height)));
+ _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth)));
_FDT((fdt_end_node(fdt)));
@@ -481,7 +510,7 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
}
QLIST_FOREACH(phb, &spapr->phbs, list) {
- ret = spapr_populate_pci_devices(phb, PHANDLE_XICP, fdt);
+ ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt);
}
if (ret < 0) {
@@ -503,7 +532,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
}
}
- spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
+ if (!spapr->has_graphics) {
+ spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
+ }
_FDT((fdt_pack(fdt)));
@@ -532,8 +563,6 @@ static void spapr_reset(void *opaque)
{
sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
- fprintf(stderr, "sPAPR reset\n");
-
/* flush out the hash table */
memset(spapr->htab, 0, spapr->htab_size);
@@ -556,6 +585,23 @@ static void spapr_cpu_reset(void *opaque)
cpu_reset(CPU(cpu));
}
+/* Returns whether we want to use VGA or not */
+static int spapr_vga_init(PCIBus *pci_bus)
+{
+ switch (vga_interface_type) {
+ case VGA_STD:
+ pci_vga_init(pci_bus);
+ return 1;
+ case VGA_NONE:
+ return 0;
+ default:
+ fprintf(stderr, "This vga model is not supported,"
+ "currently it only supports -vga std\n");
+ exit(0);
+ break;
+ }
+}
+
/* pSeries LPAR / sPAPR hardware init */
static void ppc_spapr_init(ram_addr_t ram_size,
const char *boot_device,
@@ -566,6 +612,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
{
PowerPCCPU *cpu;
CPUPPCState *env;
+ PCIHostState *phb;
int i;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -576,6 +623,8 @@ static void ppc_spapr_init(ram_addr_t ram_size,
long pteg_shift = 17;
char *filename;
+ msi_supported = true;
+
spapr = g_malloc0(sizeof(*spapr));
QLIST_INIT(&spapr->phbs);
@@ -687,10 +736,14 @@ static void ppc_spapr_init(ram_addr_t ram_size,
}
/* Set up PCI */
+ spapr_pci_rtas_init();
+
spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID,
SPAPR_PCI_MEM_WIN_ADDR,
SPAPR_PCI_MEM_WIN_SIZE,
- SPAPR_PCI_IO_WIN_ADDR);
+ SPAPR_PCI_IO_WIN_ADDR,
+ SPAPR_PCI_MSI_WIN_ADDR);
+ phb = PCI_HOST_BRIDGE(QLIST_FIRST(&spapr->phbs));
for (i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
@@ -710,20 +763,25 @@ static void ppc_spapr_init(ram_addr_t ram_size,
spapr_vscsi_create(spapr->vio_bus);
}
+ /* Graphics */
+ if (spapr_vga_init(phb->bus)) {
+ spapr->has_graphics = true;
+ }
+
+ if (usb_enabled) {
+ pci_create_simple(phb->bus, -1, "pci-ohci");
+ if (spapr->has_graphics) {
+ usbdevice_create("keyboard");
+ usbdevice_create("mouse");
+ }
+ }
+
if (rma_size < (MIN_RMA_SLOF << 20)) {
fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
"%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
exit(1);
}
- fprintf(stderr, "sPAPR memory map:\n");
- fprintf(stderr, "RTAS : 0x%08lx..%08lx\n",
- (unsigned long)spapr->rtas_addr,
- (unsigned long)(spapr->rtas_addr + spapr->rtas_size - 1));
- fprintf(stderr, "FDT : 0x%08lx..%08lx\n",
- (unsigned long)spapr->fdt_addr,
- (unsigned long)(spapr->fdt_addr + FDT_MAX_SIZE - 1));
-
if (kernel_filename) {
uint64_t lowaddr = 0;
@@ -739,8 +797,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
kernel_filename);
exit(1);
}
- fprintf(stderr, "Kernel : 0x%08x..%08lx\n",
- KERNEL_LOAD_ADDR, KERNEL_LOAD_ADDR + kernel_size - 1);
/* load initrd */
if (initrd_filename) {
@@ -755,8 +811,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
initrd_filename);
exit(1);
}
- fprintf(stderr, "Ramdisk : 0x%08lx..%08lx\n",
- (long)initrd_base, (long)(initrd_base + initrd_size - 1));
} else {
initrd_base = 0;
initrd_size = 0;
@@ -770,10 +824,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
exit(1);
}
g_free(filename);
- fprintf(stderr, "Firmware load : 0x%08x..%08lx\n",
- 0, fw_size);
- fprintf(stderr, "Firmware runtime : 0x%08lx..%08lx\n",
- load_limit, (unsigned long)spapr->fdt_addr);
spapr->entry_point = 0x100;
diff --git a/hw/spapr.h b/hw/spapr.h
index 9153f29..ac34a17 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -23,6 +23,7 @@ typedef struct sPAPREnvironment {
int next_irq;
int rtc_offset;
char *cpu_model;
+ bool has_graphics;
} sPAPREnvironment;
#define H_SUCCESS 0
@@ -288,17 +289,17 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode,
target_ulong *args);
-qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
- enum xics_irq_type type);
+int spapr_allocate_irq(int hint, enum xics_irq_type type);
+int spapr_allocate_irq_block(int num, enum xics_irq_type type);
-static inline qemu_irq spapr_allocate_msi(uint32_t hint, uint32_t *irq_num)
+static inline int spapr_allocate_msi(int hint)
{
- return spapr_allocate_irq(hint, irq_num, XICS_MSI);
+ return spapr_allocate_irq(hint, XICS_MSI);
}
-static inline qemu_irq spapr_allocate_lsi(uint32_t hint, uint32_t *irq_num)
+static inline int spapr_allocate_lsi(int hint)
{
- return spapr_allocate_irq(hint, irq_num, XICS_LSI);
+ return spapr_allocate_irq(hint, XICS_LSI);
}
static inline uint32_t rtas_ld(target_ulong phys, int n)
@@ -336,6 +337,8 @@ void spapr_iommu_init(void);
DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size);
void spapr_tce_free(DMAContext *dma);
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
- DMAContext *dma);
+ uint32_t liobn, uint64_t window, uint32_t size);
+int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
+ DMAContext *dma);
#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c
index 388ffa4..53b7317 100644
--- a/hw/spapr_iommu.c
+++ b/hw/spapr_iommu.c
@@ -216,31 +216,47 @@ void spapr_iommu_init(void)
}
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
- DMAContext *dma)
+ uint32_t liobn, uint64_t window, uint32_t size)
{
- if (dma) {
- sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
- uint32_t dma_prop[] = {cpu_to_be32(tcet->liobn),
- 0, 0,
- 0, cpu_to_be32(tcet->window_size)};
- int ret;
-
- ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
- if (ret < 0) {
- return ret;
- }
+ uint32_t dma_prop[5];
+ int ret;
+
+ dma_prop[0] = cpu_to_be32(liobn);
+ dma_prop[1] = cpu_to_be32(window >> 32);
+ dma_prop[2] = cpu_to_be32(window & 0xFFFFFFFF);
+ dma_prop[3] = 0; /* window size is 32 bits */
+ dma_prop[4] = cpu_to_be32(size);
+
+ ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
+ if (ret < 0) {
+ return ret;
+ }
- ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
- if (ret < 0) {
- return ret;
- }
+ ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
+ if (ret < 0) {
+ return ret;
+ }
- ret = fdt_setprop(fdt, node_off, propname, dma_prop,
- sizeof(dma_prop));
- if (ret < 0) {
- return ret;
- }
+ ret = fdt_setprop(fdt, node_off, propname, dma_prop, sizeof(dma_prop));
+ if (ret < 0) {
+ return ret;
}
return 0;
}
+
+int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
+ DMAContext *iommu)
+{
+ if (!iommu) {
+ return 0;
+ }
+
+ if (iommu->translate == spapr_tce_translate) {
+ sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, iommu);
+ return spapr_dma_dt(fdt, node_off, propname,
+ tcet->liobn, 0, tcet->window_size);
+ }
+
+ return -1;
+}
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 01e54f3..bd3f131 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -169,7 +169,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
}
if (sdev->signal_state & 1) {
- qemu_irq_pulse(sdev->qirq);
+ qemu_irq_pulse(spapr_vio_qirq(sdev));
}
return size;
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index b2e4f78..661c05b 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -24,32 +24,59 @@
*/
#include "hw.h"
#include "pci.h"
+#include "msi.h"
+#include "msix.h"
#include "pci_host.h"
#include "hw/spapr.h"
#include "hw/spapr_pci.h"
#include "exec-memory.h"
#include <libfdt.h>
+#include "trace.h"
#include "hw/pci_internals.h"
-static PCIDevice *find_dev(sPAPREnvironment *spapr,
- uint64_t buid, uint32_t config_addr)
-{
- int devfn = (config_addr >> 8) & 0xFF;
- sPAPRPHBState *phb;
+/* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
+#define RTAS_QUERY_FN 0
+#define RTAS_CHANGE_FN 1
+#define RTAS_RESET_FN 2
+#define RTAS_CHANGE_MSI_FN 3
+#define RTAS_CHANGE_MSIX_FN 4
- QLIST_FOREACH(phb, &spapr->phbs, list) {
- BusChild *kid;
+/* Interrupt types to return on RTAS_CHANGE_* */
+#define RTAS_TYPE_MSI 1
+#define RTAS_TYPE_MSIX 2
+
+static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
+{
+ sPAPRPHBState *sphb;
- if (phb->buid != buid) {
+ QLIST_FOREACH(sphb, &spapr->phbs, list) {
+ if (sphb->buid != buid) {
continue;
}
+ return sphb;
+ }
+
+ return NULL;
+}
+
+static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid,
+ uint32_t config_addr)
+{
+ sPAPRPHBState *sphb = find_phb(spapr, buid);
+ PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
+ BusState *bus = BUS(phb->bus);
+ BusChild *kid;
+ int devfn = (config_addr >> 8) & 0xFF;
+
+ if (!phb) {
+ return NULL;
+ }
- QTAILQ_FOREACH(kid, &phb->host_state.bus->qbus.children, sibling) {
- PCIDevice *dev = (PCIDevice *)kid->child;
- if (dev->devfn == devfn) {
- return dev;
- }
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ PCIDevice *dev = (PCIDevice *)kid->child;
+ if (dev->devfn == devfn) {
+ return dev;
}
}
@@ -199,6 +226,191 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
finish_write_pci_config(spapr, 0, addr, size, val, rets);
}
+/*
+ * Find an entry with config_addr or returns the empty one if not found AND
+ * alloc_new is set.
+ * At the moment the msi_table entries are never released so there is
+ * no point to look till the end of the list if we need to find the free entry.
+ */
+static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
+ bool alloc_new)
+{
+ int i;
+
+ for (i = 0; i < SPAPR_MSIX_MAX_DEVS; ++i) {
+ if (!phb->msi_table[i].nvec) {
+ break;
+ }
+ if (phb->msi_table[i].config_addr == config_addr) {
+ return i;
+ }
+ }
+ if ((i < SPAPR_MSIX_MAX_DEVS) && alloc_new) {
+ trace_spapr_pci_msi("Allocating new MSI config", i, config_addr);
+ return i;
+ }
+
+ return -1;
+}
+
+/*
+ * Set MSI/MSIX message data.
+ * This is required for msi_notify()/msix_notify() which
+ * will write at the addresses via spapr_msi_write().
+ */
+static void spapr_msi_setmsg(PCIDevice *pdev, target_phys_addr_t addr,
+ bool msix, unsigned req_num)
+{
+ unsigned i;
+ MSIMessage msg = { .address = addr, .data = 0 };
+
+ if (!msix) {
+ msi_set_message(pdev, msg);
+ trace_spapr_pci_msi_setup(pdev->name, 0, msg.address);
+ return;
+ }
+
+ for (i = 0; i < req_num; ++i) {
+ msg.address = addr | (i << 2);
+ msix_set_message(pdev, i, msg);
+ trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
+ }
+}
+
+static void rtas_ibm_change_msi(sPAPREnvironment *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args, uint32_t nret,
+ target_ulong rets)
+{
+ uint32_t config_addr = rtas_ld(args, 0);
+ uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+ unsigned int func = rtas_ld(args, 3);
+ unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
+ unsigned int seq_num = rtas_ld(args, 5);
+ unsigned int ret_intr_type;
+ int ndev, irq;
+ sPAPRPHBState *phb = NULL;
+ PCIDevice *pdev = NULL;
+
+ switch (func) {
+ case RTAS_CHANGE_MSI_FN:
+ case RTAS_CHANGE_FN:
+ ret_intr_type = RTAS_TYPE_MSI;
+ break;
+ case RTAS_CHANGE_MSIX_FN:
+ ret_intr_type = RTAS_TYPE_MSIX;
+ break;
+ default:
+ fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func);
+ rtas_st(rets, 0, -3); /* Parameter error */
+ return;
+ }
+
+ /* Fins sPAPRPHBState */
+ phb = find_phb(spapr, buid);
+ if (phb) {
+ pdev = find_dev(spapr, buid, config_addr);
+ }
+ if (!phb || !pdev) {
+ rtas_st(rets, 0, -3); /* Parameter error */
+ return;
+ }
+
+ /* Releasing MSIs */
+ if (!req_num) {
+ ndev = spapr_msicfg_find(phb, config_addr, false);
+ if (ndev < 0) {
+ trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
+ rtas_st(rets, 0, -1); /* Hardware error */
+ return;
+ }
+ trace_spapr_pci_msi("Released MSIs", ndev, config_addr);
+ rtas_st(rets, 0, 0);
+ rtas_st(rets, 1, 0);
+ return;
+ }
+
+ /* Enabling MSI */
+
+ /* Find a device number in the map to add or reuse the existing one */
+ ndev = spapr_msicfg_find(phb, config_addr, true);
+ if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) {
+ fprintf(stderr, "No free entry for a new MSI device\n");
+ rtas_st(rets, 0, -1); /* Hardware error */
+ return;
+ }
+ trace_spapr_pci_msi("Configuring MSI", ndev, config_addr);
+
+ /* Check if there is an old config and MSI number has not changed */
+ if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
+ /* Unexpected behaviour */
+ fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev);
+ rtas_st(rets, 0, -1); /* Hardware error */
+ return;
+ }
+
+ /* There is no cached config, allocate MSIs */
+ if (!phb->msi_table[ndev].nvec) {
+ irq = spapr_allocate_irq_block(req_num, XICS_MSI);
+ if (irq < 0) {
+ fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
+ rtas_st(rets, 0, -1); /* Hardware error */
+ return;
+ }
+ phb->msi_table[ndev].irq = irq;
+ phb->msi_table[ndev].nvec = req_num;
+ phb->msi_table[ndev].config_addr = config_addr;
+ }
+
+ /* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
+ spapr_msi_setmsg(pdev, phb->msi_win_addr | (ndev << 16),
+ ret_intr_type == RTAS_TYPE_MSIX, req_num);
+
+ rtas_st(rets, 0, 0);
+ rtas_st(rets, 1, req_num);
+ rtas_st(rets, 2, ++seq_num);
+ rtas_st(rets, 3, ret_intr_type);
+
+ trace_spapr_pci_rtas_ibm_change_msi(func, req_num);
+}
+
+static void rtas_ibm_query_interrupt_source_number(sPAPREnvironment *spapr,
+ uint32_t token,
+ uint32_t nargs,
+ target_ulong args,
+ uint32_t nret,
+ target_ulong rets)
+{
+ uint32_t config_addr = rtas_ld(args, 0);
+ uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+ unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
+ int ndev;
+ sPAPRPHBState *phb = NULL;
+
+ /* Fins sPAPRPHBState */
+ phb = find_phb(spapr, buid);
+ if (!phb) {
+ rtas_st(rets, 0, -3); /* Parameter error */
+ return;
+ }
+
+ /* Find device descriptor and start IRQ */
+ ndev = spapr_msicfg_find(phb, config_addr, false);
+ if (ndev < 0) {
+ trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
+ rtas_st(rets, 0, -1); /* Hardware error */
+ return;
+ }
+
+ intr_src_num = phb->msi_table[ndev].irq + ioa_intr_num;
+ trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num,
+ intr_src_num);
+
+ rtas_st(rets, 0, 0);
+ rtas_st(rets, 1, intr_src_num);
+ rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
+}
+
static int pci_spapr_swizzle(int slot, int pin)
{
return (slot + pin) % PCI_NUM_PINS;
@@ -223,7 +435,8 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
*/
sPAPRPHBState *phb = opaque;
- qemu_set_irq(phb->lsi_table[irq_num].qirq, level);
+ trace_spapr_pci_lsi_set(phb->busname, irq_num, phb->lsi_table[irq_num].irq);
+ qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
}
static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr,
@@ -264,6 +477,33 @@ static const MemoryRegionOps spapr_io_ops = {
};
/*
+ * MSI/MSIX memory region implementation.
+ * The handler handles both MSI and MSIX.
+ * For MSI-X, the vector number is encoded as a part of the address,
+ * data is set to 0.
+ * For MSI, the vector number is encoded in least bits in data.
+ */
+static void spapr_msi_write(void *opaque, target_phys_addr_t addr,
+ uint64_t data, unsigned size)
+{
+ sPAPRPHBState *phb = opaque;
+ int ndev = addr >> 16;
+ int vec = ((addr & 0xFFFF) >> 2) | data;
+ uint32_t irq = phb->msi_table[ndev].irq + vec;
+
+ trace_spapr_pci_msi_write(addr, data, irq);
+
+ qemu_irq_pulse(xics_get_qirq(spapr->icp, irq));
+}
+
+static const MemoryRegionOps spapr_msi_ops = {
+ /* There is no .read as the read result is undefined by PCI spec */
+ .read = NULL,
+ .write = spapr_msi_write,
+ .endianness = DEVICE_LITTLE_ENDIAN
+};
+
+/*
* PHB PCI device
*/
static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque,
@@ -276,24 +516,24 @@ static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque,
static int spapr_phb_init(SysBusDevice *s)
{
- sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s);
+ sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
char *namebuf;
int i;
PCIBus *bus;
- uint32_t liobn;
- phb->dtbusname = g_strdup_printf("pci@%" PRIx64, phb->buid);
- namebuf = alloca(strlen(phb->dtbusname) + 32);
+ sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid);
+ namebuf = alloca(strlen(sphb->dtbusname) + 32);
/* Initialize memory regions */
- sprintf(namebuf, "%s.mmio", phb->dtbusname);
- memory_region_init(&phb->memspace, namebuf, INT64_MAX);
+ sprintf(namebuf, "%s.mmio", sphb->dtbusname);
+ memory_region_init(&sphb->memspace, namebuf, INT64_MAX);
- sprintf(namebuf, "%s.mmio-alias", phb->dtbusname);
- memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace,
- SPAPR_PCI_MEM_WIN_BUS_OFFSET, phb->mem_win_size);
- memory_region_add_subregion(get_system_memory(), phb->mem_win_addr,
- &phb->memwindow);
+ sprintf(namebuf, "%s.mmio-alias", sphb->dtbusname);
+ memory_region_init_alias(&sphb->memwindow, namebuf, &sphb->memspace,
+ SPAPR_PCI_MEM_WIN_BUS_OFFSET, sphb->mem_win_size);
+ memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
+ &sphb->memwindow);
/* On ppc, we only have MMIO no specific IO space from the CPU
* perspective. In theory we ought to be able to embed the PCI IO
@@ -303,42 +543,53 @@ static int spapr_phb_init(SysBusDevice *s)
* system io address space. This hack to bounce things via
* system_io works around the problem until all the users of
* old_portion are updated */
- sprintf(namebuf, "%s.io", phb->dtbusname);
- memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
+ sprintf(namebuf, "%s.io", sphb->dtbusname);
+ memory_region_init(&sphb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
/* FIXME: fix to support multiple PHBs */
- memory_region_add_subregion(get_system_io(), 0, &phb->iospace);
+ memory_region_add_subregion(get_system_io(), 0, &sphb->iospace);
- sprintf(namebuf, "%s.io-alias", phb->dtbusname);
- memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb,
+ sprintf(namebuf, "%s.io-alias", sphb->dtbusname);
+ memory_region_init_io(&sphb->iowindow, &spapr_io_ops, sphb,
namebuf, SPAPR_PCI_IO_WIN_SIZE);
- memory_region_add_subregion(get_system_memory(), phb->io_win_addr,
- &phb->iowindow);
+ memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
+ &sphb->iowindow);
+
+ /* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
+ * we need to allocate some memory to catch those writes coming
+ * from msi_notify()/msix_notify() */
+ if (msi_supported) {
+ sprintf(namebuf, "%s.msi", sphb->dtbusname);
+ memory_region_init_io(&sphb->msiwindow, &spapr_msi_ops, sphb,
+ namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000);
+ memory_region_add_subregion(get_system_memory(), sphb->msi_win_addr,
+ &sphb->msiwindow);
+ }
- bus = pci_register_bus(&phb->busdev.qdev,
- phb->busname ? phb->busname : phb->dtbusname,
- pci_spapr_set_irq, pci_spapr_map_irq, phb,
- &phb->memspace, &phb->iospace,
+ bus = pci_register_bus(DEVICE(s),
+ sphb->busname ? sphb->busname : sphb->dtbusname,
+ pci_spapr_set_irq, pci_spapr_map_irq, sphb,
+ &sphb->memspace, &sphb->iospace,
PCI_DEVFN(0, 0), PCI_NUM_PINS);
- phb->host_state.bus = bus;
+ phb->bus = bus;
- liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16);
- phb->dma = spapr_tce_new_dma_context(liobn, 0x40000000);
- pci_setup_iommu(bus, spapr_pci_dma_context_fn, phb);
+ sphb->dma_liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16);
+ sphb->dma_window_start = 0;
+ sphb->dma_window_size = 0x40000000;
+ sphb->dma = spapr_tce_new_dma_context(sphb->dma_liobn, sphb->dma_window_size);
+ pci_setup_iommu(bus, spapr_pci_dma_context_fn, sphb);
- QLIST_INSERT_HEAD(&spapr->phbs, phb, list);
+ QLIST_INSERT_HEAD(&spapr->phbs, sphb, list);
/* Initialize the LSI table */
for (i = 0; i < PCI_NUM_PINS; i++) {
- qemu_irq qirq;
- uint32_t num;
+ uint32_t irq;
- qirq = spapr_allocate_lsi(0, &num);
- if (!qirq) {
+ irq = spapr_allocate_lsi(0);
+ if (!irq) {
return -1;
}
- phb->lsi_table[i].dt_irq = num;
- phb->lsi_table[i].qirq = qirq;
+ sphb->lsi_table[i].irq = irq;
}
return 0;
@@ -351,6 +602,7 @@ static Property spapr_phb_properties[] = {
DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, 0x20000000),
DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, 0),
DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, 0x10000),
+ DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -361,16 +613,11 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
sdc->init = spapr_phb_init;
dc->props = spapr_phb_properties;
-
- spapr_rtas_register("read-pci-config", rtas_read_pci_config);
- spapr_rtas_register("write-pci-config", rtas_write_pci_config);
- spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
- spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
}
-static TypeInfo spapr_phb_info = {
- .name = "spapr-pci-host-bridge",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo spapr_phb_info = {
+ .name = TYPE_SPAPR_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(sPAPRPHBState),
.class_init = spapr_phb_class_init,
};
@@ -378,11 +625,11 @@ static TypeInfo spapr_phb_info = {
void spapr_create_phb(sPAPREnvironment *spapr,
const char *busname, uint64_t buid,
uint64_t mem_win_addr, uint64_t mem_win_size,
- uint64_t io_win_addr)
+ uint64_t io_win_addr, uint64_t msi_win_addr)
{
DeviceState *dev;
- dev = qdev_create(NULL, spapr_phb_info.name);
+ dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
if (busname) {
qdev_prop_set_string(dev, "busname", g_strdup(busname));
@@ -391,6 +638,7 @@ void spapr_create_phb(sPAPREnvironment *spapr,
qdev_prop_set_uint64(dev, "mem_win_addr", mem_win_addr);
qdev_prop_set_uint64(dev, "mem_win_size", mem_win_size);
qdev_prop_set_uint64(dev, "io_win_addr", io_win_addr);
+ qdev_prop_set_uint64(dev, "msi_win_addr", msi_win_addr);
qdev_init_nofail(dev);
}
@@ -406,9 +654,9 @@ void spapr_create_phb(sPAPREnvironment *spapr,
#define b_fff(x) b_x((x), 8, 3) /* function number */
#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */
-int spapr_populate_pci_devices(sPAPRPHBState *phb,
- uint32_t xics_phandle,
- void *fdt)
+int spapr_populate_pci_dt(sPAPRPHBState *phb,
+ uint32_t xics_phandle,
+ void *fdt)
{
int bus_off, i, j;
char nodename[256];
@@ -477,7 +725,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
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[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq);
irqmap[6] = cpu_to_be32(0x8);
}
}
@@ -485,13 +733,29 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
sizeof(interrupt_map)));
- spapr_dma_dt(fdt, bus_off, "ibm,dma-window", phb->dma);
+ spapr_dma_dt(fdt, bus_off, "ibm,dma-window",
+ phb->dma_liobn, phb->dma_window_start,
+ phb->dma_window_size);
return 0;
}
-static void register_types(void)
+void spapr_pci_rtas_init(void)
+{
+ spapr_rtas_register("read-pci-config", rtas_read_pci_config);
+ spapr_rtas_register("write-pci-config", rtas_write_pci_config);
+ spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
+ spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
+ if (msi_supported) {
+ spapr_rtas_register("ibm,query-interrupt-source-number",
+ rtas_ibm_query_interrupt_source_number);
+ spapr_rtas_register("ibm,change-msi", rtas_ibm_change_msi);
+ }
+}
+
+static void spapr_pci_register_types(void)
{
type_register_static(&spapr_phb_info);
}
-type_init(register_types)
+
+type_init(spapr_pci_register_types)
diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h
index d9e46e2..670dc62 100644
--- a/hw/spapr_pci.h
+++ b/hw/spapr_pci.h
@@ -27,9 +27,15 @@
#include "hw/pci_host.h"
#include "hw/xics.h"
+#define SPAPR_MSIX_MAX_DEVS 32
+
+#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge"
+
+#define SPAPR_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(sPAPRPHBState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE)
+
typedef struct sPAPRPHBState {
- SysBusDevice busdev;
- PCIHostState host_state;
+ PCIHostState parent_obj;
uint64_t buid;
char *busname;
@@ -37,27 +43,44 @@ typedef struct sPAPRPHBState {
MemoryRegion memspace, iospace;
target_phys_addr_t mem_win_addr, mem_win_size, io_win_addr, io_win_size;
- MemoryRegion memwindow, iowindow;
+ target_phys_addr_t msi_win_addr;
+ MemoryRegion memwindow, iowindow, msiwindow;
+
+ uint32_t dma_liobn;
+ uint64_t dma_window_start;
+ uint64_t dma_window_size;
DMAContext *dma;
struct {
- uint32_t dt_irq;
- qemu_irq qirq;
+ uint32_t irq;
} lsi_table[PCI_NUM_PINS];
+ struct {
+ uint32_t config_addr;
+ uint32_t irq;
+ int nvec;
+ } msi_table[SPAPR_MSIX_MAX_DEVS];
+
QLIST_ENTRY(sPAPRPHBState) list;
} sPAPRPHBState;
+static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
+{
+ return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);
+}
+
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
void spapr_create_phb(sPAPREnvironment *spapr,
const char *busname, uint64_t buid,
uint64_t mem_win_addr, uint64_t mem_win_size,
- uint64_t io_win_addr);
+ uint64_t io_win_addr, uint64_t msi_win_addr);
+
+int spapr_populate_pci_dt(sPAPRPHBState *phb,
+ uint32_t xics_phandle,
+ void *fdt);
-int spapr_populate_pci_devices(sPAPRPHBState *phb,
- uint32_t xics_phandle,
- void *fdt);
+void spapr_pci_rtas_init(void);
#endif /* __HW_SPAPR_PCI_H__ */
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 05b5503..7ca4452 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -49,7 +49,7 @@
#endif
static Property spapr_vio_props[] = {
- DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, vio_irq_num, 0), \
+ DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \
DEFINE_PROP_END_OF_LIST(),
};
@@ -132,8 +132,8 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
}
}
- if (dev->qirq) {
- uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
+ if (dev->irq) {
+ uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0};
ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
sizeof(ints_prop));
@@ -142,7 +142,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
}
}
- ret = spapr_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
+ ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
if (ret < 0) {
return ret;
}
@@ -306,7 +306,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
if (dev->signal_state & 1) {
- qemu_irq_pulse(dev->qirq);
+ qemu_irq_pulse(spapr_vio_qirq(dev));
}
return 0;
@@ -459,8 +459,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
dev->qdev.id = id;
}
- dev->qirq = spapr_allocate_msi(dev->vio_irq_num, &dev->vio_irq_num);
- if (!dev->qirq) {
+ dev->irq = spapr_allocate_msi(dev->irq);
+ if (!dev->irq) {
return -1;
}
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 6f9a498..ea6aa43 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -61,8 +61,7 @@ struct VIOsPAPRDevice {
DeviceState qdev;
uint32_t reg;
uint32_t flags;
- qemu_irq qirq;
- uint32_t vio_irq_num;
+ uint32_t irq;
target_ulong signal_state;
VIOsPAPR_CRQ crq;
DMAContext *dma;
@@ -85,6 +84,11 @@ extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
+static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev)
+{
+ return xics_get_qirq(spapr->icp, dev->irq);
+}
+
static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr,
uint32_t size, DMADirection dir)
{
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index 99e52cc..5da17a3 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -26,7 +26,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
if ((dev->in == dev->out) && size) {
/* toggle line to simulate edge interrupt */
- qemu_irq_pulse(dev->sdev.qirq);
+ qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
}
for (i = 0; i < size; i++) {
assert((dev->in - dev->out) < VTERM_BUFSIZE);
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index b0b2e94..b101c51 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -19,7 +19,9 @@
#define DPRINTF(fmt, ...) \
do { printf("ssd0323: " fmt , ## __VA_ARGS__); } while (0)
#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+do { \
+ fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); abort(); \
+} while (0)
#else
#define DPRINTF(fmt, ...) do {} while(0)
#define BADF(fmt, ...) \
diff --git a/hw/stream.c b/hw/stream.c
new file mode 100644
index 0000000..be57e8b
--- /dev/null
+++ b/hw/stream.c
@@ -0,0 +1,23 @@
+#include "stream.h"
+
+void
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app)
+{
+ StreamSlaveClass *k = STREAM_SLAVE_GET_CLASS(sink);
+
+ k->push(sink, buf, len, app);
+}
+
+static TypeInfo stream_slave_info = {
+ .name = TYPE_STREAM_SLAVE,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(StreamSlaveClass),
+};
+
+
+static void stream_slave_register_types(void)
+{
+ type_register_static(&stream_slave_info);
+}
+
+type_init(stream_slave_register_types)
diff --git a/hw/stream.h b/hw/stream.h
new file mode 100644
index 0000000..21123a9
--- /dev/null
+++ b/hw/stream.h
@@ -0,0 +1,31 @@
+#ifndef STREAM_H
+#define STREAM_H 1
+
+#include "qemu-common.h"
+#include "qemu/object.h"
+
+/* stream slave. Used until qdev provides a generic way. */
+#define TYPE_STREAM_SLAVE "stream-slave"
+
+#define STREAM_SLAVE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(StreamSlaveClass, (klass), TYPE_STREAM_SLAVE)
+#define STREAM_SLAVE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(StreamSlaveClass, (obj), TYPE_STREAM_SLAVE)
+#define STREAM_SLAVE(obj) \
+ INTERFACE_CHECK(StreamSlave, (obj), TYPE_STREAM_SLAVE)
+
+typedef struct StreamSlave {
+ Object Parent;
+} StreamSlave;
+
+typedef struct StreamSlaveClass {
+ InterfaceClass parent;
+
+ void (*push)(StreamSlave *obj, unsigned char *buf, size_t len,
+ uint32_t *app);
+} StreamSlaveClass;
+
+void
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app);
+
+#endif /* STREAM_H */
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 137a7c6..07cd042 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -39,6 +39,7 @@
#include "elf.h"
#include "blockdev.h"
#include "exec-memory.h"
+#include "vga-pci.h"
//#define DEBUG_IRQ
//#define DEBUG_EBUS
diff --git a/hw/unicore32/Makefile.objs b/hw/unicore32/Makefile.objs
new file mode 100644
index 0000000..0725ce3
--- /dev/null
+++ b/hw/unicore32/Makefile.objs
@@ -0,0 +1,6 @@
+# For UniCore32 machines and boards
+
+# PKUnity-v3 SoC and board information
+obj-${CONFIG_PUV3} += puv3.o
+
+obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 409bcd4..d1cc680 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -38,8 +38,23 @@
static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
+#define TYPE_UNI_NORTH_PCI_HOST_BRIDGE "uni-north-pci-pcihost"
+#define TYPE_UNI_NORTH_AGP_HOST_BRIDGE "uni-north-agp-pcihost"
+#define TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE "uni-north-internal-pci-pcihost"
+#define TYPE_U3_AGP_HOST_BRIDGE "u3-agp-pcihost"
+
+#define UNI_NORTH_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_PCI_HOST_BRIDGE)
+#define UNI_NORTH_AGP_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_AGP_HOST_BRIDGE)
+#define UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE)
+#define U3_AGP_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(UNINState, (obj), TYPE_U3_AGP_HOST_BRIDGE)
+
typedef struct UNINState {
- PCIHostState host_state;
+ PCIHostState parent_obj;
+
MemoryRegion pci_mmio;
MemoryRegion pci_hole;
} UNINState;
@@ -100,10 +115,11 @@ static void unin_data_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned len)
{
UNINState *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n",
addr, len, val);
- pci_data_write(s->host_state.bus,
- unin_get_config_reg(s->host_state.config_reg, addr),
+ pci_data_write(phb->bus,
+ unin_get_config_reg(phb->config_reg, addr),
val, len);
}
@@ -111,10 +127,11 @@ static uint64_t unin_data_read(void *opaque, target_phys_addr_t addr,
unsigned len)
{
UNINState *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
uint32_t val;
- val = pci_data_read(s->host_state.bus,
- unin_get_config_reg(s->host_state.config_reg, addr),
+ val = pci_data_read(phb->bus,
+ unin_get_config_reg(phb->config_reg, addr),
len);
UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n",
addr, len, val);
@@ -130,19 +147,17 @@ static const MemoryRegionOps unin_data_ops = {
static int pci_unin_main_init_device(SysBusDevice *dev)
{
PCIHostState *h;
- UNINState *s;
/* Use values found on a real PowerMac */
/* Uninorth main bus */
- h = FROM_SYSBUS(PCIHostState, dev);
- s = DO_UPCAST(UNINState, host_state, h);
+ h = PCI_HOST_BRIDGE(dev);
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s,
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&h->data_mem, &unin_data_ops, dev,
"pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ sysbus_init_mmio(dev, &h->conf_mem);
+ sysbus_init_mmio(dev, &h->data_mem);
return 0;
}
@@ -151,18 +166,16 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
static int pci_u3_agp_init_device(SysBusDevice *dev)
{
PCIHostState *h;
- UNINState *s;
/* Uninorth U3 AGP bus */
- h = FROM_SYSBUS(PCIHostState, dev);
- s = DO_UPCAST(UNINState, host_state, h);
+ h = PCI_HOST_BRIDGE(dev);
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s,
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&h->data_mem, &unin_data_ops, dev,
"pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ sysbus_init_mmio(dev, &h->conf_mem);
+ sysbus_init_mmio(dev, &h->data_mem);
return 0;
}
@@ -170,36 +183,32 @@ static int pci_u3_agp_init_device(SysBusDevice *dev)
static int pci_unin_agp_init_device(SysBusDevice *dev)
{
PCIHostState *h;
- UNINState *s;
/* Uninorth AGP bus */
- h = FROM_SYSBUS(PCIHostState, dev);
- s = DO_UPCAST(UNINState, host_state, h);
-
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
- &s->host_state, "pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ h = PCI_HOST_BRIDGE(dev);
+
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&h->data_mem, &pci_host_data_le_ops,
+ dev, "pci-conf-data", 0x1000);
+ sysbus_init_mmio(dev, &h->conf_mem);
+ sysbus_init_mmio(dev, &h->data_mem);
return 0;
}
static int pci_unin_internal_init_device(SysBusDevice *dev)
{
PCIHostState *h;
- UNINState *s;
/* Uninorth internal bus */
- h = FROM_SYSBUS(PCIHostState, dev);
- s = DO_UPCAST(UNINState, host_state, h);
-
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
- &s->host_state, "pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ h = PCI_HOST_BRIDGE(dev);
+
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&h->data_mem, &pci_host_data_le_ops,
+ dev, "pci-conf-data", 0x1000);
+ sysbus_init_mmio(dev, &h->conf_mem);
+ sysbus_init_mmio(dev, &h->data_mem);
return 0;
}
@@ -214,26 +223,26 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
/* Use values found on a real PowerMac */
/* Uninorth main bus */
- dev = qdev_create(NULL, "uni-north-pci-pcihost");
+ dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
- h = FROM_SYSBUS(PCIHostState, s);
- d = DO_UPCAST(UNINState, host_state, h);
+ s = SYS_BUS_DEVICE(dev);
+ h = PCI_HOST_BRIDGE(s);
+ d = UNI_NORTH_PCI_HOST_BRIDGE(dev);
memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
0x80000000ULL, 0x70000000ULL);
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole);
- d->host_state.bus = pci_register_bus(dev, "pci",
- pci_unin_set_irq, pci_unin_map_irq,
- pic,
- &d->pci_mmio,
- address_space_io,
- PCI_DEVFN(11, 0), 4);
+ h->bus = pci_register_bus(dev, "pci",
+ pci_unin_set_irq, pci_unin_map_irq,
+ pic,
+ &d->pci_mmio,
+ address_space_io,
+ PCI_DEVFN(11, 0), 4);
#if 0
- pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north");
+ pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
#endif
sysbus_mmio_map(s, 0, 0xf2800000);
@@ -242,30 +251,30 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
/* DEC 21154 bridge */
#if 0
/* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
- pci_create_simple(d->host_state.bus, PCI_DEVFN(12, 0), "dec-21154");
+ pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154");
#endif
/* Uninorth AGP bus */
- pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north-agp");
- dev = qdev_create(NULL, "uni-north-agp-pcihost");
+ pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-agp");
+ dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
+ s = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(s, 0, 0xf0800000);
sysbus_mmio_map(s, 1, 0xf0c00000);
/* Uninorth internal bus */
#if 0
/* XXX: not needed for now */
- pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0),
+ pci_create_simple(h->bus, PCI_DEVFN(14, 0),
"uni-north-internal-pci");
- dev = qdev_create(NULL, "uni-north-internal-pci-pcihost");
+ dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
+ s = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(s, 0, 0xf4800000);
sysbus_mmio_map(s, 1, 0xf4c00000);
#endif
- return d->host_state.bus;
+ return h->bus;
}
PCIBus *pci_pmac_u3_init(qemu_irq *pic,
@@ -279,11 +288,11 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
/* Uninorth AGP bus */
- dev = qdev_create(NULL, "u3-agp-pcihost");
+ dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
- h = FROM_SYSBUS(PCIHostState, s);
- d = DO_UPCAST(UNINState, host_state, h);
+ s = SYS_BUS_DEVICE(dev);
+ h = PCI_HOST_BRIDGE(dev);
+ d = U3_AGP_HOST_BRIDGE(dev);
memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
@@ -291,19 +300,19 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole);
- d->host_state.bus = pci_register_bus(dev, "pci",
- pci_unin_set_irq, pci_unin_map_irq,
- pic,
- &d->pci_mmio,
- address_space_io,
- PCI_DEVFN(11, 0), 4);
+ h->bus = pci_register_bus(dev, "pci",
+ pci_unin_set_irq, pci_unin_map_irq,
+ pic,
+ &d->pci_mmio,
+ address_space_io,
+ PCI_DEVFN(11, 0), 4);
sysbus_mmio_map(s, 0, 0xf0800000);
sysbus_mmio_map(s, 1, 0xf0c00000);
- pci_create_simple(d->host_state.bus, 11 << 3, "u3-agp");
+ pci_create_simple(h->bus, 11 << 3, "u3-agp");
- return d->host_state.bus;
+ return h->bus;
}
static int unin_main_pci_host_init(PCIDevice *d)
@@ -350,7 +359,7 @@ static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
-static TypeInfo unin_main_pci_host_info = {
+static const TypeInfo unin_main_pci_host_info = {
.name = "uni-north-pci",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -368,7 +377,7 @@ static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
-static TypeInfo u3_agp_pci_host_info = {
+static const TypeInfo u3_agp_pci_host_info = {
.name = "u3-agp",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -386,7 +395,7 @@ static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
-static TypeInfo unin_agp_pci_host_info = {
+static const TypeInfo unin_agp_pci_host_info = {
.name = "uni-north-agp",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -404,7 +413,7 @@ static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
-static TypeInfo unin_internal_pci_host_info = {
+static const TypeInfo unin_internal_pci_host_info = {
.name = "uni-north-internal-pci",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -418,9 +427,9 @@ static void pci_unin_main_class_init(ObjectClass *klass, void *data)
sbc->init = pci_unin_main_init_device;
}
-static TypeInfo pci_unin_main_info = {
- .name = "uni-north-pci-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo pci_unin_main_info = {
+ .name = TYPE_UNI_NORTH_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(UNINState),
.class_init = pci_unin_main_class_init,
};
@@ -432,9 +441,9 @@ static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
sbc->init = pci_u3_agp_init_device;
}
-static TypeInfo pci_u3_agp_info = {
- .name = "u3-agp-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo pci_u3_agp_info = {
+ .name = TYPE_U3_AGP_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(UNINState),
.class_init = pci_u3_agp_class_init,
};
@@ -446,9 +455,9 @@ static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
sbc->init = pci_unin_agp_init_device;
}
-static TypeInfo pci_unin_agp_info = {
- .name = "uni-north-agp-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo pci_unin_agp_info = {
+ .name = TYPE_UNI_NORTH_AGP_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(UNINState),
.class_init = pci_unin_agp_class_init,
};
@@ -460,9 +469,9 @@ static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
sbc->init = pci_unin_internal_init_device;
}
-static TypeInfo pci_unin_internal_info = {
- .name = "uni-north-internal-pci-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo pci_unin_internal_info = {
+ .name = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(UNINState),
.class_init = pci_unin_internal_class_init,
};
diff --git a/hw/usb.h b/hw/usb.h
index 432ccae..b8fceec 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -179,6 +179,7 @@ struct USBEndpoint {
uint8_t ifnum;
int max_packet_size;
bool pipeline;
+ bool halted;
USBDevice *dev;
QTAILQ_HEAD(, USBPacket) queue;
};
@@ -331,6 +332,7 @@ typedef enum USBPacketState {
struct USBPacket {
/* Data fields for use by the driver. */
int pid;
+ uint64_t id;
USBEndpoint *ep;
QEMUIOVector iov;
uint64_t parameter; /* control transfers */
@@ -343,7 +345,7 @@ struct USBPacket {
void usb_packet_init(USBPacket *p);
void usb_packet_set_state(USBPacket *p, USBPacketState state);
void usb_packet_check_state(USBPacket *p, USBPacketState expected);
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep);
+void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id);
void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl);
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 01a7622..2da38e7 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -107,6 +107,7 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
}
usb_packet_copy(p, s->setup_buf, p->iov.size);
+ p->result = 0;
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
s->setup_index = 0;
@@ -381,12 +382,23 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
usb_packet_check_state(p, USB_PACKET_SETUP);
assert(p->ep != NULL);
+ /* Submitting a new packet clears halt */
+ if (p->ep->halted) {
+ assert(QTAILQ_EMPTY(&p->ep->queue));
+ p->ep->halted = false;
+ }
+
if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
ret = usb_process_one(p);
if (ret == USB_RET_ASYNC) {
usb_packet_set_state(p, USB_PACKET_ASYNC);
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
} else {
+ /*
+ * When pipelining is enabled usb-devices must always return async,
+ * otherwise packets can complete out of order!
+ */
+ assert(!p->ep->pipeline);
p->result = ret;
usb_packet_set_state(p, USB_PACKET_COMPLETE);
}
@@ -398,6 +410,20 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
return ret;
}
+static void __usb_packet_complete(USBDevice *dev, USBPacket *p)
+{
+ USBEndpoint *ep = p->ep;
+
+ assert(p->result != USB_RET_ASYNC && p->result != USB_RET_NAK);
+
+ if (p->result < 0) {
+ ep->halted = true;
+ }
+ usb_packet_set_state(p, USB_PACKET_COMPLETE);
+ QTAILQ_REMOVE(&ep->queue, p, queue);
+ dev->port->ops->complete(dev->port, p);
+}
+
/* Notify the controller that an async packet is complete. This should only
be called for packets previously deferred by returning USB_RET_ASYNC from
handle_packet. */
@@ -408,11 +434,9 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
usb_packet_check_state(p, USB_PACKET_ASYNC);
assert(QTAILQ_FIRST(&ep->queue) == p);
- usb_packet_set_state(p, USB_PACKET_COMPLETE);
- QTAILQ_REMOVE(&ep->queue, p, queue);
- dev->port->ops->complete(dev->port, p);
+ __usb_packet_complete(dev, p);
- while (!QTAILQ_EMPTY(&ep->queue)) {
+ while (!ep->halted && !QTAILQ_EMPTY(&ep->queue)) {
p = QTAILQ_FIRST(&ep->queue);
if (p->state == USB_PACKET_ASYNC) {
break;
@@ -424,9 +448,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
break;
}
p->result = ret;
- usb_packet_set_state(p, USB_PACKET_COMPLETE);
- QTAILQ_REMOVE(&ep->queue, p, queue);
- dev->port->ops->complete(dev->port, p);
+ __usb_packet_complete(ep->dev, p);
}
}
@@ -498,10 +520,11 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state)
p->state = state;
}
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep)
+void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id)
{
assert(!usb_packet_is_inflight(p));
assert(p->iov.iov != NULL);
+ p->id = id;
p->pid = pid;
p->ep = ep;
p->result = 0;
diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index 9b02ff4..5a0057a 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -223,7 +223,7 @@ static const USBDescDevice desc_device_high = {
static const USBDesc desc = {
.id = {
.idVendor = 0x46f4, /* CRC16() of "QEMU" */
- .idProduct = 0x0002,
+ .idProduct = 0x0003,
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT,
@@ -424,6 +424,7 @@ static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv)
}
QTAILQ_REMOVE(&uas->requests, req, next);
g_free(req);
+ usb_uas_start_next_transfer(uas);
}
static UASRequest *usb_uas_find_request(UASDevice *uas, uint16_t tag)
@@ -456,7 +457,6 @@ static void usb_uas_scsi_command_complete(SCSIRequest *r,
uint32_t status, size_t resid)
{
UASRequest *req = r->hba_private;
- UASDevice *uas = req->uas;
trace_usb_uas_scsi_complete(req->uas->dev.addr, req->tag, status, resid);
req->complete = true;
@@ -465,7 +465,6 @@ static void usb_uas_scsi_command_complete(SCSIRequest *r,
}
usb_uas_queue_sense(req, status);
scsi_req_unref(req->req);
- usb_uas_start_next_transfer(uas);
}
static void usb_uas_scsi_request_cancelled(SCSIRequest *r)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index b043e7c..017342b 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -575,7 +575,12 @@ static inline void ehci_update_irq(EHCIState *s)
/* flag interrupt condition */
static inline void ehci_raise_irq(EHCIState *s, int intr)
{
- s->usbsts_pending |= intr;
+ if (intr & (USBSTS_PCD | USBSTS_FLR | USBSTS_HSE)) {
+ s->usbsts |= intr;
+ ehci_update_irq(s);
+ } else {
+ s->usbsts_pending |= intr;
+ }
}
/*
@@ -761,15 +766,27 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
return q;
}
+static void ehci_cancel_queue(EHCIQueue *q)
+{
+ EHCIPacket *p;
+
+ p = QTAILQ_FIRST(&q->packets);
+ if (p == NULL) {
+ return;
+ }
+
+ trace_usb_ehci_queue_action(q, "cancel");
+ do {
+ ehci_free_packet(p);
+ } while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
+}
+
static void ehci_free_queue(EHCIQueue *q)
{
EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
- EHCIPacket *p;
trace_usb_ehci_queue_action(q, "free");
- while ((p = QTAILQ_FIRST(&q->packets)) != NULL) {
- ehci_free_packet(p);
- }
+ ehci_cancel_queue(q);
QTAILQ_REMOVE(head, q, next);
g_free(q);
}
@@ -1182,22 +1199,32 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
break;
}
+ /* not supporting dynamic frame list size at the moment */
+ if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
+ fprintf(stderr, "attempt to set frame list size -- value %d\n",
+ val & USBCMD_FLS);
+ val &= ~USBCMD_FLS;
+ }
+
+ if (val & USBCMD_IAAD) {
+ /*
+ * Process IAAD immediately, otherwise the Linux IAAD watchdog may
+ * trigger and re-use a qh without us seeing the unlink.
+ */
+ s->async_stepdown = 0;
+ qemu_bh_schedule(s->async_bh);
+ }
+
if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) !=
((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & s->usbcmd)) {
if (s->pstate == EST_INACTIVE) {
SET_LAST_RUN_CLOCK(s);
}
+ s->usbcmd = val; /* Set usbcmd for ehci_update_halt() */
ehci_update_halt(s);
s->async_stepdown = 0;
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
}
-
- /* not supporting dynamic frame list size at the moment */
- if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
- fprintf(stderr, "attempt to set frame list size -- value %d\n",
- val & USBCMD_FLS);
- val &= ~USBCMD_FLS;
- }
break;
case USBSTS:
@@ -1524,7 +1551,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
ep = usb_ep_get(p->queue->dev, p->pid, endp);
- usb_packet_setup(&p->packet, p->pid, ep);
+ usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr);
usb_packet_map(&p->packet, &p->sgl);
trace_usb_ehci_packet_action(p->queue, p, action);
@@ -1546,7 +1573,8 @@ static int ehci_execute(EHCIPacket *p, const char *action)
*/
static int ehci_process_itd(EHCIState *ehci,
- EHCIitd *itd)
+ EHCIitd *itd,
+ uint32_t addr)
{
USBDevice *dev;
USBEndpoint *ep;
@@ -1591,8 +1619,8 @@ static int ehci_process_itd(EHCIState *ehci,
dev = ehci_find_device(ehci, devaddr);
ep = usb_ep_get(dev, pid, endp);
- if (ep->type == USB_ENDPOINT_XFER_ISOC) {
- usb_packet_setup(&ehci->ipacket, pid, ep);
+ if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
+ usb_packet_setup(&ehci->ipacket, pid, ep, addr);
usb_packet_map(&ehci->ipacket, &ehci->isgl);
ret = usb_handle_packet(dev, &ehci->ipacket);
assert(ret != USB_RET_ASYNC);
@@ -1780,9 +1808,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
if (q->dev != NULL && q->dev->addr != devaddr) {
if (!QTAILQ_EMPTY(&q->packets)) {
/* should not happen (guest bug) */
- while ((p = QTAILQ_FIRST(&q->packets)) != NULL) {
- ehci_free_packet(p);
- }
+ ehci_cancel_queue(q);
}
q->dev = NULL;
}
@@ -1790,11 +1816,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
q->dev = ehci_find_device(q->ehci, devaddr);
}
- if (p && p->async == EHCI_ASYNC_INFLIGHT) {
- /* I/O still in progress -- skip queue */
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
- goto out;
- }
if (p && p->async == EHCI_ASYNC_FINISHED) {
/* I/O finished -- continue processing queue */
trace_usb_ehci_packet_action(p->queue, p, "complete");
@@ -1856,7 +1877,7 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
sizeof(EHCIitd) >> 2);
ehci_trace_itd(ehci, entry, &itd);
- if (ehci_process_itd(ehci, &itd) != 0) {
+ if (ehci_process_itd(ehci, &itd, entry) != 0) {
return -1;
}
@@ -1943,29 +1964,50 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
p = QTAILQ_FIRST(&q->packets);
- while (p != NULL && p->qtdaddr != q->qtdaddr) {
- /* should not happen (guest bug) */
- ehci_free_packet(p);
- p = QTAILQ_FIRST(&q->packets);
- }
if (p != NULL) {
- ehci_qh_do_overlay(q);
- ehci_flush_qh(q);
- if (p->async == EHCI_ASYNC_INFLIGHT) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
+ if (p->qtdaddr != q->qtdaddr ||
+ (!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) ||
+ (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
+ p->qtd.bufptr[0] != qtd.bufptr[0]) {
+ /* guest bug: guest updated active QH or qTD underneath us */
+ ehci_cancel_queue(q);
+ p = NULL;
} else {
+ p->qtd = qtd;
+ ehci_qh_do_overlay(q);
+ }
+ }
+
+ if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
+ if (p != NULL) {
+ /* transfer canceled by guest (clear active) */
+ ehci_cancel_queue(q);
+ p = NULL;
+ }
+ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
+ again = 1;
+ } else if (p != NULL) {
+ switch (p->async) {
+ case EHCI_ASYNC_NONE:
+ /* Previously nacked packet (likely interrupt ep) */
+ ehci_set_state(q->ehci, q->async, EST_EXECUTE);
+ break;
+ case EHCI_ASYNC_INFLIGHT:
+ /* Unfinyshed async handled packet, go horizontal */
+ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
+ break;
+ case EHCI_ASYNC_FINISHED:
+ /* Should never happen, as this case is caught by fetchqh */
ehci_set_state(q->ehci, q->async, EST_EXECUTING);
+ break;
}
again = 1;
- } else if (qtd.token & QTD_TOKEN_ACTIVE) {
+ } else {
p = ehci_alloc_packet(q);
p->qtdaddr = q->qtdaddr;
p->qtd = qtd;
ehci_set_state(q->ehci, q->async, EST_EXECUTE);
again = 1;
- } else {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- again = 1;
}
return again;
@@ -2010,7 +2052,7 @@ static void ehci_fill_queue(EHCIPacket *p)
p->qtdaddr = qtdaddr;
p->qtd = qtd;
p->usb_status = ehci_execute(p, "queue");
- assert(p->usb_status = USB_RET_ASYNC);
+ assert(p->usb_status == USB_RET_ASYNC);
p->async = EHCI_ASYNC_INFLIGHT;
}
}
@@ -2069,19 +2111,11 @@ out:
static int ehci_state_executing(EHCIQueue *q)
{
EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- int again = 0;
assert(p != NULL);
assert(p->qtdaddr == q->qtdaddr);
ehci_execute_complete(q);
- if (p->usb_status == USB_RET_ASYNC) {
- goto out;
- }
- if (p->usb_status == USB_RET_PROCERR) {
- again = -1;
- goto out;
- }
// 4.10.3
if (!q->async) {
@@ -2099,11 +2133,8 @@ static int ehci_state_executing(EHCIQueue *q)
ehci_set_state(q->ehci, q->async, EST_WRITEBACK);
}
- again = 1;
-
-out:
ehci_flush_qh(q);
- return again;
+ return 1;
}
@@ -2132,6 +2163,19 @@ static int ehci_state_writeback(EHCIQueue *q)
* bit is clear.
*/
if (q->qh.token & QTD_TOKEN_HALT) {
+ /*
+ * We should not do any further processing on a halted queue!
+ * This is esp. important for bulk endpoints with pipelining enabled
+ * (redirection to a real USB device), where we must cancel all the
+ * transfers after this one so that:
+ * 1) If they've completed already, they are not processed further
+ * causing more stalls, originating from the same failed transfer
+ * 2) If still in flight, they are cancelled before the guest does
+ * a clear stall, otherwise the guest and device can loose sync!
+ */
+ while ((p = QTAILQ_FIRST(&q->packets)) != NULL) {
+ ehci_free_packet(p);
+ }
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
again = 1;
} else {
@@ -2466,13 +2510,16 @@ static int usb_ehci_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_ehci = {
.name = "ehci",
- .version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 1,
.post_load = usb_ehci_post_load,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, EHCIState),
/* mmio registers */
VMSTATE_UINT32(usbcmd, EHCIState),
VMSTATE_UINT32(usbsts, EHCIState),
+ VMSTATE_UINT32_V(usbsts_pending, EHCIState, 2),
+ VMSTATE_UINT32_V(usbsts_frindex, EHCIState, 2),
VMSTATE_UINT32(usbintr, EHCIState),
VMSTATE_UINT32(frindex, EHCIState),
VMSTATE_UINT32(ctrldssegment, EHCIState),
diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c
index 0e860da..e77e0b2 100644
--- a/hw/usb/hcd-musb.c
+++ b/hw/usb/hcd-musb.c
@@ -627,7 +627,8 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
/* A wild guess on the FADDR semantics... */
dev = usb_find_device(&s->port, ep->faddr[idx]);
uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
- usb_packet_setup(&ep->packey[dir].p, pid, uep);
+ usb_packet_setup(&ep->packey[dir].p, pid, uep,
+ (dev->addr << 16) | (uep->nr << 8) | pid);
usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
ep->packey[dir].ep = ep;
ep->packey[dir].dir = dir;
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index 844e7ed..c36184a 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -812,7 +812,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
} else {
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep);
+ usb_packet_setup(&ohci->usb_packet, pid, ep, addr);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret == USB_RET_ASYNC) {
@@ -1011,7 +1011,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep);
+ usb_packet_setup(&ohci->usb_packet, pid, ep, addr);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
ret = usb_handle_packet(dev, &ohci->usb_packet);
#ifdef DEBUG_PACKET
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 1ace2a4..b0db921 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -748,6 +748,22 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
return TD_RESULT_COMPLETE;
out:
+ /*
+ * We should not do any further processing on a queue with errors!
+ * This is esp. important for bulk endpoints with pipelining enabled
+ * (redirection to a real USB device), where we must cancel all the
+ * transfers after this one so that:
+ * 1) If they've completed already, they are not processed further
+ * causing more stalls, originating from the same failed transfer
+ * 2) If still in flight, they are cancelled before the guest does
+ * a clear stall, otherwise the guest and device can loose sync!
+ */
+ while (!QTAILQ_EMPTY(&async->queue->asyncs)) {
+ UHCIAsync *as = QTAILQ_FIRST(&async->queue->asyncs);
+ uhci_async_unlink(as);
+ uhci_async_cancel(as);
+ }
+
switch(ret) {
case USB_RET_STALL:
td->ctrl |= TD_CTRL_STALL;
@@ -843,14 +859,14 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
* for initial isochronous requests
*/
async->queue->valid = 32;
- async->isoc = td->ctrl & TD_CTRL_IOS;
+ async->isoc = td->ctrl & TD_CTRL_IOS;
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
- usb_packet_setup(&async->packet, pid, ep);
+ usb_packet_setup(&async->packet, pid, ep, addr);
qemu_sglist_add(&async->sgl, td->buffer, max_len);
usb_packet_map(&async->packet, &async->sgl);
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 6c2ff02..3eb27fa 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1392,7 +1392,7 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
ep = usb_ep_get(dev, dir, xfer->epid >> 1);
- usb_packet_setup(&xfer->packet, dir, ep);
+ usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr);
usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length);
DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
xfer->packet.pid, dev->addr, ep->nr);
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index d55be87..8df9207 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -1045,6 +1045,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
/* Note request is (bRequestType << 8) | bRequest */
trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
+ assert(p->result == 0);
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 4fd5d9b..7a92034 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -162,7 +162,7 @@ static int vpb_sic_init(SysBusDevice *dev)
/* Board init. */
/* The AB and PB boards both use the same core, just with different
- peripherans and expansion busses. For now we emulate a subset of the
+ peripherals and expansion busses. For now we emulate a subset of the
PB peripherals and just change the board ID. */
static struct arm_boot_info versatile_binfo;
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 37dc019..9abbada 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -23,8 +23,8 @@
*/
#include "hw.h"
#include "console.h"
-#include "pc.h"
#include "pci.h"
+#include "vga-pci.h"
#include "vga_int.h"
#include "pixel_ops.h"
#include "qemu-timer.h"
diff --git a/hw/vga-pci.h b/hw/vga-pci.h
new file mode 100644
index 0000000..49abf13
--- /dev/null
+++ b/hw/vga-pci.h
@@ -0,0 +1,12 @@
+#ifndef VGA_PCI_H
+#define VGA_PCI_H
+
+#include "qemu-common.h"
+
+/* vga-pci.c */
+DeviceState *pci_vga_init(PCIBus *bus);
+
+/* cirrus_vga.c */
+DeviceState *pci_cirrus_vga_init(PCIBus *bus);
+
+#endif
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index f21757e..6f6d172 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -254,6 +254,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
virtio_blk_req_complete(req, status);
g_free(req);
+ return;
#else
abort();
#endif
@@ -509,9 +510,19 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
blkcfg.size_max = 0;
blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
blkcfg.alignment_offset = 0;
+ blkcfg.wce = bdrv_enable_write_cache(s->bs);
memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
}
+static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+ VirtIOBlock *s = to_virtio_blk(vdev);
+ struct virtio_blk_config blkcfg;
+
+ memcpy(&blkcfg, config, sizeof(blkcfg));
+ bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0);
+}
+
static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
{
VirtIOBlock *s = to_virtio_blk(vdev);
@@ -523,14 +534,27 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
features |= (1 << VIRTIO_BLK_F_SCSI);
if (bdrv_enable_write_cache(s->bs))
- features |= (1 << VIRTIO_BLK_F_WCACHE);
-
+ features |= (1 << VIRTIO_BLK_F_WCE);
+
if (bdrv_is_read_only(s->bs))
features |= 1 << VIRTIO_BLK_F_RO;
return features;
}
+static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
+{
+ VirtIOBlock *s = to_virtio_blk(vdev);
+ uint32_t features;
+
+ if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ return;
+ }
+
+ features = vdev->guest_features;
+ bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
+}
+
static void virtio_blk_save(QEMUFile *f, void *opaque)
{
VirtIOBlock *s = opaque;
@@ -609,7 +633,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk)
sizeof(VirtIOBlock));
s->vdev.get_config = virtio_blk_update_config;
+ s->vdev.set_config = virtio_blk_set_config;
s->vdev.get_features = virtio_blk_get_features;
+ s->vdev.set_status = virtio_blk_set_status;
s->vdev.reset = virtio_blk_reset;
s->bs = blk->conf.bs;
s->conf = &blk->conf;
diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h
index 79ebccc..f0740d0 100644
--- a/hw/virtio-blk.h
+++ b/hw/virtio-blk.h
@@ -31,8 +31,9 @@
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
/* #define VIRTIO_BLK_F_IDENTIFY 8 ATA IDENTIFY supported, DEPRECATED */
-#define VIRTIO_BLK_F_WCACHE 9 /* write cache enabled */
+#define VIRTIO_BLK_F_WCE 9 /* write cache enabled */
#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
+#define VIRTIO_BLK_F_CONFIG_WCE 11 /* write cache configurable */
#define VIRTIO_BLK_ID_BYTES 20 /* ID string length */
@@ -49,6 +50,7 @@ struct virtio_blk_config
uint8_t alignment_offset;
uint16_t min_io_size;
uint32_t opt_io_size;
+ uint8_t wce;
} QEMU_PACKED;
/* These two define direction. */
@@ -102,9 +104,11 @@ struct VirtIOBlkConf
BlockConf conf;
char *serial;
uint32_t scsi;
+ uint32_t config_wce;
};
#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
- DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
+ DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
+ DEFINE_PROP_BIT("config-wce", _state, _field, VIRTIO_BLK_F_CONFIG_WCE, true)
#endif
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 5e6e09e..b3f0710 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -131,6 +131,7 @@ static int virtio_pci_load_config(void * opaque, QEMUFile *f)
if (ret) {
return ret;
}
+ msix_unuse_all_vectors(&proxy->pci_dev);
msix_load(&proxy->pci_dev, f);
if (msix_present(&proxy->pci_dev)) {
qemu_get_be16s(f, &proxy->vdev->config_vector);
@@ -246,6 +247,7 @@ void virtio_pci_reset(DeviceState *d)
VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
virtio_pci_stop_ioeventfd(proxy);
virtio_reset(proxy->vdev);
+ msix_unuse_all_vectors(&proxy->pci_dev);
proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
}
@@ -886,6 +888,7 @@ static Property virtio_blk_properties[] = {
#ifdef __linux__
DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true),
#endif
+ DEFINE_PROP_BIT("config-wce", VirtIOPCIProxy, blk.config_wce, 0, true),
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index c4a5b22..c1b47a8 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -24,11 +24,6 @@
#define VIRTIO_SCSI_MAX_TARGET 255
#define VIRTIO_SCSI_MAX_LUN 16383
-/* Feature Bits */
-#define VIRTIO_SCSI_F_INOUT 0
-#define VIRTIO_SCSI_F_HOTPLUG 1
-#define VIRTIO_SCSI_F_CHANGE 2
-
/* Response codes */
#define VIRTIO_SCSI_S_OK 0
#define VIRTIO_SCSI_S_OVERRUN 1
@@ -305,11 +300,17 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
goto incorrect_lun;
}
QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
- if (r->tag == req->req.tmf->tag) {
+ VirtIOSCSIReq *cmd_req = r->hba_private;
+ if (cmd_req && cmd_req->req.cmd->tag == req->req.tmf->tag) {
break;
}
}
- if (r && r->hba_private) {
+ if (r) {
+ /*
+ * Assert that the request has not been completed yet, we
+ * check for it in the loop above.
+ */
+ assert(r->hba_private);
if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
/* "If the specified command is present in the task set, then
* return a service response set to FUNCTION SUCCEEDED".
@@ -555,8 +556,6 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
uint32_t requested_features)
{
- requested_features |= (1UL << VIRTIO_SCSI_F_HOTPLUG);
- requested_features |= (1UL << VIRTIO_SCSI_F_CHANGE);
return requested_features;
}
diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h
index 4bc889d..91924f6 100644
--- a/hw/virtio-scsi.h
+++ b/hw/virtio-scsi.h
@@ -21,6 +21,11 @@
/* The ID for virtio_scsi */
#define VIRTIO_ID_SCSI 8
+/* Feature Bits */
+#define VIRTIO_SCSI_F_INOUT 0
+#define VIRTIO_SCSI_F_HOTPLUG 1
+#define VIRTIO_SCSI_F_CHANGE 2
+
struct VirtIOSCSIConf {
uint32_t num_queues;
uint32_t max_sectors;
@@ -31,6 +36,8 @@ struct VirtIOSCSIConf {
DEFINE_VIRTIO_COMMON_FEATURES(_state, _features_field), \
DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \
DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF), \
- DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128)
+ DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128), \
+ DEFINE_PROP_BIT("hotplug", _state, _features_field, VIRTIO_SCSI_F_HOTPLUG, true), \
+ DEFINE_PROP_BIT("param_change", _state, _features_field, VIRTIO_SCSI_F_CHANGE, true)
#endif /* _QEMU_VIRTIO_SCSI_H */
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index c1fe984..0d6c2ff 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -87,9 +87,6 @@ static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
{
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
PCI_CLASS_NETWORK_ETHERNET) {
- /* Until qdev_free includes a call to object_unparent, we call it here
- */
- object_unparent(&d->qdev.parent_obj);
qdev_free(&d->qdev);
}
}
diff --git a/hw/xics.c b/hw/xics.c
index 668a0d6..b674771 100644
--- a/hw/xics.c
+++ b/hw/xics.c
@@ -315,18 +315,24 @@ static void ics_eoi(struct ics_state *ics, int nr)
* Exported functions
*/
-qemu_irq xics_assign_irq(struct icp_state *icp, int irq,
- enum xics_irq_type type)
+qemu_irq xics_get_qirq(struct icp_state *icp, int irq)
{
if ((irq < icp->ics->offset)
|| (irq >= (icp->ics->offset + icp->ics->nr_irqs))) {
return NULL;
}
+ return icp->ics->qirqs[irq - icp->ics->offset];
+}
+
+void xics_set_irq_type(struct icp_state *icp, int irq,
+ enum xics_irq_type type)
+{
+ assert((irq >= icp->ics->offset)
+ && (irq < (icp->ics->offset + icp->ics->nr_irqs)));
assert((type == XICS_MSI) || (type == XICS_LSI));
icp->ics->irqs[irq - icp->ics->offset].type = type;
- return icp->ics->qirqs[irq - icp->ics->offset];
}
static target_ulong h_cppr(CPUPPCState *env, sPAPREnvironment *spapr,
diff --git a/hw/xics.h b/hw/xics.h
index 2080159..99b96ac 100644
--- a/hw/xics.h
+++ b/hw/xics.h
@@ -36,8 +36,9 @@ enum xics_irq_type {
XICS_LSI, /* Level-signalled interrupt */
};
-qemu_irq xics_assign_irq(struct icp_state *icp, int irq,
- enum xics_irq_type type);
+qemu_irq xics_get_qirq(struct icp_state *icp, int irq);
+void xics_set_irq_type(struct icp_state *icp, int irq,
+ enum xics_irq_type type);
struct icp_state *xics_system_init(int nr_irqs);
diff --git a/hw/xilinx.h b/hw/xilinx.h
index 7df21eb..556c5aa 100644
--- a/hw/xilinx.h
+++ b/hw/xilinx.h
@@ -1,3 +1,4 @@
+#include "stream.h"
#include "qemu-common.h"
#include "net.h"
@@ -49,8 +50,8 @@ xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
}
static inline DeviceState *
-xilinx_axiethernet_create(void *dmach,
- NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
+xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer,
+ target_phys_addr_t base, qemu_irq irq,
int txmem, int rxmem)
{
DeviceState *dev;
@@ -60,7 +61,7 @@ xilinx_axiethernet_create(void *dmach,
qdev_set_nic_properties(dev, nd);
qdev_prop_set_uint32(dev, "rxmem", rxmem);
qdev_prop_set_uint32(dev, "txmem", txmem);
- qdev_prop_set_ptr(dev, "dmach", dmach);
+ object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
qdev_init_nofail(dev);
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
@@ -68,21 +69,16 @@ xilinx_axiethernet_create(void *dmach,
return dev;
}
-static inline DeviceState *
-xilinx_axiethernetdma_create(void *dmach,
- target_phys_addr_t base, qemu_irq irq,
- qemu_irq irq2, int freqhz)
+static inline void
+xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer,
+ target_phys_addr_t base, qemu_irq irq,
+ qemu_irq irq2, int freqhz)
{
- DeviceState *dev = NULL;
-
- dev = qdev_create(NULL, "xlnx.axi-dma");
qdev_prop_set_uint32(dev, "freqhz", freqhz);
- qdev_prop_set_ptr(dev, "dmach", dmach);
+ object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
qdev_init_nofail(dev);
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
sysbus_connect_irq(sysbus_from_qdev(dev), 1, irq2);
-
- return dev;
}
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index f4bec37..0e28c51 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -29,7 +29,7 @@
#include "qemu-log.h"
#include "qdev-addr.h"
-#include "xilinx_axidma.h"
+#include "stream.h"
#define D(x)
@@ -77,7 +77,7 @@ enum {
SDESC_STATUS_COMPLETE = (1 << 31)
};
-struct AXIStream {
+struct Stream {
QEMUBH *bh;
ptimer_state *ptimer;
qemu_irq irq;
@@ -94,9 +94,9 @@ struct XilinxAXIDMA {
SysBusDevice busdev;
MemoryRegion iomem;
uint32_t freqhz;
- void *dmach;
+ StreamSlave *tx_dev;
- struct AXIStream streams[2];
+ struct Stream streams[2];
};
/*
@@ -113,27 +113,27 @@ static inline int stream_desc_eof(struct SDesc *d)
return d->control & SDESC_CTRL_EOF;
}
-static inline int stream_resetting(struct AXIStream *s)
+static inline int stream_resetting(struct Stream *s)
{
return !!(s->regs[R_DMACR] & DMACR_RESET);
}
-static inline int stream_running(struct AXIStream *s)
+static inline int stream_running(struct Stream *s)
{
return s->regs[R_DMACR] & DMACR_RUNSTOP;
}
-static inline int stream_halted(struct AXIStream *s)
+static inline int stream_halted(struct Stream *s)
{
return s->regs[R_DMASR] & DMASR_HALTED;
}
-static inline int stream_idle(struct AXIStream *s)
+static inline int stream_idle(struct Stream *s)
{
return !!(s->regs[R_DMASR] & DMASR_IDLE);
}
-static void stream_reset(struct AXIStream *s)
+static void stream_reset(struct Stream *s)
{
s->regs[R_DMASR] = DMASR_HALTED; /* starts up halted. */
s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold. */
@@ -159,7 +159,7 @@ static void stream_desc_show(struct SDesc *d)
}
#endif
-static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr)
+static void stream_desc_load(struct Stream *s, target_phys_addr_t addr)
{
struct SDesc *d = &s->desc;
int i;
@@ -176,7 +176,7 @@ static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr)
}
}
-static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr)
+static void stream_desc_store(struct Stream *s, target_phys_addr_t addr)
{
struct SDesc *d = &s->desc;
int i;
@@ -192,7 +192,7 @@ static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr)
cpu_physical_memory_write(addr, (void *) d, sizeof *d);
}
-static void stream_update_irq(struct AXIStream *s)
+static void stream_update_irq(struct Stream *s)
{
unsigned int pending, mask, irq;
@@ -204,7 +204,7 @@ static void stream_update_irq(struct AXIStream *s)
qemu_set_irq(s->irq, !!irq);
}
-static void stream_reload_complete_cnt(struct AXIStream *s)
+static void stream_reload_complete_cnt(struct Stream *s)
{
unsigned int comp_th;
comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
@@ -213,14 +213,14 @@ static void stream_reload_complete_cnt(struct AXIStream *s)
static void timer_hit(void *opaque)
{
- struct AXIStream *s = opaque;
+ struct Stream *s = opaque;
stream_reload_complete_cnt(s);
s->regs[R_DMASR] |= DMASR_DLY_IRQ;
stream_update_irq(s);
}
-static void stream_complete(struct AXIStream *s)
+static void stream_complete(struct Stream *s)
{
unsigned int comp_delay;
@@ -240,8 +240,8 @@ static void stream_complete(struct AXIStream *s)
}
}
-static void stream_process_mem2s(struct AXIStream *s,
- struct XilinxDMAConnection *dmach)
+static void stream_process_mem2s(struct Stream *s,
+ StreamSlave *tx_dev)
{
uint32_t prev_d;
unsigned char txbuf[16 * 1024];
@@ -276,7 +276,7 @@ static void stream_process_mem2s(struct AXIStream *s,
s->pos += txlen;
if (stream_desc_eof(&s->desc)) {
- xlx_dma_push_to_client(dmach, txbuf, s->pos, app);
+ stream_push(tx_dev, txbuf, s->pos, app);
s->pos = 0;
stream_complete(s);
}
@@ -295,7 +295,7 @@ static void stream_process_mem2s(struct AXIStream *s,
}
}
-static void stream_process_s2mem(struct AXIStream *s,
+static void stream_process_s2mem(struct Stream *s,
unsigned char *buf, size_t len, uint32_t *app)
{
uint32_t prev_d;
@@ -351,11 +351,11 @@ static void stream_process_s2mem(struct AXIStream *s,
}
}
-static
-void axidma_push(void *opaque, unsigned char *buf, size_t len, uint32_t *app)
+static void
+axidma_push(StreamSlave *obj, unsigned char *buf, size_t len, uint32_t *app)
{
- struct XilinxAXIDMA *d = opaque;
- struct AXIStream *s = &d->streams[1];
+ struct XilinxAXIDMA *d = FROM_SYSBUS(typeof(*d), SYS_BUS_DEVICE(obj));
+ struct Stream *s = &d->streams[1];
if (!app) {
hw_error("No stream app data!\n");
@@ -368,7 +368,7 @@ static uint64_t axidma_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
struct XilinxAXIDMA *d = opaque;
- struct AXIStream *s;
+ struct Stream *s;
uint32_t r = 0;
int sid;
@@ -403,7 +403,7 @@ static void axidma_write(void *opaque, target_phys_addr_t addr,
uint64_t value, unsigned size)
{
struct XilinxAXIDMA *d = opaque;
- struct AXIStream *s;
+ struct Stream *s;
int sid;
sid = streamid_from_addr(addr);
@@ -440,7 +440,7 @@ static void axidma_write(void *opaque, target_phys_addr_t addr,
s->regs[addr] = value;
s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle. */
if (!sid) {
- stream_process_mem2s(s, d->dmach);
+ stream_process_mem2s(s, d->tx_dev);
}
break;
default:
@@ -466,12 +466,6 @@ static int xilinx_axidma_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->streams[0].irq);
sysbus_init_irq(dev, &s->streams[1].irq);
- if (!s->dmach) {
- hw_error("Unconnected DMA channel.\n");
- }
-
- xlx_dma_connect_dma(s->dmach, s, axidma_push);
-
memory_region_init_io(&s->iomem, &axidma_ops, s,
"xlnx.axi-dma", R_MAX * 4 * 2);
sysbus_init_mmio(dev, &s->iomem);
@@ -486,9 +480,16 @@ static int xilinx_axidma_init(SysBusDevice *dev)
return 0;
}
+static void xilinx_axidma_initfn(Object *obj)
+{
+ struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+
+ object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
+ (Object **) &s->tx_dev, NULL);
+}
+
static Property axidma_properties[] = {
DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
- DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
DEFINE_PROP_END_OF_LIST(),
};
@@ -496,9 +497,11 @@ static void axidma_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
k->init = xilinx_axidma_init;
dc->props = axidma_properties;
+ ssc->push = axidma_push;
}
static TypeInfo axidma_info = {
@@ -506,6 +509,11 @@ static TypeInfo axidma_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct XilinxAXIDMA),
.class_init = axidma_class_init,
+ .instance_init = xilinx_axidma_initfn,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_STREAM_SLAVE },
+ { }
+ }
};
static void xilinx_axidma_register_types(void)
diff --git a/hw/xilinx_axidma.h b/hw/xilinx_axidma.h
deleted file mode 100644
index 37cb6f0..0000000
--- a/hw/xilinx_axidma.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* AXI DMA connection. Used until qdev provides a generic way. */
-typedef void (*DMAPushFn)(void *opaque,
- unsigned char *buf, size_t len, uint32_t *app);
-
-struct XilinxDMAConnection {
- void *dma;
- void *client;
-
- DMAPushFn to_dma;
- DMAPushFn to_client;
-};
-
-static inline void xlx_dma_connect_client(struct XilinxDMAConnection *dmach,
- void *c, DMAPushFn f)
-{
- dmach->client = c;
- dmach->to_client = f;
-}
-
-static inline void xlx_dma_connect_dma(struct XilinxDMAConnection *dmach,
- void *d, DMAPushFn f)
-{
- dmach->dma = d;
- dmach->to_dma = f;
-}
-
-static inline
-void xlx_dma_push_to_dma(struct XilinxDMAConnection *dmach,
- uint8_t *buf, size_t len, uint32_t *app)
-{
- dmach->to_dma(dmach->dma, buf, len, app);
-}
-static inline
-void xlx_dma_push_to_client(struct XilinxDMAConnection *dmach,
- uint8_t *buf, size_t len, uint32_t *app)
-{
- dmach->to_client(dmach->client, buf, len, app);
-}
-
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index 9b08c62..eec155d 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -28,7 +28,7 @@
#include "net.h"
#include "net/checksum.h"
-#include "xilinx_axidma.h"
+#include "stream.h"
#define DPHY(x)
@@ -310,7 +310,7 @@ struct XilinxAXIEnet {
SysBusDevice busdev;
MemoryRegion iomem;
qemu_irq irq;
- void *dmach;
+ StreamSlave *tx_dev;
NICState *nic;
NICConf conf;
@@ -772,7 +772,7 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
/* Good frame. */
app[2] |= 1 << 6;
- xlx_dma_push_to_dma(s->dmach, (void *)s->rxmem, size, app);
+ stream_push(s->tx_dev, (void *)s->rxmem, size, app);
s->regs[R_IS] |= IS_RX_COMPLETE;
enet_update_irq(s);
@@ -788,9 +788,9 @@ static void eth_cleanup(NetClientState *nc)
}
static void
-axienet_stream_push(void *opaque, uint8_t *buf, size_t size, uint32_t *hdr)
+axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr)
{
- struct XilinxAXIEnet *s = opaque;
+ struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
/* TX enable ? */
if (!(s->tc & TC_TX)) {
@@ -844,12 +844,6 @@ static int xilinx_enet_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq);
- if (!s->dmach) {
- hw_error("Unconnected Xilinx Ethernet MAC.\n");
- }
-
- xlx_dma_connect_client(s->dmach, s, axienet_stream_push);
-
memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000);
sysbus_init_mmio(dev, &s->iomem);
@@ -869,11 +863,18 @@ static int xilinx_enet_init(SysBusDevice *dev)
return 0;
}
+static void xilinx_enet_initfn(Object *obj)
+{
+ struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+
+ object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
+ (Object **) &s->tx_dev, NULL);
+}
+
static Property xilinx_enet_properties[] = {
DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
DEFINE_PROP_UINT32("rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
DEFINE_PROP_UINT32("txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
- DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -882,9 +883,11 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
k->init = xilinx_enet_init;
dc->props = xilinx_enet_properties;
+ ssc->push = axienet_stream_push;
}
static TypeInfo xilinx_enet_info = {
@@ -892,6 +895,11 @@ static TypeInfo xilinx_enet_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct XilinxAXIEnet),
.class_init = xilinx_enet_class_init,
+ .instance_init = xilinx_enet_initfn,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_STREAM_SLAVE },
+ { }
+ }
};
static void xilinx_enet_register_types(void)