s390x fixes and improvements:

- various bugfixes (css/event-facility)
 - more efficient adapter interrupt routes setup
 - gdb enhancement
 - sclp got treated with a lot of remodelling/cleanup
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJV7aJjAAoJEN7Pa5PG8C+v1fgQALFLDq1zNaq4/mZkYLMqaFnt
 nRQsZLzecxHJAVKdFBc5QlCBSRCFjSRLeLeiULu8UkREFO+iZ1HhdnwlTB83cs/3
 iHuz+NzJI1C++ATIzqGJpZSXZgYqftar7LKAANwpwjSkANOytrs/m7Y31UYl4zkT
 MgfAD0AYWITrOEyefMSXkPL4ddY0otzx7d9az16sIbarSlkItoNj/AVFVmKfPIFa
 8cI54YNG582L4gWavC2HGNC95Fau8/oZhNzFAprerIOdCx0bqE5Pmlkohz6AJg+U
 e5PyVfIV+fnZtnFtII68HtTwFz0JcBgtga0xWiqlVU+ICrXvyADJDmqeTsU6QMMR
 sxTzHNtuSAvJ4JgwXz3nNq7nbUPDAo6SX/YwsTcKPWmFLG5ZctSAYxPBvNY27Mrw
 NdywJ8xif6yK8Fc53Dey0+ZYnNTaI6sd/EMPGpeP4B7PU6iZU3z8YOtevSYGib5B
 vonGo1YA+Z2DxM+WdT8rjSwgU/MRbRWdWSA4FBr/7K4dkG18d4Pi8Wng4BXlHz+w
 kUzXhANJ2QvIfVlPlm8EKudPDVPMeXGG0SGSIDeUKnh/vZQ56LCUTYTasTsx3+MU
 XbKJeDBbn+nB33KEOZB9weBL51BIjSB6iGEzVrKQSAsK85iUyqv7NzkrMPVYSB/e
 ZQV4lfk6pJTQ2LaBp1Fb
 =Ax4r
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20150907' into staging

s390x fixes and improvements:
- various bugfixes (css/event-facility)
- more efficient adapter interrupt routes setup
- gdb enhancement
- sclp got treated with a lot of remodelling/cleanup

# gpg: Signature made Mon 07 Sep 2015 15:42:43 BST using RSA key ID C6F02FAF
# gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>"

* remotes/cohuck/tags/s390x-20150907: (23 commits)
  s390/sclp: simplify calculation of rnmax
  s390/sclp: store the increment_size in the sclp device
  s390: unify allocation of initial memory
  s390: move memory calculation into the sclp device
  s390/sclp: ignore memory hotplug operations if it is disabled
  s390: disallow memory hotplug for the s390-virtio machine
  s390: no need to manually parse for slots and maxmem
  s390/sclp: move sclp_service_interrupt into the sclp device
  s390/sclp: move sclp_execute related functions into the SCLP class
  s390/sclp: introduce a root sclp device
  s390/sclp: temporarily fix unassignment/reassignment of memory subregions
  s390/sclp: replace sclp event types with proper defines
  s390/sclp: rework sclp event facility initialization + device realization
  sclp/s390: rework sclp cpu hotplug device notification
  s390x/gdb: support reading/writing of control registers
  s390x/kvm: make setting of in-kernel irq routes more efficient
  pc-bios/s390-ccw: rebuild image
  pc-bios/s390-ccw: Device detection in higher subchannel sets
  s390x/event-facility: fix location of receive mask
  s390x/css: start with cleared cstat/dstat
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-09-07 16:07:47 +01:00
commit 9d34158a5a
17 changed files with 430 additions and 226 deletions

2
configure vendored
View File

@ -5392,7 +5392,7 @@ case "$target_name" in
echo "TARGET_ABI32=y" >> $config_target_mak echo "TARGET_ABI32=y" >> $config_target_mak
;; ;;
s390x) s390x)
gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml" gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml s390-cr.xml"
;; ;;
tricore) tricore)
;; ;;

