aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2011-04-01 15:15:26 +1100
committerAlexander Graf <agraf@suse.de>2011-04-01 18:34:56 +0200
commit00dc738d8a08fce0f0d327e081bb2bd7b6fba888 (patch)
tree01f3616328994f4680cb6dd0bc1cc9aa3e6f9858
parentb5cec4c5f294ca3af24e7edf4f37cc2de0ae0e03 (diff)
Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts
This patch adds infrastructure to support interrupts from PAPR virtual IO devices. This includes correctly advertising those interrupts in the device tree, and implementing the H_VIO_SIGNAL hypercall, used to enable and disable individual device interrupts. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de>
-rw-r--r--hw/spapr.c2
-rw-r--r--hw/spapr_vio.c37
-rw-r--r--hw/spapr_vio.h6
3 files changed, 44 insertions, 1 deletions
diff --git a/hw/spapr.c b/hw/spapr.c
index b5aefd72c3..200617bc7c 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -65,7 +65,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
uint32_t start_prop = cpu_to_be32(initrd_base);
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
- char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr";
+ char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt";
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
int i;
char *modelname;
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 10acb4c308..605079cda5 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -105,6 +105,16 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
}
}
+ if (dev->qirq) {
+ uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
+
+ ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
+ sizeof(ints_prop));
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
if (info->devnode) {
ret = (info->devnode)(dev, fdt, node_off);
if (ret < 0) {
@@ -140,6 +150,30 @@ void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
qdev_register(&info->qdev);
}
+static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ target_ulong reg = args[0];
+ target_ulong mode = args[1];
+ VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ VIOsPAPRDeviceInfo *info;
+
+ if (!dev) {
+ return H_PARAMETER;
+ }
+
+ info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+
+ if (mode & ~info->signal_mask) {
+ return H_PARAMETER;
+ }
+
+ dev->signal_state = mode;
+
+ return H_SUCCESS;
+}
+
VIOsPAPRBus *spapr_vio_bus_init(void)
{
VIOsPAPRBus *bus;
@@ -156,6 +190,9 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
+ /* hcall-vio */
+ spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
+
for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index b164ad326c..8a000c6fe5 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -24,6 +24,9 @@
typedef struct VIOsPAPRDevice {
DeviceState qdev;
uint32_t reg;
+ qemu_irq qirq;
+ uint32_t vio_irq_num;
+ target_ulong signal_state;
} VIOsPAPRDevice;
typedef struct VIOsPAPRBus {
@@ -33,6 +36,7 @@ typedef struct VIOsPAPRBus {
typedef struct {
DeviceInfo qdev;
const char *dt_name, *dt_type, *dt_compatible;
+ target_ulong signal_mask;
int (*init)(VIOsPAPRDevice *dev);
void (*hcalls)(VIOsPAPRBus *bus);
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
@@ -43,6 +47,8 @@ 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);
+extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
+
void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
void spapr_vty_create(VIOsPAPRBus *bus,
uint32_t reg, CharDriverState *chardev);