[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 15/15] Implement the bus structure for PAPR virtual
From: |
David Gibson |
Subject: |
[Qemu-devel] [PATCH 15/15] Implement the bus structure for PAPR virtual IO |
Date: |
Sun, 13 Feb 2011 01:54:27 +1100 |
This extends the "pseries" (PAPR) machine to include a virtual IO bus
supporting the PAPR defined hypercall based virtual IO mechanisms.
So far only one VIO device is provided, the vty / vterm, providing
a full console (polled only, for now).
Signed-off-by: David Gibson <address@hidden>
---
Makefile.target | 3 +-
hw/spapr.c | 31 +++++++++-
hw/spapr.h | 10 +++
hw/spapr_hcall.c | 19 ++----
hw/spapr_vio.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/spapr_vio.h | 49 ++++++++++++++
hw/spapr_vty.c | 132 +++++++++++++++++++++++++++++++++++++
7 files changed, 419 insertions(+), 16 deletions(-)
create mode 100644 hw/spapr_vio.c
create mode 100644 hw/spapr_vio.h
create mode 100644 hw/spapr_vty.c
diff --git a/Makefile.target b/Makefile.target
index e0796ba..fe232da 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -232,7 +232,8 @@ obj-ppc-y += ppc_oldworld.o
# NewWorld PowerMac
obj-ppc-y += ppc_newworld.o
# IBM pSeries (sPAPR)
-obj-ppc-y += spapr.o spapr_hcall.o
+obj-ppc-y += spapr.o spapr_hcall.o spapr_vio.o
+obj-ppc-y += spapr_vty.o
# PowerPC 4xx boards
obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
obj-ppc-y += ppc440.o ppc440_bamboo.o
diff --git a/hw/spapr.c b/hw/spapr.c
index 8aca4e0..da61061 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -37,6 +37,7 @@
#include "net.h"
#include "blockdev.h"
#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
#include <libfdt.h>
@@ -49,6 +50,7 @@
static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
const char *cpu_model, CPUState *envs[],
+ sPAPREnvironment *spapr,
target_phys_addr_t initrd_base,
target_phys_addr_t initrd_size,
const char *kernel_cmdline)
@@ -59,6 +61,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t
ramsize,
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
int i;
char *modelname;
+ int ret;
#define _FDT(exp) \
do { \
@@ -151,9 +154,28 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t
ramsize,
_FDT((fdt_end_node(fdt)));
+ /* vdevice */
+ _FDT((fdt_begin_node(fdt, "vdevice")));
+
+ _FDT((fdt_property_string(fdt, "device_type", "vdevice")));
+ _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
+ _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
+ _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+
+ _FDT((fdt_end_node(fdt)));
+
_FDT((fdt_end_node(fdt))); /* close root node */
_FDT((fdt_finish(fdt)));
+ /* re-expand to allow for further tweaks */
+ _FDT((fdt_open_into(fdt, fdt, FDT_MAX_SIZE)));
+
+ ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
+ if (ret < 0)
+ fprintf(stderr, "couldn't setup vio devices in fdt\n");
+
+ _FDT((fdt_pack(fdt)));
+
if (fdt_size)
*fdt_size = fdt_totalsize(fdt);
@@ -211,6 +233,12 @@ static void ppc_spapr_init (ram_addr_t ram_size,
ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size);
cpu_register_physical_memory(0, ram_size, ram_offset);
+ spapr->vio_bus = spapr_vio_bus_init();
+
+ for (i = 0; i < MAX_SERIAL_PORTS; i++)
+ if (serial_hds[i])
+ spapr_vty_create(spapr->vio_bus, i, serial_hds[i]);
+
if (kernel_filename) {
uint64_t lowaddr = 0;
@@ -242,7 +270,7 @@ static void ppc_spapr_init (ram_addr_t ram_size,
}
/* load fdt */
- fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, &env,
+ fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, &env, spapr,
initrd_base, initrd_size,
kernel_cmdline);
if (!fdt) {
@@ -267,6 +295,7 @@ static QEMUMachine spapr_machine = {
.desc = "pSeries Logical Partition (PAPR compliant)",
.init = ppc_spapr_init,
.max_cpus = 1,
+ .no_parallel = 1,
.no_vga = 1,
.no_parallel = 1,
};
diff --git a/hw/spapr.h b/hw/spapr.h
index dae9617..168511f 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -1,7 +1,10 @@
#if !defined (__HW_SPAPR_H__)
#define __HW_SPAPR_H__
+struct VIOsPAPRBus;
+
typedef struct sPAPREnvironment {
+ struct VIOsPAPRBus *vio_bus;
} sPAPREnvironment;
#define H_SUCCESS 0
@@ -237,4 +240,11 @@ typedef struct sPAPREnvironment {
target_ulong spapr_hypercall(CPUState *env, sPAPREnvironment *spapr,
target_ulong token, target_ulong *args);
+target_ulong h_put_term_char(sPAPREnvironment *spapr,
+ target_ulong termno, target_ulong len,
+ target_ulong char0_7, target_ulong char8_15);
+target_ulong h_get_term_char(sPAPREnvironment *spapr,
+ target_ulong termno, target_ulong *len,
+ target_ulong *char0_7, target_ulong *char8_15);
+
#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index c99c345..e2ed9cf 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -3,19 +3,6 @@
#include "qemu-char.h"
#include "hw/spapr.h"
-static target_ulong h_put_term_char(target_ulong termno, target_ulong len,
- target_ulong char0_7, target_ulong
char8_15)
-{
- uint8_t buf[16];
-
- *((uint64_t *)buf) = cpu_to_be64(char0_7);
- *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
-
- qemu_chr_write(serial_hds[0], buf, len);
-
- return 0;
-}
-
target_ulong spapr_hypercall(CPUState *env, sPAPREnvironment *spapr,
target_ulong token, target_ulong *args)
{
@@ -29,7 +16,11 @@ target_ulong spapr_hypercall(CPUState *env, sPAPREnvironment
*spapr,
switch (token) {
case H_PUT_TERM_CHAR:
- r = h_put_term_char(args[0], args[1], args[2], args[3]);
+ r = h_put_term_char(spapr, args[0], args[1], args[2], args[3]);
+ break;
+
+ case H_GET_TERM_CHAR:
+ r = h_get_term_char(spapr, args[0], &args[0], &args[1], &args[2]);
break;
default:
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
new file mode 100644
index 0000000..d9c7292
--- /dev/null
+++ b/hw/spapr_vio.c
@@ -0,0 +1,191 @@
+/*
+ * QEMU sPAPR VIO code
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <address@hidden>
+ * Based on the s390 virtio bus code:
+ * Copyright (c) 2009 Alexander Graf <address@hidden>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "monitor.h"
+#include "loader.h"
+#include "elf.h"
+#include "hw/sysbus.h"
+#include "kvm.h"
+#include "device_tree.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#ifdef CONFIG_FDT
+#include <libfdt.h>
+#endif /* CONFIG_FDT */
+
+/* #define DEBUG_SPAPR */
+
+#ifdef DEBUG_SPAPR
+#define dprintf(fmt, ...) \
+ do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+ do { } while (0)
+#endif
+
+struct BusInfo spapr_vio_bus_info = {
+ .name = "spapr-vio",
+ .size = sizeof(VIOsPAPRBus),
+};
+
+VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
+{
+ DeviceState *qdev;
+ VIOsPAPRDevice *dev = NULL;
+
+ QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+ dev = (VIOsPAPRDevice *)qdev;
+ if (dev->reg == reg)
+ break;
+ }
+
+ return dev;
+}
+
+VIOsPAPRBus *spapr_vio_bus_init(void)
+{
+ VIOsPAPRBus *bus;
+ BusState *_bus;
+ DeviceState *dev;
+
+ /* Create bridge device */
+ dev = qdev_create(NULL, "spapr-vio-bridge");
+ qdev_init_nofail(dev);
+
+ /* Create bus on bridge device */
+
+ _bus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
+ bus = DO_UPCAST(VIOsPAPRBus, bus, _bus);
+
+ return bus;
+}
+
+#ifdef CONFIG_FDT
+static int vio_make_devnode(VIOsPAPRDevice *dev,
+ void *fdt)
+{
+ VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+ int vdevice_off, node_off;
+ int ret;
+
+ vdevice_off = fdt_path_offset(fdt, "/vdevice");
+ if (vdevice_off < 0)
+ return vdevice_off;
+
+ node_off = fdt_add_subnode(fdt, vdevice_off, dev->qdev.id);
+ if (node_off < 0)
+ return node_off;
+
+ ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
+ if (ret < 0)
+ return ret;
+
+ if (info->dt_type) {
+ ret = fdt_setprop_string(fdt, node_off, "device_type",
+ info->dt_type);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (info->dt_compatible) {
+ ret = fdt_setprop_string(fdt, node_off, "compatible",
+ info->dt_compatible);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (info->devnode) {
+ ret = (info->devnode)(dev, fdt, node_off);
+ if (ret < 0)
+ return ret;
+ }
+
+ return node_off;
+}
+#endif /* CONFIG_FDT */
+
+static int spapr_vio_busdev_init(DeviceState *dev, DeviceInfo *info)
+{
+ VIOsPAPRDeviceInfo *_info = (VIOsPAPRDeviceInfo *)info;
+ VIOsPAPRDevice *_dev = (VIOsPAPRDevice *)dev;
+ char *id;
+
+ if (asprintf(&id, "address@hidden", _info->dt_name, _dev->reg) < 0)
+ return -1;
+
+ _dev->qdev.id = id;
+
+ return _info->init(_dev);
+}
+
+void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
+{
+ info->qdev.init = spapr_vio_busdev_init;
+ info->qdev.bus_info = &spapr_vio_bus_info;
+
+ assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
+ qdev_register(&info->qdev);
+}
+
+static int spapr_vio_bridge_init(SysBusDevice *dev)
+{
+ /* nothing */
+ return 0;
+}
+
+static SysBusDeviceInfo spapr_vio_bridge_info = {
+ .init = spapr_vio_bridge_init,
+ .qdev.name = "spapr-vio-bridge",
+ .qdev.size = sizeof(SysBusDevice),
+ .qdev.no_user = 1,
+};
+
+static void spapr_vio_register_devices(void)
+{
+ sysbus_register_withprop(&spapr_vio_bridge_info);
+}
+
+device_init(spapr_vio_register_devices)
+
+#ifdef CONFIG_FDT
+
+int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
+{
+ DeviceState *qdev;
+ int ret = 0;
+
+ QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+ VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+
+ ret = vio_make_devnode(dev, fdt);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_FDT */
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
new file mode 100644
index 0000000..fb5e301
--- /dev/null
+++ b/hw/spapr_vio.h
@@ -0,0 +1,49 @@
+#ifndef _HW_SPAPR_VIO_H
+#define _HW_SPAPR_VIO_H
+/*
+ * QEMU sPAPR VIO bus definitions
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <address@hidden>
+ * Based on the s390 virtio bus definitions:
+ * Copyright (c) 2009 Alexander Graf <address@hidden>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+typedef struct VIOsPAPRDevice {
+ DeviceState qdev;
+ uint32_t reg;
+} VIOsPAPRDevice;
+
+typedef struct VIOsPAPRBus {
+ BusState bus;
+} VIOsPAPRBus;
+
+typedef struct {
+ DeviceInfo qdev;
+ const char *dt_name, *dt_type, *dt_compatible;
+ int (*init)(VIOsPAPRDevice *dev);
+ int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
+} VIOsPAPRDeviceInfo;
+
+extern VIOsPAPRBus *spapr_vio_bus_init(void);
+extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
+extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
+extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
+
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
+void spapr_vty_create(VIOsPAPRBus *bus,
+ uint32_t reg, CharDriverState *chardev);
+
+#endif /* _HW_SPAPR_VIO_H */
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
new file mode 100644
index 0000000..9a2dc0b
--- /dev/null
+++ b/hw/spapr_vty.c
@@ -0,0 +1,132 @@
+#include "qdev.h"
+#include "qemu-char.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#define VTERM_BUFSIZE 16
+
+typedef struct VIOsPAPRVTYDevice {
+ VIOsPAPRDevice sdev;
+ CharDriverState *chardev;
+ uint32_t in, out;
+ uint8_t buf[VTERM_BUFSIZE];
+} VIOsPAPRVTYDevice;
+
+static int vty_can_receive(void *opaque)
+{
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+
+ return (dev->in - dev->out) < VTERM_BUFSIZE;
+}
+
+static void vty_receive(void *opaque, const uint8_t *buf, int size)
+{
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ assert((dev->in - dev->out) < VTERM_BUFSIZE);
+ dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
+ }
+}
+
+static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
+{
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+ int n = 0;
+
+ while ((n < max) && (dev->out != dev->in))
+ buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
+
+ return n;
+}
+
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
+{
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+ /* FIXME: should check the qemu_chr_write() return value */
+ qemu_chr_write(dev->chardev, buf, len);
+}
+
+static int spapr_vty_init(VIOsPAPRDevice *sdev)
+{
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+ qemu_chr_add_handlers(dev->chardev, vty_can_receive,
+ vty_receive, NULL, dev);
+
+ return 0;
+}
+
+target_ulong h_put_term_char(sPAPREnvironment *spapr,
+ target_ulong termno, target_ulong len,
+ target_ulong char0_7, target_ulong char8_15)
+{
+ VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, termno);
+ uint8_t buf[16];
+
+ if (!sdev)
+ return H_PARAMETER;
+
+ if (len > 16)
+ return H_PARAMETER;
+
+ *((uint64_t *)buf) = cpu_to_be64(char0_7);
+ *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
+
+ vty_putchars(sdev, buf, len);
+
+ return 0;
+}
+
+target_ulong h_get_term_char(sPAPREnvironment *spapr,
+ target_ulong termno, target_ulong *len,
+ target_ulong *char0_7, target_ulong *char8_15)
+{
+ VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, termno);
+ uint8_t buf[16];
+
+ if (!sdev)
+ return H_PARAMETER;
+
+ *len = vty_getchars(sdev, buf, sizeof(buf));
+ if (*len < 16)
+ memset(buf + *len, 0, 16 - *len);
+
+ *char0_7 = be64_to_cpu(*((uint64_t *)buf));
+ *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
+
+ return H_SUCCESS;
+}
+
+void spapr_vty_create(VIOsPAPRBus *bus,
+ uint32_t reg, CharDriverState *chardev)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(&bus->bus, "spapr-vty");
+ qdev_prop_set_uint32(dev, "reg", reg);
+ qdev_prop_set_chr(dev, "chardev", chardev);
+ qdev_init_nofail(dev);
+}
+
+static VIOsPAPRDeviceInfo spapr_vty = {
+ .init = spapr_vty_init,
+ .dt_name = "vty",
+ .dt_type = "serial",
+ .dt_compatible = "hvterm1",
+ .qdev.name = "spapr-vty",
+ .qdev.size = sizeof(VIOsPAPRVTYDevice),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0),
+ DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
+static void spapr_vty_register(void)
+{
+ spapr_vio_bus_register_withprop(&spapr_vty);
+}
+device_init(spapr_vty_register);
--
1.7.1
- Re: [Qemu-devel] Re: [PATCH 12/15] Support 1T segments on ppc, (continued)
[Qemu-devel] [PATCH 13/15] Add POWER7 support for ppc, David Gibson, 2011/02/12
[Qemu-devel] [PATCH 14/15] Start implementing pSeries logical partition machine, David Gibson, 2011/02/12
[Qemu-devel] [PATCH 15/15] Implement the bus structure for PAPR virtual IO,
David Gibson <=
- [Qemu-devel] Re: [PATCH 15/15] Implement the bus structure for PAPR virtual IO, Alexander Graf, 2011/02/12
- [Qemu-devel] Re: [PATCH 15/15] Implement the bus structure for PAPR virtual IO, Blue Swirl, 2011/02/12
- [Qemu-devel] Re: [PATCH 15/15] Implement the bus structure for PAPR virtual IO, Benjamin Herrenschmidt, 2011/02/12
- [Qemu-devel] Re: [PATCH 15/15] Implement the bus structure for PAPR virtual IO, Blue Swirl, 2011/02/12
- [Qemu-devel] Re: [PATCH 15/15] Implement the bus structure for PAPR virtual IO, Benjamin Herrenschmidt, 2011/02/12
- [Qemu-devel] Re: [PATCH 15/15] Implement the bus structure for PAPR virtual IO, Blue Swirl, 2011/02/13
- Re: [Qemu-devel] Re: [PATCH 15/15] Implement the bus structure for PAPR virtual IO, David Gibson, 2011/02/13
- Re: [Qemu-devel] Re: [PATCH 15/15] Implement the bus structure for PAPR virtual IO, Blue Swirl, 2011/02/13
- Re: [Qemu-devel] Re: [PATCH 15/15] Implement the bus structure for PAPR virtual IO, Benjamin Herrenschmidt, 2011/02/13
- Re: [Qemu-devel] Re: [PATCH 15/15] Implement the bus structure for PAPR virtual IO, Anthony Liguori, 2011/02/13