26
gdb-xml/s390-cr.xml Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<!-- Copyright 2015 IBM Corp.
This work is licensed under the terms of the GNU GPL, version 2 or
(at your option) any later version. See the COPYING file in the
top-level directory. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.s390.cr">
<reg name="cr0" bitsize="64" type="uint64" group="control"/>
<reg name="cr1" bitsize="64" type="uint64" group="control"/>
<reg name="cr2" bitsize="64" type="uint64" group="control"/>
<reg name="cr3" bitsize="64" type="uint64" group="control"/>
<reg name="cr4" bitsize="64" type="uint64" group="control"/>
<reg name="cr5" bitsize="64" type="uint64" group="control"/>
<reg name="cr6" bitsize="64" type="uint64" group="control"/>
<reg name="cr7" bitsize="64" type="uint64" group="control"/>
<reg name="cr8" bitsize="64" type="uint64" group="control"/>
<reg name="cr9" bitsize="64" type="uint64" group="control"/>
<reg name="cr10" bitsize="64" type="uint64" group="control"/>
<reg name="cr11" bitsize="64" type="uint64" group="control"/>
<reg name="cr12" bitsize="64" type="uint64" group="control"/>
<reg name="cr13" bitsize="64" type="uint64" group="control"/>
<reg name="cr14" bitsize="64" type="uint64" group="control"/>
<reg name="cr15" bitsize="64" type="uint64" group="control"/>
</feature>

View File

@ -228,6 +228,8 @@ static int kvm_s390_add_adapter_routes(S390FLICState *fs,
routes->gsi[i] = ret; routes->gsi[i] = ret;
routes->adapter.ind_offset++; routes->adapter.ind_offset++;
} }
kvm_irqchip_commit_routes(kvm_state);
/* Restore passed-in structure to original state. */ /* Restore passed-in structure to original state. */
routes->adapter.ind_offset = ind_offset; routes->adapter.ind_offset = ind_offset;
return 0; return 0;

View File

