diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/intc/s390_flic_kvm.c | 2 | ||||
-rw-r--r-- | hw/s390x/css.c | 9 | ||||
-rw-r--r-- | hw/s390x/event-facility.c | 55 | ||||
-rw-r--r-- | hw/s390x/s390-virtio-ccw.c | 75 | ||||
-rw-r--r-- | hw/s390x/s390-virtio.c | 30 | ||||
-rw-r--r-- | hw/s390x/s390-virtio.h | 1 | ||||
-rw-r--r-- | hw/s390x/sclp.c | 267 | ||||
-rw-r--r-- | hw/s390x/sclpcpu.c | 28 | ||||
-rw-r--r-- | hw/s390x/sclpquiesce.c | 4 |
9 files changed, 281 insertions, 190 deletions
diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index b471e7a..48714f9 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -228,6 +228,8 @@ static int kvm_s390_add_adapter_routes(S390FLICState *fs, routes->gsi[i] = ret; routes->adapter.ind_offset++; } + kvm_irqchip_commit_routes(kvm_state); + /* Restore passed-in structure to original state. */ routes->adapter.ind_offset = ind_offset; return 0; diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 5df450e..c033612 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -261,6 +261,9 @@ static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1) ret.flags = tmp0.flags; ret.count = be16_to_cpu(tmp0.count); ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16); + if ((ret.cmd_code & 0x0f) == CCW_CMD_TIC) { + ret.cmd_code &= 0x0f; + } } return ret; } @@ -287,6 +290,10 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr) ((ccw.cmd_code & 0xf0) != 0)) { return -EINVAL; } + if (!sch->ccw_fmt_1 && (ccw.count == 0) && + (ccw.cmd_code != CCW_CMD_TIC)) { + return -EINVAL; + } if (ccw.flags & CCW_FLAG_SUSPEND) { return -EINPROGRESS; @@ -392,6 +399,8 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb) path = 0x80; if (!(s->ctrl & SCSW_ACTL_SUSP)) { + s->cstat = 0; + s->dstat = 0; /* Look at the orb and try to execute the channel program. */ assert(orb != NULL); /* resume does not pass an orb */ p->intparm = orb->intparm; diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 0c700ef..ef2a051 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -27,12 +27,12 @@ typedef struct SCLPEventsBus { struct SCLPEventFacility { SysBusDevice parent_obj; SCLPEventsBus sbus; + SCLPEvent quiesce_event; + SCLPEvent cpu_hotplug_event; /* guest' receive mask */ unsigned int receive_mask; }; -static SCLPEvent cpu_hotplug; - /* return true if any child has event pending set */ static bool event_pending(SCLPEventFacility *ef) { @@ -240,12 +240,13 @@ static void read_event_data(SCLPEventFacility *ef, SCCB *sccb) sclp_active_selection_mask = sclp_cp_receive_mask; break; case SCLP_SELECTIVE_READ: - if (!(sclp_cp_receive_mask & be32_to_cpu(red->mask))) { + sclp_active_selection_mask = be32_to_cpu(red->mask); + if (!sclp_cp_receive_mask || + (sclp_active_selection_mask & ~sclp_cp_receive_mask)) { sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK); goto out; } - sclp_active_selection_mask = be32_to_cpu(red->mask); break; default: sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION); @@ -286,8 +287,26 @@ out: #define TYPE_SCLP_EVENTS_BUS "s390-sclp-events-bus" +static void sclp_events_bus_realize(BusState *bus, Error **errp) +{ + BusChild *kid; + + /* TODO: recursive realization has to be done in common code */ + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + + object_property_set_bool(OBJECT(dev), true, "realized", errp); + if (*errp) { + return; + } + } +} + static void sclp_events_bus_class_init(ObjectClass *klass, void *data) { + BusClass *bc = BUS_CLASS(klass); + + bc->realize = sclp_events_bus_realize; } static const TypeInfo sclp_events_bus_info = { @@ -324,26 +343,24 @@ static const VMStateDescription vmstate_event_facility = { } }; -static int init_event_facility(SCLPEventFacility *event_facility) +static void init_event_facility(Object *obj) { - DeviceState *sdev = DEVICE(event_facility); - DeviceState *quiesce; + SCLPEventFacility *event_facility = EVENT_FACILITY(obj); + DeviceState *sdev = DEVICE(obj); /* Spawn a new bus for SCLP events */ qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus), TYPE_SCLP_EVENTS_BUS, sdev, NULL); - quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce"); - if (!quiesce) { - return -1; - } - qdev_init_nofail(quiesce); - - object_initialize(&cpu_hotplug, sizeof(cpu_hotplug), TYPE_SCLP_CPU_HOTPLUG); - qdev_set_parent_bus(DEVICE(&cpu_hotplug), BUS(&event_facility->sbus)); - object_property_set_bool(OBJECT(&cpu_hotplug), true, "realized", NULL); - - return 0; + object_initialize(&event_facility->quiesce_event, sizeof(SCLPEvent), + TYPE_SCLP_QUIESCE); + qdev_set_parent_bus(DEVICE(&event_facility->quiesce_event), + &event_facility->sbus.qbus); + object_initialize(&event_facility->cpu_hotplug_event, sizeof(SCLPEvent), + TYPE_SCLP_CPU_HOTPLUG); + qdev_set_parent_bus(DEVICE(&event_facility->cpu_hotplug_event), + &event_facility->sbus.qbus); + /* the facility will automatically realize the devices via the bus */ } static void reset_event_facility(DeviceState *dev) @@ -362,7 +379,6 @@ static void init_event_facility_class(ObjectClass *klass, void *data) dc->reset = reset_event_facility; dc->vmsd = &vmstate_event_facility; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - k->init = init_event_facility; k->command_handler = command_handler; k->event_pending = event_pending; } @@ -370,6 +386,7 @@ static void init_event_facility_class(ObjectClass *klass, void *data) static const TypeInfo sclp_event_facility_info = { .name = TYPE_SCLP_EVENT_FACILITY, .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = init_event_facility, .instance_size = sizeof(SCLPEventFacility), .class_init = init_event_facility_class, .class_size = sizeof(SCLPEventFacilityClass), diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index e2a26e9..27a8360 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -100,57 +100,31 @@ static void virtio_ccw_register_hcalls(void) virtio_ccw_hcall_early_printk); } -static void ccw_init(MachineState *machine) +void s390_memory_init(ram_addr_t mem_size) { - ram_addr_t my_ram_size = machine->ram_size; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - sclpMemoryHotplugDev *mhd = init_sclp_memory_hotplug_dev(); + + /* allocate RAM for core */ + memory_region_init_ram(ram, NULL, "s390.ram", mem_size, &error_abort); + vmstate_register_ram_global(ram); + memory_region_add_subregion(sysmem, 0, ram); + + /* Initialize storage key device */ + s390_skeys_init(); +} + +static void ccw_init(MachineState *machine) +{ int ret; VirtualCssBus *css_bus; DeviceState *dev; - QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory"), NULL); - ram_addr_t pad_size = 0; - ram_addr_t maxmem = qemu_opt_get_size(opts, "maxmem", my_ram_size); - ram_addr_t standby_mem_size = maxmem - my_ram_size; - uint64_t kvm_limit; - - /* The storage increment size is a multiple of 1M and is a power of 2. - * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer. - * The variable 'mhd->increment_size' is an exponent of 2 that can be - * used to calculate the size (in bytes) of an increment. */ - mhd->increment_size = 20; - while ((my_ram_size >> mhd->increment_size) > MAX_STORAGE_INCREMENTS) { - mhd->increment_size++; - } - while ((standby_mem_size >> mhd->increment_size) > MAX_STORAGE_INCREMENTS) { - mhd->increment_size++; - } - /* The core and standby memory areas need to be aligned with - * the increment size. In effect, this can cause the - * user-specified memory size to be rounded down to align - * with the nearest increment boundary. */ - standby_mem_size = standby_mem_size >> mhd->increment_size - << mhd->increment_size; - my_ram_size = my_ram_size >> mhd->increment_size - << mhd->increment_size; - - /* let's propagate the changed ram size into the global variable. */ - ram_size = my_ram_size; - machine->maxram_size = my_ram_size + standby_mem_size; - - ret = s390_set_memory_limit(machine->maxram_size, &kvm_limit); - if (ret == -E2BIG) { - hw_error("qemu: host supports a maximum of %" PRIu64 " GB", - kvm_limit >> 30); - } else if (ret) { - hw_error("qemu: setting the guest size failed"); - } + s390_sclp_init(); + s390_memory_init(machine->ram_size); /* get a BUS */ css_bus = virtual_css_bus_init(); - s390_sclp_init(); s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, machine->initrd_filename, "s390-ccw.img", true); s390_flic_init(); @@ -163,25 +137,6 @@ static void ccw_init(MachineState *machine) /* register hypercalls */ virtio_ccw_register_hcalls(); - /* allocate RAM for core */ - memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size, &error_abort); - vmstate_register_ram_global(ram); - memory_region_add_subregion(sysmem, 0, ram); - - /* If the size of ram is not on a MEM_SECTION_SIZE boundary, - calculate the pad size necessary to force this boundary. */ - if (standby_mem_size) { - if (my_ram_size % MEM_SECTION_SIZE) { - pad_size = MEM_SECTION_SIZE - my_ram_size % MEM_SECTION_SIZE; - } - my_ram_size += standby_mem_size + pad_size; - mhd->pad_size = pad_size; - mhd->standby_mem_size = standby_mem_size; - } - - /* Initialize storage key device */ - s390_skeys_init(); - /* init CPUs */ s390_init_cpus(machine->cpu_model); diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index 6cc6b5d..e4000c9 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -23,6 +23,7 @@ #include "hw/hw.h" #include "qapi/qmp/qerror.h" +#include "qemu/error-report.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" @@ -260,30 +261,20 @@ int gtod_load(QEMUFile *f, void *opaque, int version_id) /* PC hardware initialisation */ static void s390_init(MachineState *machine) { - ram_addr_t my_ram_size = machine->ram_size; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - int increment_size = 20; + ram_addr_t my_ram_size; void *virtio_region; hwaddr virtio_region_len; hwaddr virtio_region_start; - /* - * The storage increment size is a multiple of 1M and is a power of 2. - * The number of storage increments must be MAX_STORAGE_INCREMENTS or - * fewer. - */ - while ((my_ram_size >> increment_size) > MAX_STORAGE_INCREMENTS) { - increment_size++; + if (machine->ram_slots) { + error_report("Memory hotplug not supported by the selected machine."); + exit(EXIT_FAILURE); } - my_ram_size = my_ram_size >> increment_size << increment_size; - - /* let's propagate the changed ram size into the global variable. */ - ram_size = my_ram_size; + s390_sclp_init(); + my_ram_size = machine->ram_size; /* get a BUS */ s390_bus = s390_virtio_bus_init(&my_ram_size); - s390_sclp_init(); s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, machine->initrd_filename, ZIPL_FILENAME, false); s390_flic_init(); @@ -292,9 +283,7 @@ static void s390_init(MachineState *machine) s390_virtio_register_hcalls(); /* allocate RAM */ - memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size, &error_abort); - vmstate_register_ram_global(ram); - memory_region_add_subregion(sysmem, 0, ram); + s390_memory_init(my_ram_size); /* clear virtio region */ virtio_region_len = my_ram_size - ram_size; @@ -305,9 +294,6 @@ static void s390_init(MachineState *machine) cpu_physical_memory_unmap(virtio_region, virtio_region_len, 1, virtio_region_len); - /* Initialize storage key device */ - s390_skeys_init(); - /* init CPUs */ s390_init_cpus(machine->cpu_model); diff --git a/hw/s390x/s390-virtio.h b/hw/s390x/s390-virtio.h index cf68796..f389aa1 100644 --- a/hw/s390x/s390-virtio.h +++ b/hw/s390x/s390-virtio.h @@ -27,4 +27,5 @@ void s390_init_ipl_dev(const char *kernel_filename, bool enforce_bios); void s390_create_virtio_net(BusState *bus, const char *name); void s390_nmi(NMIState *n, int cpu_index, Error **errp); +void s390_memory_init(ram_addr_t mem_size); #endif diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index b3a6c5e..fd277e1 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -17,37 +17,27 @@ #include "exec/memory.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" -#include "qemu/config-file.h" +#include "hw/boards.h" #include "hw/s390x/sclp.h" #include "hw/s390x/event-facility.h" #include "hw/s390x/s390-pci-bus.h" -static inline SCLPEventFacility *get_event_facility(void) +static inline SCLPDevice *get_sclp_device(void) { - ObjectProperty *op = object_property_find(qdev_get_machine(), - TYPE_SCLP_EVENT_FACILITY, - NULL); - assert(op); - return op->opaque; + return SCLP(object_resolve_path_type("", TYPE_SCLP, NULL)); } /* Provide information about the configuration, CPUs and storage */ -static void read_SCP_info(SCCB *sccb) +static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) { ReadInfo *read_info = (ReadInfo *) sccb; + MachineState *machine = MACHINE(qdev_get_machine()); sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); CPUState *cpu; int cpu_count = 0; int i = 0; - int increment_size = 20; int rnsize, rnmax; - QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory"), NULL); - int slots = qemu_opt_get_number(opts, "slots", 0); - int max_avail_slots = s390_get_memslot_count(kvm_state); - - if (slots > max_avail_slots) { - slots = max_avail_slots; - } + int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state)); CPU_FOREACH(cpu) { cpu_count++; @@ -66,23 +56,8 @@ static void read_SCP_info(SCCB *sccb) read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO | SCLP_HAS_PCI_RECONFIG); - /* - * The storage increment size is a multiple of 1M and is a power of 2. - * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer. - */ - while ((ram_size >> increment_size) > MAX_STORAGE_INCREMENTS) { - increment_size++; - } - rnmax = ram_size >> increment_size; - /* Memory Hotplug is only supported for the ccw machine type */ if (mhd) { - while ((mhd->standby_mem_size >> increment_size) > - MAX_STORAGE_INCREMENTS) { - increment_size++; - } - assert(increment_size == mhd->increment_size); - mhd->standby_subregion_size = MEM_SECTION_SIZE; /* Deduct the memory slot already used for core */ if (slots > 0) { @@ -108,13 +83,11 @@ static void read_SCP_info(SCCB *sccb) } mhd->padded_ram_size = ram_size + mhd->pad_size; mhd->rzm = 1 << mhd->increment_size; - rnmax = ((ram_size + mhd->standby_mem_size + mhd->pad_size) - >> mhd->increment_size); read_info->facilities |= cpu_to_be64(SCLP_FC_ASSIGN_ATTACH_READ_STOR); } - rnsize = 1 << (increment_size - 20); + rnsize = 1 << (sclp->increment_size - 20); if (rnsize <= 128) { read_info->rnsize = rnsize; } else { @@ -122,6 +95,7 @@ static void read_SCP_info(SCCB *sccb) read_info->rnsize2 = cpu_to_be32(rnsize); } + rnmax = machine->maxram_size >> sclp->increment_size; if (rnmax < 0x10000) { read_info->rnmax = cpu_to_be16(rnmax); } else { @@ -132,14 +106,17 @@ static void read_SCP_info(SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); } -static void read_storage_element0_info(SCCB *sccb) +static void read_storage_element0_info(SCLPDevice *sclp, SCCB *sccb) { int i, assigned; int subincrement_id = SCLP_STARTING_SUBINCREMENT_ID; ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - assert(mhd); + if (!mhd) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + return; + } if ((ram_size >> mhd->increment_size) >= 0x10000) { sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); @@ -158,12 +135,15 @@ static void read_storage_element0_info(SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); } -static void read_storage_element1_info(SCCB *sccb) +static void read_storage_element1_info(SCLPDevice *sclp, SCCB *sccb) { ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - assert(mhd); + if (!mhd) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + return; + } if ((mhd->standby_mem_size >> mhd->increment_size) >= 0x10000) { sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); @@ -179,13 +159,17 @@ static void read_storage_element1_info(SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_STANDBY_READ_COMPLETION); } -static void attach_storage_element(SCCB *sccb, uint16_t element) +static void attach_storage_element(SCLPDevice *sclp, SCCB *sccb, + uint16_t element) { int i, assigned, subincrement_id; AttachStorageElement *attach_info = (AttachStorageElement *) sccb; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - assert(mhd); + if (!mhd) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + return; + } if (element != 1) { sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); @@ -203,20 +187,26 @@ static void attach_storage_element(SCCB *sccb, uint16_t element) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION); } -static void assign_storage(SCCB *sccb) +static void assign_storage(SCLPDevice *sclp, SCCB *sccb) { MemoryRegion *mr = NULL; uint64_t this_subregion_size; AssignStorage *assign_info = (AssignStorage *) sccb; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - assert(mhd); - ram_addr_t assign_addr = (assign_info->rn - 1) * mhd->rzm; + ram_addr_t assign_addr; MemoryRegion *sysmem = get_system_memory(); + if (!mhd) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + return; + } + assign_addr = (assign_info->rn - 1) * mhd->rzm; + if ((assign_addr % MEM_SECTION_SIZE == 0) && (assign_addr >= mhd->padded_ram_size)) { /* Re-use existing memory region if found */ mr = memory_region_find(sysmem, assign_addr, 1).mr; + memory_region_unref(mr); if (!mr) { MemoryRegion *standby_ram = g_new(MemoryRegion, 1); @@ -242,6 +232,11 @@ static void assign_storage(SCCB *sccb) } memory_region_init_ram(standby_ram, NULL, id, this_subregion_size, &error_abort); + /* This is a hack to make memory hotunplug work again. Once we have + * subdevices, we have to unparent them when unassigning memory, + * instead of doing it via the ref count of the MemoryRegion. */ + object_ref(OBJECT(standby_ram)); + object_unparent(OBJECT(standby_ram)); vmstate_register_ram_global(standby_ram); memory_region_add_subregion(sysmem, offset, standby_ram); } @@ -252,15 +247,20 @@ static void assign_storage(SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION); } -static void unassign_storage(SCCB *sccb) +static void unassign_storage(SCLPDevice *sclp, SCCB *sccb) { MemoryRegion *mr = NULL; AssignStorage *assign_info = (AssignStorage *) sccb; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - assert(mhd); - ram_addr_t unassign_addr = (assign_info->rn - 1) * mhd->rzm; + ram_addr_t unassign_addr; MemoryRegion *sysmem = get_system_memory(); + if (!mhd) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + return; + } + unassign_addr = (assign_info->rn - 1) * mhd->rzm; + /* if the addr is a multiple of 256 MB */ if ((unassign_addr % MEM_SECTION_SIZE == 0) && (unassign_addr >= mhd->padded_ram_size)) { @@ -269,6 +269,7 @@ static void unassign_storage(SCCB *sccb) /* find the specified memory region and destroy it */ mr = memory_region_find(sysmem, unassign_addr, 1).mr; + memory_region_unref(mr); if (mr) { int i; int is_removable = 1; @@ -287,8 +288,7 @@ static void unassign_storage(SCCB *sccb) } if (is_removable) { memory_region_del_subregion(sysmem, mr); - object_unparent(OBJECT(mr)); - g_free(mr); + object_unref(OBJECT(mr)); } } } @@ -296,7 +296,7 @@ static void unassign_storage(SCCB *sccb) } /* Provide information about the CPU */ -static void sclp_read_cpu_info(SCCB *sccb) +static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) { ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb; CPUState *cpu; @@ -323,34 +323,35 @@ static void sclp_read_cpu_info(SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); } -static void sclp_execute(SCCB *sccb, uint32_t code) +static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code) { - SCLPEventFacility *ef = get_event_facility(); + SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); + SCLPEventFacility *ef = sclp->event_facility; SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef); switch (code & SCLP_CMD_CODE_MASK) { case SCLP_CMDW_READ_SCP_INFO: case SCLP_CMDW_READ_SCP_INFO_FORCED: - read_SCP_info(sccb); + sclp_c->read_SCP_info(sclp, sccb); break; case SCLP_CMDW_READ_CPU_INFO: - sclp_read_cpu_info(sccb); + sclp_c->read_cpu_info(sclp, sccb); break; case SCLP_READ_STORAGE_ELEMENT_INFO: if (code & 0xff00) { - read_storage_element1_info(sccb); + sclp_c->read_storage_element1_info(sclp, sccb); } else { - read_storage_element0_info(sccb); + sclp_c->read_storage_element0_info(sclp, sccb); } break; case SCLP_ATTACH_STORAGE_ELEMENT: - attach_storage_element(sccb, (code & 0xff00) >> 8); + sclp_c->attach_storage_element(sclp, sccb, (code & 0xff00) >> 8); break; case SCLP_ASSIGN_STORAGE: - assign_storage(sccb); + sclp_c->assign_storage(sclp, sccb); break; case SCLP_UNASSIGN_STORAGE: - unassign_storage(sccb); + sclp_c->unassign_storage(sclp, sccb); break; case SCLP_CMDW_CONFIGURE_PCI: s390_pci_sclp_configure(1, sccb); @@ -366,6 +367,8 @@ static void sclp_execute(SCCB *sccb, uint32_t code) int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) { + SCLPDevice *sclp = get_sclp_device(); + SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); int r = 0; SCCB work_sccb; @@ -400,20 +403,20 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) goto out; } - sclp_execute((SCCB *)&work_sccb, code); + sclp_c->execute(sclp, (SCCB *)&work_sccb, code); cpu_physical_memory_write(sccb, &work_sccb, be16_to_cpu(work_sccb.h.length)); - sclp_service_interrupt(sccb); + sclp_c->service_interrupt(sclp, sccb); out: return r; } -void sclp_service_interrupt(uint32_t sccb) +static void service_interrupt(SCLPDevice *sclp, uint32_t sccb) { - SCLPEventFacility *ef = get_event_facility(); + SCLPEventFacility *ef = sclp->event_facility; SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef); uint32_t param = sccb & ~3; @@ -428,17 +431,148 @@ void sclp_service_interrupt(uint32_t sccb) s390_sclp_extint(param); } +void sclp_service_interrupt(uint32_t sccb) +{ + SCLPDevice *sclp = get_sclp_device(); + SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); + + sclp_c->service_interrupt(sclp, sccb); +} + /* qemu object creation and initialization functions */ void s390_sclp_init(void) { - DeviceState *dev = qdev_create(NULL, TYPE_SCLP_EVENT_FACILITY); + Object *new = object_new(TYPE_SCLP); - object_property_add_child(qdev_get_machine(), TYPE_SCLP_EVENT_FACILITY, - OBJECT(dev), NULL); - qdev_init_nofail(dev); + object_property_add_child(qdev_get_machine(), TYPE_SCLP, new, + NULL); + object_unref(OBJECT(new)); + qdev_init_nofail(DEVICE(new)); +} + +static void sclp_realize(DeviceState *dev, Error **errp) +{ + MachineState *machine = MACHINE(qdev_get_machine()); + SCLPDevice *sclp = SCLP(dev); + Error *l_err = NULL; + uint64_t hw_limit; + int ret; + + object_property_set_bool(OBJECT(sclp->event_facility), true, "realized", + &l_err); + if (l_err) { + goto error; + } + + ret = s390_set_memory_limit(machine->maxram_size, &hw_limit); + if (ret == -E2BIG) { + error_setg(&l_err, "qemu: host supports a maximum of %" PRIu64 " GB", + hw_limit >> 30); + goto error; + } else if (ret) { + error_setg(&l_err, "qemu: setting the guest size failed"); + goto error; + } + return; +error: + assert(l_err); + error_propagate(errp, l_err); +} + +static void sclp_memory_init(SCLPDevice *sclp) +{ + MachineState *machine = MACHINE(qdev_get_machine()); + ram_addr_t initial_mem = machine->ram_size; + ram_addr_t max_mem = machine->maxram_size; + ram_addr_t standby_mem = max_mem - initial_mem; + ram_addr_t pad_mem = 0; + int increment_size = 20; + + /* The storage increment size is a multiple of 1M and is a power of 2. + * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer. + * The variable 'increment_size' is an exponent of 2 that can be + * used to calculate the size (in bytes) of an increment. */ + while ((initial_mem >> increment_size) > MAX_STORAGE_INCREMENTS) { + increment_size++; + } + if (machine->ram_slots) { + while ((standby_mem >> increment_size) > MAX_STORAGE_INCREMENTS) { + increment_size++; + } + } + sclp->increment_size = increment_size; + + /* The core and standby memory areas need to be aligned with + * the increment size. In effect, this can cause the + * user-specified memory size to be rounded down to align + * with the nearest increment boundary. */ + initial_mem = initial_mem >> increment_size << increment_size; + standby_mem = standby_mem >> increment_size << increment_size; + + /* If the size of ram is not on a MEM_SECTION_SIZE boundary, + calculate the pad size necessary to force this boundary. */ + if (machine->ram_slots && standby_mem) { + sclpMemoryHotplugDev *mhd = init_sclp_memory_hotplug_dev(); + + if (initial_mem % MEM_SECTION_SIZE) { + pad_mem = MEM_SECTION_SIZE - initial_mem % MEM_SECTION_SIZE; + } + mhd->increment_size = increment_size; + mhd->pad_size = pad_mem; + mhd->standby_mem_size = standby_mem; + } + machine->ram_size = initial_mem; + machine->maxram_size = initial_mem + pad_mem + standby_mem; + /* let's propagate the changed ram size into the global variable. */ + ram_size = initial_mem; +} + +static void sclp_init(Object *obj) +{ + SCLPDevice *sclp = SCLP(obj); + Object *new; + + new = object_new(TYPE_SCLP_EVENT_FACILITY); + object_property_add_child(obj, TYPE_SCLP_EVENT_FACILITY, new, NULL); + /* qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS */ + qdev_set_parent_bus(DEVICE(new), sysbus_get_default()); + object_unref(new); + sclp->event_facility = EVENT_FACILITY(new); + + sclp_memory_init(sclp); } +static void sclp_class_init(ObjectClass *oc, void *data) +{ + SCLPDeviceClass *sc = SCLP_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->desc = "SCLP (Service-Call Logical Processor)"; + dc->realize = sclp_realize; + dc->hotpluggable = false; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + sc->read_SCP_info = read_SCP_info; + sc->read_storage_element0_info = read_storage_element0_info; + sc->read_storage_element1_info = read_storage_element1_info; + sc->attach_storage_element = attach_storage_element; + sc->assign_storage = assign_storage; + sc->unassign_storage = unassign_storage; + sc->read_cpu_info = sclp_read_cpu_info; + sc->execute = sclp_execute; + sc->service_interrupt = service_interrupt; +} + +static TypeInfo sclp_info = { + .name = TYPE_SCLP, + .parent = TYPE_DEVICE, + .instance_init = sclp_init, + .instance_size = sizeof(SCLPDevice), + .class_init = sclp_class_init, + .class_size = sizeof(SCLPDeviceClass), +}; + sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void) { DeviceState *dev; @@ -475,5 +609,6 @@ static TypeInfo sclp_memory_hotplug_dev_info = { static void register_types(void) { type_register_static(&sclp_memory_hotplug_dev_info); + type_register_static(&sclp_info); } type_init(register_types); diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c index 2fe8b5a..322eb31 100644 --- a/hw/s390x/sclpcpu.c +++ b/hw/s390x/sclpcpu.c @@ -25,13 +25,16 @@ typedef struct ConfigMgtData { uint8_t event_qualifier; } QEMU_PACKED ConfigMgtData; -static qemu_irq *irq_cpu_hotplug; /* Only used in this file */ - #define EVENT_QUAL_CPU_CHANGE 1 void raise_irq_cpu_hotplug(void) { - qemu_irq_raise(*irq_cpu_hotplug); + Object *obj = object_resolve_path_type("", TYPE_SCLP_CPU_HOTPLUG, NULL); + + SCLP_EVENT(obj)->event_pending = true; + + /* Trigger SCLP read operation */ + sclp_service_interrupt(0); } static unsigned int send_mask(void) @@ -70,36 +73,19 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, return 1; } -static void trigger_signal(void *opaque, int n, int level) -{ - SCLPEvent *event = opaque; - event->event_pending = true; - - /* Trigger SCLP read operation */ - sclp_service_interrupt(0); -} - -static int irq_cpu_hotplug_init(SCLPEvent *event) -{ - irq_cpu_hotplug = qemu_allocate_irqs(trigger_signal, event, 1); - return 0; -} - static void cpu_class_init(ObjectClass *oc, void *data) { SCLPEventClass *k = SCLP_EVENT_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); - k->init = irq_cpu_hotplug_init; k->get_send_mask = send_mask; k->get_receive_mask = receive_mask; k->read_event_data = read_event_data; - k->write_event_data = NULL; set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo sclp_cpu_info = { - .name = "sclp-cpu-hotplug", + .name = TYPE_SCLP_CPU_HOTPLUG, .parent = TYPE_SCLP_EVENT, .instance_size = sizeof(SCLPEvent), .class_init = cpu_class_init, diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index ffa5553..15b06e1 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -66,7 +66,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, } static const VMStateDescription vmstate_sclpquiesce = { - .name = "sclpquiesce", + .name = TYPE_SCLP_QUIESCE, .version_id = 0, .minimum_version_id = 0, .fields = (VMStateField[]) { @@ -127,7 +127,7 @@ static void quiesce_class_init(ObjectClass *klass, void *data) } static const TypeInfo sclp_quiesce_info = { - .name = "sclpquiesce", + .name = TYPE_SCLP_QUIESCE, .parent = TYPE_SCLP_EVENT, .instance_size = sizeof(SCLPEvent), .class_init = quiesce_class_init, |