@ -261,6 +261,9 @@ static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1)
ret.flags = tmp0.flags; ret.flags = tmp0.flags;
ret.count = be16_to_cpu(tmp0.count); ret.count = be16_to_cpu(tmp0.count);
ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16); ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16);
if ((ret.cmd_code & 0x0f) == CCW_CMD_TIC) {
ret.cmd_code &= 0x0f;
}
} }
return ret; return ret;
} }
@ -287,6 +290,10 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr)
((ccw.cmd_code & 0xf0) != 0)) { ((ccw.cmd_code & 0xf0) != 0)) {
return -EINVAL; return -EINVAL;
} }
if (!sch->ccw_fmt_1 && (ccw.count == 0) &&
(ccw.cmd_code != CCW_CMD_TIC)) {
return -EINVAL;
}
if (ccw.flags & CCW_FLAG_SUSPEND) { if (ccw.flags & CCW_FLAG_SUSPEND) {
return -EINPROGRESS; return -EINPROGRESS;
@ -392,6 +399,8 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
path = 0x80; path = 0x80;
if (!(s->ctrl & SCSW_ACTL_SUSP)) { if (!(s->ctrl & SCSW_ACTL_SUSP)) {
s->cstat = 0;
s->dstat = 0;
/* Look at the orb and try to execute the channel program. */ /* Look at the orb and try to execute the channel program. */
assert(orb != NULL); /* resume does not pass an orb */ assert(orb != NULL); /* resume does not pass an orb */
p->intparm = orb->intparm; p->intparm = orb->intparm;

View File

@ -27,12 +27,12 @@ typedef struct SCLPEventsBus {
struct SCLPEventFacility { struct SCLPEventFacility {
SysBusDevice parent_obj; SysBusDevice parent_obj;
SCLPEventsBus sbus; SCLPEventsBus sbus;
SCLPEvent quiesce_event;
SCLPEvent cpu_hotplug_event;
/* guest' receive mask */ /* guest' receive mask */
unsigned int receive_mask; unsigned int receive_mask;
}; };
static SCLPEvent cpu_hotplug;
/* return true if any child has event pending set */ /* return true if any child has event pending set */
static bool event_pending(SCLPEventFacility *ef) 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; sclp_active_selection_mask = sclp_cp_receive_mask;
break; break;
case SCLP_SELECTIVE_READ: 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 = sccb->h.response_code =
cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK); cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
goto out; goto out;
} }
sclp_active_selection_mask = be32_to_cpu(red->mask);
break; break;
default: default:
sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION); 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" #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) 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 = { 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); SCLPEventFacility *event_facility = EVENT_FACILITY(obj);
DeviceState *quiesce; DeviceState *sdev = DEVICE(obj);
/* Spawn a new bus for SCLP events */ /* Spawn a new bus for SCLP events */
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus), qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
TYPE_SCLP_EVENTS_BUS, sdev, NULL); TYPE_SCLP_EVENTS_BUS, sdev, NULL);
quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce"); object_initialize(&event_facility->quiesce_event, sizeof(SCLPEvent),
if (!quiesce) { TYPE_SCLP_QUIESCE);
return -1; qdev_set_parent_bus(DEVICE(&event_facility->quiesce_event),
} &event_facility->sbus.qbus);
qdev_init_nofail(quiesce); object_initialize(&event_facility->cpu_hotplug_event, sizeof(SCLPEvent),
TYPE_SCLP_CPU_HOTPLUG);
object_initialize(&cpu_hotplug, sizeof(cpu_hotplug), TYPE_SCLP_CPU_HOTPLUG); qdev_set_parent_bus(DEVICE(&event_facility->cpu_hotplug_event),
qdev_set_parent_bus(DEVICE(&cpu_hotplug), BUS(&event_facility->sbus)); &event_facility->sbus.qbus);
object_property_set_bool(OBJECT(&cpu_hotplug), true, "realized", NULL); /* the facility will automatically realize the devices via the bus */
return 0;
} }
static void reset_event_facility(DeviceState *dev) 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->reset = reset_event_facility;
dc->vmsd = &vmstate_event_facility; dc->vmsd = &vmstate_event_facility;
set_bit(DEVICE_CATEGORY_MISC, dc->categories); set_bit(DEVICE_CATEGORY_MISC, dc->categories);
k->init = init_event_facility;
k->command_handler = command_handler; k->command_handler = command_handler;
k->event_pending = event_pending; 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 = { static const TypeInfo sclp_event_facility_info = {
.name = TYPE_SCLP_EVENT_FACILITY, .name = TYPE_SCLP_EVENT_FACILITY,
.parent = TYPE_SYS_BUS_DEVICE, .parent = TYPE_SYS_BUS_DEVICE,
.instance_init = init_event_facility,
.instance_size = sizeof(SCLPEventFacility), .instance_size = sizeof(SCLPEventFacility),
.class_init = init_event_facility_class, .class_init = init_event_facility_class,
.class_size = sizeof(SCLPEventFacilityClass), .class_size = sizeof(SCLPEventFacilityClass),

View File

@ -100,57 +100,31 @@ static void virtio_ccw_register_hcalls(void)
virtio_ccw_hcall_early_printk); 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 *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1); 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; int ret;
VirtualCssBus *css_bus; VirtualCssBus *css_bus;
DeviceState *dev; 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. s390_sclp_init();
* The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer. s390_memory_init(machine->ram_size);
* 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");
}
/* get a BUS */ /* get a BUS */
css_bus = virtual_css_bus_init(); css_bus = virtual_css_bus_init();
s390_sclp_init();
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
machine->initrd_filename, "s390-ccw.img", true); machine->initrd_filename, "s390-ccw.img", true);
s390_flic_init(); s390_flic_init();
@ -163,25 +137,6 @@ static void ccw_init(MachineState *machine)
/* register hypercalls */ /* register hypercalls */
virtio_ccw_register_hcalls(); 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 */ /* init CPUs */
s390_init_cpus(machine->cpu_model); s390_init_cpus(machine->cpu_model);

View File

@ -23,6 +23,7 @@
#include "hw/hw.h" #include "hw/hw.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
@ -260,30 +261,20 @@ int gtod_load(QEMUFile *f, void *opaque, int version_id)
/* PC hardware initialisation */ /* PC hardware initialisation */
static void s390_init(MachineState *machine) static void s390_init(MachineState *machine)
{ {
ram_addr_t my_ram_size = machine->ram_size; ram_addr_t my_ram_size;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
int increment_size = 20;
void *virtio_region; void *virtio_region;
hwaddr virtio_region_len; hwaddr virtio_region_len;
hwaddr virtio_region_start; hwaddr virtio_region_start;
/* if (machine->ram_slots) {
* The storage increment size is a multiple of 1M and is a power of 2. error_report("Memory hotplug not supported by the selected machine.");
* The number of storage increments must be MAX_STORAGE_INCREMENTS or exit(EXIT_FAILURE);
* fewer.
*/
while ((my_ram_size >> increment_size) > MAX_STORAGE_INCREMENTS) {
increment_size++;
} }
my_ram_size = my_ram_size >> increment_size << increment_size; s390_sclp_init();
my_ram_size = machine->ram_size;
/* let's propagate the changed ram size into the global variable. */
ram_size = my_ram_size;
/* get a BUS */ /* get a BUS */
s390_bus = s390_virtio_bus_init(&my_ram_size); s390_bus = s390_virtio_bus_init(&my_ram_size);
s390_sclp_init();
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
machine->initrd_filename, ZIPL_FILENAME, false); machine->initrd_filename, ZIPL_FILENAME, false);
s390_flic_init(); s390_flic_init();
@ -292,9 +283,7 @@ static void s390_init(MachineState *machine)
s390_virtio_register_hcalls(); s390_virtio_register_hcalls();
/* allocate RAM */ /* allocate RAM */
memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size, &error_abort); s390_memory_init(my_ram_size);
vmstate_register_ram_global(ram);
memory_region_add_subregion(sysmem, 0, ram);
/* clear virtio region */ /* clear virtio region */
virtio_region_len = my_ram_size - ram_size; 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, cpu_physical_memory_unmap(virtio_region, virtio_region_len, 1,
virtio_region_len); virtio_region_len);
/* Initialize storage key device */
s390_skeys_init();
/* init CPUs */ /* init CPUs */
s390_init_cpus(machine->cpu_model); s390_init_cpus(machine->cpu_model);

View File

@ -27,4 +27,5 @@ void s390_init_ipl_dev(const char *kernel_filename,
bool enforce_bios); bool enforce_bios);
void s390_create_virtio_net(BusState *bus, const char *name); void s390_create_virtio_net(BusState *bus, const char *name);
void s390_nmi(NMIState *n, int cpu_index, Error **errp); void s390_nmi(NMIState *n, int cpu_index, Error **errp);
void s390_memory_init(ram_addr_t mem_size);
#endif #endif

View File

@ -17,37 +17,27 @@
#include "exec/memory.h" #include "exec/memory.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "qemu/config-file.h" #include "hw/boards.h"
#include "hw/s390x/sclp.h" #include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h" #include "hw/s390x/event-facility.h"
#include "hw/s390x/s390-pci-bus.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(), return SCLP(object_resolve_path_type("", TYPE_SCLP, NULL));
TYPE_SCLP_EVENT_FACILITY,
NULL);
assert(op);
return op->opaque;
} }
/* Provide information about the configuration, CPUs and storage */ /* 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; ReadInfo *read_info = (ReadInfo *) sccb;
MachineState *machine = MACHINE(qdev_get_machine());
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
CPUState *cpu; CPUState *cpu;
int cpu_count = 0; int cpu_count = 0;
int i = 0; int i = 0;
int increment_size = 20;
int rnsize, rnmax; int rnsize, rnmax;
QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory"), NULL); int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
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;
}
CPU_FOREACH(cpu) { CPU_FOREACH(cpu) {
cpu_count++; cpu_count++;
@ -66,23 +56,8 @@ static void read_SCP_info(SCCB *sccb)
read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO | read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO |
SCLP_HAS_PCI_RECONFIG); 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 */ /* Memory Hotplug is only supported for the ccw machine type */
if (mhd) { 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; mhd->standby_subregion_size = MEM_SECTION_SIZE;
/* Deduct the memory slot already used for core */ /* Deduct the memory slot already used for core */
if (slots > 0) { if (slots > 0) {
@ -108,13 +83,11 @@ static void read_SCP_info(SCCB *sccb)
} }
mhd->padded_ram_size = ram_size + mhd->pad_size; mhd->padded_ram_size = ram_size + mhd->pad_size;
mhd->rzm = 1 << mhd->increment_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); 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) { if (rnsize <= 128) {
read_info->rnsize = rnsize; read_info->rnsize = rnsize;
} else { } else {
@ -122,6 +95,7 @@ static void read_SCP_info(SCCB *sccb)
read_info->rnsize2 = cpu_to_be32(rnsize); read_info->rnsize2 = cpu_to_be32(rnsize);
} }
rnmax = machine->maxram_size >> sclp->increment_size;
if (rnmax < 0x10000) { if (rnmax < 0x10000) {
read_info->rnmax = cpu_to_be16(rnmax); read_info->rnmax = cpu_to_be16(rnmax);
} else { } else {
@ -132,14 +106,17 @@ static void read_SCP_info(SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); 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 i, assigned;
int subincrement_id = SCLP_STARTING_SUBINCREMENT_ID; int subincrement_id = SCLP_STARTING_SUBINCREMENT_ID;
ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb; ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); 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) { if ((ram_size >> mhd->increment_size) >= 0x10000) {
sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); 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); 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; ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); 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) { if ((mhd->standby_mem_size >> mhd->increment_size) >= 0x10000) {
sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); 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); 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; int i, assigned, subincrement_id;
AttachStorageElement *attach_info = (AttachStorageElement *) sccb; AttachStorageElement *attach_info = (AttachStorageElement *) sccb;
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); 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) { if (element != 1) {
sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); 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); 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; MemoryRegion *mr = NULL;
uint64_t this_subregion_size; uint64_t this_subregion_size;
AssignStorage *assign_info = (AssignStorage *) sccb; AssignStorage *assign_info = (AssignStorage *) sccb;
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
assert(mhd); ram_addr_t assign_addr;
ram_addr_t assign_addr = (assign_info->rn - 1) * mhd->rzm;
MemoryRegion *sysmem = get_system_memory(); 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) && if ((assign_addr % MEM_SECTION_SIZE == 0) &&
(assign_addr >= mhd->padded_ram_size)) { (assign_addr >= mhd->padded_ram_size)) {
/* Re-use existing memory region if found */ /* Re-use existing memory region if found */
mr = memory_region_find(sysmem, assign_addr, 1).mr; mr = memory_region_find(sysmem, assign_addr, 1).mr;
memory_region_unref(mr);
if (!mr) { if (!mr) {
MemoryRegion *standby_ram = g_new(MemoryRegion, 1); 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); 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); vmstate_register_ram_global(standby_ram);
memory_region_add_subregion(sysmem, offset, 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); 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; MemoryRegion *mr = NULL;
AssignStorage *assign_info = (AssignStorage *) sccb; AssignStorage *assign_info = (AssignStorage *) sccb;
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
assert(mhd); ram_addr_t unassign_addr;
ram_addr_t unassign_addr = (assign_info->rn - 1) * mhd->rzm;
MemoryRegion *sysmem = get_system_memory(); 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 the addr is a multiple of 256 MB */
if ((unassign_addr % MEM_SECTION_SIZE == 0) && if ((unassign_addr % MEM_SECTION_SIZE == 0) &&
(unassign_addr >= mhd->padded_ram_size)) { (unassign_addr >= mhd->padded_ram_size)) {
@ -269,6 +269,7 @@ static void unassign_storage(SCCB *sccb)
/* find the specified memory region and destroy it */ /* find the specified memory region and destroy it */
mr = memory_region_find(sysmem, unassign_addr, 1).mr; mr = memory_region_find(sysmem, unassign_addr, 1).mr;
memory_region_unref(mr);
if (mr) { if (mr) {
int i; int i;
int is_removable = 1; int is_removable = 1;
@ -287,8 +288,7 @@ static void unassign_storage(SCCB *sccb)
} }
if (is_removable) { if (is_removable) {
memory_region_del_subregion(sysmem, mr); memory_region_del_subregion(sysmem, mr);
object_unparent(OBJECT(mr)); object_unref(OBJECT(mr));
g_free(mr);
} }
} }
} }
@ -296,7 +296,7 @@ static void unassign_storage(SCCB *sccb)
} }
/* Provide information about the CPU */ /* 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; ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb;
CPUState *cpu; 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); 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); SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
switch (code & SCLP_CMD_CODE_MASK) { switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMDW_READ_SCP_INFO: case SCLP_CMDW_READ_SCP_INFO:
case SCLP_CMDW_READ_SCP_INFO_FORCED: case SCLP_CMDW_READ_SCP_INFO_FORCED:
read_SCP_info(sccb); sclp_c->read_SCP_info(sclp, sccb);
break; break;
case SCLP_CMDW_READ_CPU_INFO: case SCLP_CMDW_READ_CPU_INFO:
sclp_read_cpu_info(sccb); sclp_c->read_cpu_info(sclp, sccb);
break; break;
case SCLP_READ_STORAGE_ELEMENT_INFO: case SCLP_READ_STORAGE_ELEMENT_INFO:
if (code & 0xff00) { if (code & 0xff00) {
read_storage_element1_info(sccb); sclp_c->read_storage_element1_info(sclp, sccb);
} else { } else {
read_storage_element0_info(sccb); sclp_c->read_storage_element0_info(sclp, sccb);
} }
break; break;
case SCLP_ATTACH_STORAGE_ELEMENT: case SCLP_ATTACH_STORAGE_ELEMENT:
attach_storage_element(sccb, (code & 0xff00) >> 8); sclp_c->attach_storage_element(sclp, sccb, (code & 0xff00) >> 8);
break; break;
case SCLP_ASSIGN_STORAGE: case SCLP_ASSIGN_STORAGE:
assign_storage(sccb); sclp_c->assign_storage(sclp, sccb);
break; break;
case SCLP_UNASSIGN_STORAGE: case SCLP_UNASSIGN_STORAGE:
unassign_storage(sccb); sclp_c->unassign_storage(sclp, sccb);
break; break;
case SCLP_CMDW_CONFIGURE_PCI: case SCLP_CMDW_CONFIGURE_PCI:
s390_pci_sclp_configure(1, sccb); 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) 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; int r = 0;
SCCB work_sccb; SCCB work_sccb;
@ -400,20 +403,20 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
goto out; goto out;
} }
sclp_execute((SCCB *)&work_sccb, code); sclp_c->execute(sclp, (SCCB *)&work_sccb, code);
cpu_physical_memory_write(sccb, &work_sccb, cpu_physical_memory_write(sccb, &work_sccb,
be16_to_cpu(work_sccb.h.length)); be16_to_cpu(work_sccb.h.length));
sclp_service_interrupt(sccb); sclp_c->service_interrupt(sclp, sccb);
out: out:
return r; 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); SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
uint32_t param = sccb & ~3; uint32_t param = sccb & ~3;
@ -428,17 +431,148 @@ void sclp_service_interrupt(uint32_t sccb)
s390_sclp_extint(param); 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 */ /* qemu object creation and initialization functions */
void s390_sclp_init(void) 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_property_add_child(qdev_get_machine(), TYPE_SCLP, new,
OBJECT(dev), NULL); NULL);
qdev_init_nofail(dev); 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) sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void)
{ {
DeviceState *dev; DeviceState *dev;
@ -475,5 +609,6 @@ static TypeInfo sclp_memory_hotplug_dev_info = {
static void register_types(void) static void register_types(void)
{ {
type_register_static(&sclp_memory_hotplug_dev_info); type_register_static(&sclp_memory_hotplug_dev_info);
type_register_static(&sclp_info);
} }
type_init(register_types); type_init(register_types);

View File

@ -25,13 +25,16 @@ typedef struct ConfigMgtData {
uint8_t event_qualifier; uint8_t event_qualifier;
} QEMU_PACKED ConfigMgtData; } QEMU_PACKED ConfigMgtData;
static qemu_irq *irq_cpu_hotplug; /* Only used in this file */
#define EVENT_QUAL_CPU_CHANGE 1 #define EVENT_QUAL_CPU_CHANGE 1
void raise_irq_cpu_hotplug(void) 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) static unsigned int send_mask(void)
@ -70,36 +73,19 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
return 1; 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) static void cpu_class_init(ObjectClass *oc, void *data)
{ {
SCLPEventClass *k = SCLP_EVENT_CLASS(oc); SCLPEventClass *k = SCLP_EVENT_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc);
k->init = irq_cpu_hotplug_init;
k->get_send_mask = send_mask; k->get_send_mask = send_mask;
k->get_receive_mask = receive_mask; k->get_receive_mask = receive_mask;
k->read_event_data = read_event_data; k->read_event_data = read_event_data;
k->write_event_data = NULL;
set_bit(DEVICE_CATEGORY_MISC, dc->categories); set_bit(DEVICE_CATEGORY_MISC, dc->categories);
} }
static const TypeInfo sclp_cpu_info = { static const TypeInfo sclp_cpu_info = {
.name = "sclp-cpu-hotplug", .name = TYPE_SCLP_CPU_HOTPLUG,
.parent = TYPE_SCLP_EVENT, .parent = TYPE_SCLP_EVENT,
.instance_size = sizeof(SCLPEvent), .instance_size = sizeof(SCLPEvent),
.class_init = cpu_class_init, .class_init = cpu_class_init,

View File

@ -66,7 +66,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
} }
static const VMStateDescription vmstate_sclpquiesce = { static const VMStateDescription vmstate_sclpquiesce = {
.name = "sclpquiesce", .name = TYPE_SCLP_QUIESCE,
.version_id = 0, .version_id = 0,
.minimum_version_id = 0, .minimum_version_id = 0,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
@ -127,7 +127,7 @@ static void quiesce_class_init(ObjectClass *klass, void *data)
} }
static const TypeInfo sclp_quiesce_info = { static const TypeInfo sclp_quiesce_info = {
.name = "sclpquiesce", .name = TYPE_SCLP_QUIESCE,
.parent = TYPE_SCLP_EVENT, .parent = TYPE_SCLP_EVENT,
.instance_size = sizeof(SCLPEvent), .instance_size = sizeof(SCLPEvent),
.class_init = quiesce_class_init, .class_init = quiesce_class_init,

View File

@ -47,6 +47,7 @@
OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT) OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
#define TYPE_SCLP_CPU_HOTPLUG "sclp-cpu-hotplug" #define TYPE_SCLP_CPU_HOTPLUG "sclp-cpu-hotplug"
#define TYPE_SCLP_QUIESCE "sclpquiesce"
typedef struct WriteEventMask { typedef struct WriteEventMask {
SCCBHeader h; SCCBHeader h;
@ -146,8 +147,10 @@ typedef struct WriteEventData {
typedef struct ReadEventData { typedef struct ReadEventData {
SCCBHeader h; SCCBHeader h;
EventBufferHeader ebh; union {
uint32_t mask; uint32_t mask;
EventBufferHeader ebh;
};
} QEMU_PACKED ReadEventData; } QEMU_PACKED ReadEventData;
typedef struct SCLPEvent { typedef struct SCLPEvent {
@ -186,11 +189,8 @@ typedef struct SCLPEventClass {
OBJECT_GET_CLASS(SCLPEventFacilityClass, (obj), \ OBJECT_GET_CLASS(SCLPEventFacilityClass, (obj), \
TYPE_SCLP_EVENT_FACILITY) TYPE_SCLP_EVENT_FACILITY)
typedef struct SCLPEventFacility SCLPEventFacility;
typedef struct SCLPEventFacilityClass { typedef struct SCLPEventFacilityClass {
DeviceClass parent_class; SysBusDeviceClass parent_class;
int (*init)(SCLPEventFacility *ef);
void (*command_handler)(SCLPEventFacility *ef, SCCB *sccb, uint64_t code); void (*command_handler)(SCLPEventFacility *ef, SCCB *sccb, uint64_t code);
bool (*event_pending)(SCLPEventFacility *ef); bool (*event_pending)(SCLPEventFacility *ef);
} SCLPEventFacilityClass; } SCLPEventFacilityClass;

View File

@ -163,6 +163,39 @@ typedef struct SCCB {
char data[SCCB_DATA_LEN]; char data[SCCB_DATA_LEN];
} QEMU_PACKED SCCB; } QEMU_PACKED SCCB;
#define TYPE_SCLP "sclp"
#define SCLP(obj) OBJECT_CHECK(SCLPDevice, (obj), TYPE_SCLP)
#define SCLP_CLASS(oc) OBJECT_CLASS_CHECK(SCLPDeviceClass, (oc), TYPE_SCLP)
#define SCLP_GET_CLASS(obj) OBJECT_GET_CLASS(SCLPDeviceClass, (obj), TYPE_SCLP)
typedef struct SCLPEventFacility SCLPEventFacility;
typedef struct SCLPDevice {
/* private */
DeviceState parent_obj;
SCLPEventFacility *event_facility;
int increment_size;
/* public */
} SCLPDevice;
typedef struct SCLPDeviceClass {
/* private */
DeviceClass parent_class;
void (*read_SCP_info)(SCLPDevice *sclp, SCCB *sccb);
void (*read_storage_element0_info)(SCLPDevice *sclp, SCCB *sccb);
void (*read_storage_element1_info)(SCLPDevice *sclp, SCCB *sccb);
void (*attach_storage_element)(SCLPDevice *sclp, SCCB *sccb,
uint16_t element);
void (*assign_storage)(SCLPDevice *sclp, SCCB *sccb);
void (*unassign_storage)(SCLPDevice *sclp, SCCB *sccb);
void (*read_cpu_info)(SCLPDevice *sclp, SCCB *sccb);
/* public */
void (*execute)(SCLPDevice *sclp, SCCB *sccb, uint32_t code);
void (*service_interrupt)(SCLPDevice *sclp, uint32_t sccb);
} SCLPDeviceClass;
typedef struct sclpMemoryHotplugDev sclpMemoryHotplugDev; typedef struct sclpMemoryHotplugDev sclpMemoryHotplugDev;
#define TYPE_SCLP_MEMORY_HOTPLUG_DEV "sclp-memory-hotplug-dev" #define TYPE_SCLP_MEMORY_HOTPLUG_DEV "sclp-memory-hotplug-dev"

View File

@ -1293,7 +1293,6 @@ int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
kroute.u.adapter.adapter_id = adapter->adapter_id; kroute.u.adapter.adapter_id = adapter->adapter_id;
kvm_add_routing_entry(s, &kroute); kvm_add_routing_entry(s, &kroute);
kvm_irqchip_commit_routes(s);
return virq; return virq;
} }

Binary file not shown.

View File

@ -38,40 +38,56 @@ void virtio_panic(const char *string)
while (1) { } while (1) { }
} }
static void virtio_setup(uint64_t dev_info) static bool find_dev(struct schib *schib, int dev_no)
{ {
struct schib schib; int i, r;
int i;
int r;
bool found = false;
bool check_devno = false;
uint16_t dev_no = -1;
if (dev_info != -1) {
check_devno = true;
dev_no = dev_info & 0xffff;
debug_print_int("device no. ", dev_no);
blk_schid.ssid = (dev_info >> 16) & 0x3;
if (blk_schid.ssid != 0) {
debug_print_int("ssid ", blk_schid.ssid);
if (enable_mss_facility() != 0) {
virtio_panic("Failed to enable mss facility\n");
}
}
}
for (i = 0; i < 0x10000; i++) { for (i = 0; i < 0x10000; i++) {
blk_schid.sch_no = i; blk_schid.sch_no = i;
r = stsch_err(blk_schid, &schib); r = stsch_err(blk_schid, schib);
if (r == 3) { if ((r == 3) || (r == -EIO)) {
break; break;
} }
if (schib.pmcw.dnv) { if (!schib->pmcw.dnv) {
if (!check_devno || (schib.pmcw.dev == dev_no)) { continue;
if (virtio_is_blk(blk_schid)) { }
found = true; if (!virtio_is_blk(blk_schid)) {
break; continue;
} }
if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) {
return true;
}
}
return false;
}
static void virtio_setup(uint64_t dev_info)
{
struct schib schib;
int ssid;
bool found = false;
uint16_t dev_no;
/*
* We unconditionally enable mss support. In every sane configuration,
* this will succeed; and even if it doesn't, stsch_err() can deal
* with the consequences.
*/
enable_mss_facility();
if (dev_info != -1) {
dev_no = dev_info & 0xffff;
debug_print_int("device no. ", dev_no);
blk_schid.ssid = (dev_info >> 16) & 0x3;
debug_print_int("ssid ", blk_schid.ssid);
found = find_dev(&schib, dev_no);
} else {
for (ssid = 0; ssid < 0x3; ssid++) {
blk_schid.ssid = ssid;
found = find_dev(&schib, -1);
if (found) {
break;
} }
} }
} }

View File

@ -174,6 +174,39 @@ static int cpu_write_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
} }
} }
/* the values represent the positions in s390-cr.xml */
#define S390_C0_REGNUM 0
#define S390_C15_REGNUM 15
/* total number of registers in s390-cr.xml */
#define S390_NUM_C_REGS 16
#ifndef CONFIG_USER_ONLY
static int cpu_read_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
{
switch (n) {
case S390_C0_REGNUM ... S390_C15_REGNUM:
return gdb_get_regl(mem_buf, env->cregs[n]);
default:
return 0;
}
}
static int cpu_write_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
{
switch (n) {
case S390_C0_REGNUM ... S390_C15_REGNUM:
env->cregs[n] = ldtul_p(mem_buf);
if (tcg_enabled()) {
tlb_flush(ENV_GET_CPU(env), 1);
}
cpu_synchronize_post_init(ENV_GET_CPU(env));
return 8;
default:
return 0;
}
}
#endif
void s390_cpu_gdb_init(CPUState *cs) void s390_cpu_gdb_init(CPUState *cs)
{ {
gdb_register_coprocessor(cs, cpu_read_ac_reg, gdb_register_coprocessor(cs, cpu_read_ac_reg,
@ -187,4 +220,10 @@ void s390_cpu_gdb_init(CPUState *cs)
gdb_register_coprocessor(cs, cpu_read_vreg, gdb_register_coprocessor(cs, cpu_read_vreg,
cpu_write_vreg, cpu_write_vreg,
S390_NUM_VREGS, "s390-vx.xml", 0); S390_NUM_VREGS, "s390-vx.xml", 0);
#ifndef CONFIG_USER_ONLY
gdb_register_coprocessor(cs, cpu_read_c_reg,
cpu_write_c_reg,
S390_NUM_C_REGS, "s390-cr.xml", 0);
#endif
} }