From fde8206b8061f808c880709c2ac26a645b11c211 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Wed, 15 Jul 2015 16:16:20 +0200 Subject: [PATCH 01/23] s390x/css: handle ccw-0 TIC correctly In CCW-0 format TIC command 4 highest bits are ignored in the subchannel. In CCW-1 format the TIC command 4 highest bits must be 0. To convert TIC from CCW-0 to CCW-1 we clear the 4 highest bits to guarantee compatibility. Signed-off-by: Pierre Morel Reviewed-by: Cornelia Huck Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 5df450e00b..2c0782cc6a 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; } From fa4463e0432ab66432a28d6b975f8eed99b3f4fa Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 16 Jul 2015 10:42:18 +0200 Subject: [PATCH 02/23] s390x/css: ccw-0 enforces count > 0 Type-0 ccws need to have a count > 0 for any command other than TIC. Generate a channel-program check if this is not the case. Reviewed-by: Matthew Rosato Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 2c0782cc6a..95962808de 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -290,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; From 3335ddddf9e5ba7743dc8e3f767f4ef857ccd20c Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 1 Jul 2015 15:28:06 +0200 Subject: [PATCH 03/23] s390x/event-facility: fix receive mask check For selective read event, we need to check if any event is requested that is not active instead of whether none of the requested events is active. Reviewed-by: David Hildenbrand Reviewed-by: Eric Farman Signed-off-by: Cornelia Huck --- hw/s390x/event-facility.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 0c700effb1..1ca6544e44 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -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); From 6b7741c2bedeae2e8c54fffce81723ca0a0c25c0 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 24 Jul 2015 12:08:37 +0200 Subject: [PATCH 04/23] s390x/css: start with cleared cstat/dstat When executing the start function, we should start with a clear state regarding subchannel and device status; it is easy to forget updating one of them after the ccw has been processed. Note that we don't need to care about resetting the various control fields: They are cleared by tsch(), and if they were still pending, we wouldn't be able to execute the start function in the first place. Also note that we don't want to clear cstat/dstat if a suspended subchannel is resumed. This fixes a bug where we would continue to present channel-program check in cstat even though later ccw requests for the subchannel finished without error (i.e. cstat should be 0). Cc: qemu-stable@nongnu.org Signed-off-by: Cornelia Huck Reviewed-by: David Hildenbrand --- hw/s390x/css.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 95962808de..c033612889 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -399,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; From f7822aa8b610a4fec57a09066974e5c088592c08 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 27 Jul 2015 16:55:23 +0200 Subject: [PATCH 05/23] s390x/event-facility: fix location of receive mask For read event mask, we assumed that the layout of the sccb was |sccb header|event buffer header|receive mask|...| The correct layout, however, is |sccb header|receive mask|...| as in-buffer and |sccb header|event buffer header|...| as out-buffer. Fix this: This makes selective read work. Reviewed-by: David Hildenbrand Signed-off-by: Cornelia Huck --- include/hw/s390x/event-facility.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h index 6a062b668a..871f3e7f11 100644 --- a/include/hw/s390x/event-facility.h +++ b/include/hw/s390x/event-facility.h @@ -146,8 +146,10 @@ typedef struct WriteEventData { typedef struct ReadEventData { SCCBHeader h; - EventBufferHeader ebh; - uint32_t mask; + union { + uint32_t mask; + EventBufferHeader ebh; + }; } QEMU_PACKED ReadEventData; typedef struct SCLPEvent { From 0f79b89bc2bdbed35d2c57d722acc4c31a5a2ce4 Mon Sep 17 00:00:00 2001 From: Alexander Yarygin Date: Thu, 25 Jun 2015 18:35:58 +0300 Subject: [PATCH 06/23] pc-bios/s390-ccw: Device detection in higher subchannel sets If no bootdevice was specified, we try to autodetect a suitable IPL device. Current code only searched in subchannel set 0; extend this search to higher subchannel sets as well. Signed-off-by: Alexander Yarygin Reviewed-by: David Hildenbrand Reviewed-by: Cornelia Huck Signed-off-by: Cornelia Huck --- pc-bios/s390-ccw/main.c | 72 +++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index 584d4a2769..d5fe4cea1d 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -38,40 +38,56 @@ void virtio_panic(const char *string) 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; - 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"); - } - } - } + int i, r; for (i = 0; i < 0x10000; i++) { blk_schid.sch_no = i; - r = stsch_err(blk_schid, &schib); - if (r == 3) { + r = stsch_err(blk_schid, schib); + if ((r == 3) || (r == -EIO)) { break; } - if (schib.pmcw.dnv) { - if (!check_devno || (schib.pmcw.dev == dev_no)) { - if (virtio_is_blk(blk_schid)) { - found = true; - break; - } + if (!schib->pmcw.dnv) { + continue; + } + if (!virtio_is_blk(blk_schid)) { + 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; } } } From 9f70b85c405093f24d9df22215ead6596819832f Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 11 Aug 2015 10:53:41 +0200 Subject: [PATCH 07/23] pc-bios/s390-ccw: rebuild image Contains: - Device detection in higher subchannel sets Signed-off-by: Cornelia Huck --- pc-bios/s390-ccw.img | Bin 13784 -> 13856 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index f64380a972f280d66a4df03f029e4e1d42da292d..0c540a10cf2a662889f5fbd08a7580395a7577d0 100644 GIT binary patch delta 4709 zcmZu#3s{t87C!&n2L>E)|G^GhhN`M5Dt2OaXymTYy5GIIW!% z(?86!_lf&Lp_c+(gv$xu1O7rt@%Uw$eB6B=zx_K4{Q$e2ZYNG=wx<|LirOPzc3aWIkh(f6c)<^%LbuH2-RRHb6>!SOF^OY% zKdvE1zn>Jk}y&S=!`wIMsdGTvX+THSDN%fsjnQ&Q0lR^8epq0N_IL| zqN(z~rZhE5DDL$6eAow2V1>QL>wy`2FZql6Cqm9mxad;KnQ9L%JzgFwHc14nRLfh( zf&uJc?DoEw<}bjdxh9=B@3-0DI4x33rQ3nV-#13W4l)U86CW886Q5`PfcHJWA9Nn8 z18_dw-oN?pg%o!yz<{%&*YLbjBg%})%9Ennn5o&>D~=h*8kf8C(8(HMGmTabhYR~ocJnm%OEXG-xpTY7Ij5~}Cc96$kufEM@OS@q#5Ip@Zc`jBzsmAY+a(rdhOF?ot+t(2&@onWQx(P{HL& z#=OROE`D$-^Pw!?z_#VMs`GjLBI|(pE5z%5W&Rn)6^k_?&m@dxc>~L_Du{WP`7Fky zh?vmTF7uD9Sj37c%sYuUpC!<>uW;3$lwcTanp@PuZ#B^2F=5Q7BbN8t^}x^N{wE7ACkm=wml88ePCqqaij{2TrPf%h=>HpX(_nTIgePV!o=TZ#jMUGtlm)1%Q?o%!#Z(tz#CbSUkRGA{=Fdf0SZoNt95r234mC{FhTUn| z-b2wSQqYUSAC{c_6uH;bqPukF-eL0<%)deW_CuoB7L~XC?clBDsEQ^xNXGfg!GE zX{7WJ%5;tSi)^u+Ef#K7Dvh{lY`_RdSiXQU?TqJVRr!kLGZ>$beQ7}ano zo{#B6w%yP2yBMG2Km$D*%(!7NfmK~%kW@Bn^85tyR>U>3a@a; zRlHpI+QU>zh}YxBE#)si+?bY)r9UuYK|cb~{DRcCGx|7bwQu9&Fqx7}uin@g1rr(* zVZ7P|LrGL!deYbmJdfKsp_MFMDtaPP6{m=aj34s`hv4In@locj9Bw0rcmZpEmiAVp zr|_uM>R%jq>6#{s;>g6{IQ0$)rJbRDuy{Rk${>Xicml#X;R%SI-L`*<-pCY_v4=vp zeJRqS#wbno^P`R{k%v5Xl-cN@M#{^dQshoN2F1i1xl=l^Q({uH_OtfS2ZrKIN-!Q` zJ1e(JYdAi#v1$|mo+1;C*I8aJK8=|bQc96KA7r}%ksf<* zoXAhSN0}nFBtA3%4=(5@7ct)%jQ}Dd$yr~PG*?%D=C|&8PXD@xC~l!&`k!_NHL&xA5LH~(i2i%!EX<( zPs$$rmeJXeVgfo$;HLtl`A9K2{jr2Kgz(iWt9kakIzyov$! zHo!*48B;(DMC6F-^dtk-x4lxd zq-W@-OW9!&y~veI>1h?28OeHFr1M>3I&x@yp+T(9NFIsC-dc3G7bb1M9^wl_X>3yB zCnCW8eKH~#mO8>$CQf7|yD-9!l*m;|{H37v_=QGEYL;P7=#US^yZ<6N=J8`M3X=MT zNJ)+haM6T(`YrMXl+yyPyG4#AzKErd0QXG_O05fY$q-=u3<1 zzX(^%vc{f)T)H_{~@Ax2F#ses3STn zH+zJAxMNt3W7P1`_E~>eupldEZf@56C+0o2V6pv)M^-L*a>H1qob6yV47u&Dn4Sm>SP delta 4615 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 VlyS1^;W5ez>3evhvS!C Date: Mon, 27 Jul 2015 16:53:27 +0200 Subject: [PATCH 08/23] s390x/kvm: make setting of in-kernel irq routes more efficient When we add new adapter routes we call kvm_irqchip_add_route() for every virtqueue and in the same step also do the KVM_SET_GSI_ROUTING ioctl. This is unnecessary costly as the interface allows us to set multiple routes in one go. Let's first add all routes to the table stored in the global kvm_state and then do the ioctl to commit the routes to the in-kernel irqchip. This saves us several ioctls to the kernel where for each call a list is reallocated and populated. Signed-off-by: Jens Freimann Reviewed-by: David Hildenbrand Acked-by: Paolo Bonzini Signed-off-by: Cornelia Huck --- hw/intc/s390_flic_kvm.c | 2 ++ kvm-all.c | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index b471e7a41e..48714f96a3 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/kvm-all.c b/kvm-all.c index 06e06f2b3f..c6f5128756 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1293,7 +1293,6 @@ int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter) kroute.u.adapter.adapter_id = adapter->adapter_id; kvm_add_routing_entry(s, &kroute); - kvm_irqchip_commit_routes(s); return virq; } From 5b9f6345a616c321a5ea2f35e09043edd933767e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 23 Jun 2015 11:00:09 +0200 Subject: [PATCH 09/23] s390x/gdb: support reading/writing of control registers Let's support reading and writing of control registers for kvm and tcg. We have to take care of flushing the tlb (tcg) and pushing the changed registers into kvm. Reviewed-by: Christian Borntraeger Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- configure | 2 +- gdb-xml/s390-cr.xml | 26 ++++++++++++++++++++++++++ target-s390x/gdbstub.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 gdb-xml/s390-cr.xml diff --git a/configure b/configure index 21c4089c5c..d854936682 100755 --- a/configure +++ b/configure @@ -5392,7 +5392,7 @@ case "$target_name" in echo "TARGET_ABI32=y" >> $config_target_mak ;; 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) ;; diff --git a/gdb-xml/s390-cr.xml b/gdb-xml/s390-cr.xml new file mode 100644 index 0000000000..5246beaab3 --- /dev/null +++ b/gdb-xml/s390-cr.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/target-s390x/gdbstub.c b/target-s390x/gdbstub.c index 31f204964f..0c39a3c69f 100644 --- a/target-s390x/gdbstub.c +++ b/target-s390x/gdbstub.c @@ -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) { 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, cpu_write_vreg, 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 } From 073f57ae347a41cbcc940ae0286bbbab993b9148 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 11 May 2015 15:30:43 +0200 Subject: [PATCH 10/23] sclp/s390: rework sclp cpu hotplug device notification Let's get rid of this strange local variable + irq logic and work directly on the QOM. (hint: what happens if two such devices are created?) We could introduce proper QOM class + state for the cpu hotplug device, however that would result in too much overhead for a simple "trigger_signal" function. Also remove one unnecessary class function initialization. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/sclpcpu.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c index 2fe8b5aa40..615ac06b18 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,31 +73,14 @@ 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); } From f6102c329c43d7d5e0bee1fc2fe4043e05f9810c Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 21 May 2015 12:43:31 +0200 Subject: [PATCH 11/23] s390/sclp: rework sclp event facility initialization + device realization The current code only works by chance. The event facility is a sysbus device, but specifies in its class structure as parent the DeviceClass (instead of a device class). The init function in return lies therefore at the same position as the init function of SysBusDeviceClass and gets triggered instead - a very bad idea of doing that (e.g. the parameter types don't match). Let's bring the initialization code up to date, initializing the event facility + child events in .instance_init and moving the realization of the child events out of the init call, into the realization step. Device realization is now automatically performed when the event facility itself is realized. That realization implicitly triggers realization of the child bus, which in turn initializes the events. Please note that we have to manually propagate the realization of the bus children, common code still has a TODO set for that task. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/event-facility.c | 50 ++++++++++++++++++++----------- include/hw/s390x/event-facility.h | 3 +- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 1ca6544e44..7b64e782e9 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) { @@ -287,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 = { @@ -325,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), + "sclpquiesce"); + 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) @@ -363,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; } @@ -371,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/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h index 871f3e7f11..eae3b3bd63 100644 --- a/include/hw/s390x/event-facility.h +++ b/include/hw/s390x/event-facility.h @@ -191,8 +191,7 @@ typedef struct SCLPEventClass { typedef struct SCLPEventFacility SCLPEventFacility; typedef struct SCLPEventFacilityClass { - DeviceClass parent_class; - int (*init)(SCLPEventFacility *ef); + SysBusDeviceClass parent_class; void (*command_handler)(SCLPEventFacility *ef, SCCB *sccb, uint64_t code); bool (*event_pending)(SCLPEventFacility *ef); } SCLPEventFacilityClass; From 35925a7a73e7df4118cb11667095bd2d8fc4e091 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 11 May 2015 15:31:47 +0200 Subject: [PATCH 12/23] s390/sclp: replace sclp event types with proper defines Introduce TYPE_SCLP_QUIESCE and make use of it. Also use TYPE_SCLP_CPU_HOTPLUG where applicable. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/event-facility.c | 2 +- hw/s390x/sclpcpu.c | 2 +- hw/s390x/sclpquiesce.c | 4 ++-- include/hw/s390x/event-facility.h | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 7b64e782e9..ef2a05160a 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -353,7 +353,7 @@ static void init_event_facility(Object *obj) TYPE_SCLP_EVENTS_BUS, sdev, NULL); object_initialize(&event_facility->quiesce_event, sizeof(SCLPEvent), - "sclpquiesce"); + 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), diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c index 615ac06b18..322eb31d95 100644 --- a/hw/s390x/sclpcpu.c +++ b/hw/s390x/sclpcpu.c @@ -85,7 +85,7 @@ static void cpu_class_init(ObjectClass *oc, void *data) } 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 ffa5553135..15b06e108b 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, diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h index eae3b3bd63..3c1ee350c8 100644 --- a/include/hw/s390x/event-facility.h +++ b/include/hw/s390x/event-facility.h @@ -47,6 +47,7 @@ OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT) #define TYPE_SCLP_CPU_HOTPLUG "sclp-cpu-hotplug" +#define TYPE_SCLP_QUIESCE "sclpquiesce" typedef struct WriteEventMask { SCCBHeader h; From 732bdd383ee06be2655b1a849a628ff03b0000b8 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Sat, 13 Jun 2015 08:46:54 +0200 Subject: [PATCH 13/23] s390/sclp: temporarily fix unassignment/reassignment of memory subregions Commit 374f2981d1f1 ("memory: protect current_map by RCU") broke unassignment of standby memory on s390x. Looks like that the new parallelism allows races with our (semi broken) memory hotplug code. The flatview_unref() can now be executed after our unparenting. Therefore memory_region_unref() tries to unreference the MemoryRegion itself instead of the parent. In theory, MemoryRegions are now bound to separate devices that control their lifetime. We don't have this yet, so we really want to control their lifetime manually. This patch fixes it temporarily, until we have a proper rework. The only drawback is that they won't pop up in "info qom-tree", but that's better than qemu crashes. We have to release the reference to a memory region after a memory_region_find, as it automatically takes a reference. As we're now able to reassign memory, the MemoryRegion is in fact deleted (otherwise vmstate_register_ram() would complain). Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/sclp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index b3a6c5e5a4..ff29e63994 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -217,6 +217,7 @@ static void assign_storage(SCCB *sccb) (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 +243,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); } @@ -269,6 +275,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 +294,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)); } } } From 515190d9da0c85084d32d6ad36afb15a6d35729e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 27 May 2015 09:49:43 +0200 Subject: [PATCH 14/23] s390/sclp: introduce a root sclp device Let's create a root sclp device, which has other sclp devices as children (e.g. the event facility for now) and can later be used for migration of sclp specific attributes and setup of memory. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/sclp.c | 65 ++++++++++++++++++++++++++----- include/hw/s390x/event-facility.h | 2 - include/hw/s390x/sclp.h | 22 +++++++++++ 3 files changed, 78 insertions(+), 11 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index ff29e63994..14cc8c1c01 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -24,11 +24,8 @@ static inline SCLPEventFacility *get_event_facility(void) { - ObjectProperty *op = object_property_find(qdev_get_machine(), - TYPE_SCLP_EVENT_FACILITY, - NULL); - assert(op); - return op->opaque; + return EVENT_FACILITY(object_resolve_path_type("", TYPE_SCLP_EVENT_FACILITY, + NULL)); } /* Provide information about the configuration, CPUs and storage */ @@ -438,13 +435,62 @@ void sclp_service_interrupt(uint32_t sccb) 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) +{ + SCLPDevice *sclp = SCLP(dev); + Error *l_err = NULL; + + object_property_set_bool(OBJECT(sclp->event_facility), true, "realized", + &l_err); + if (l_err) { + goto error; + } + return; +error: + assert(l_err); + error_propagate(errp, l_err); +} + +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); +} + +static void sclp_class_init(ObjectClass *oc, void *data) +{ + 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); +} + +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; @@ -481,5 +527,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/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h index 3c1ee350c8..dd8881838c 100644 --- a/include/hw/s390x/event-facility.h +++ b/include/hw/s390x/event-facility.h @@ -189,8 +189,6 @@ typedef struct SCLPEventClass { OBJECT_GET_CLASS(SCLPEventFacilityClass, (obj), \ TYPE_SCLP_EVENT_FACILITY) -typedef struct SCLPEventFacility SCLPEventFacility; - typedef struct SCLPEventFacilityClass { SysBusDeviceClass parent_class; void (*command_handler)(SCLPEventFacility *ef, SCCB *sccb, uint64_t code); diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index e8a64e25b7..f243438dde 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -163,6 +163,28 @@ typedef struct SCCB { char data[SCCB_DATA_LEN]; } 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; + + /* public */ +} SCLPDevice; + +typedef struct SCLPDeviceClass { + /* private */ + DeviceClass parent_class; + + /* public */ +} SCLPDeviceClass; + typedef struct sclpMemoryHotplugDev sclpMemoryHotplugDev; #define TYPE_SCLP_MEMORY_HOTPLUG_DEV "sclp-memory-hotplug-dev" From 25a3c5af57db0319f5cfb4c439efbc78b230599e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 27 May 2015 10:04:56 +0200 Subject: [PATCH 15/23] s390/sclp: move sclp_execute related functions into the SCLP class Let's move the sclp_execute related functions into the SCLP class and pass the device state as parameter, so we have easy access to the SCLPDevice later on. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/sclp.c | 53 ++++++++++++++++++++++++++++------------- include/hw/s390x/sclp.h | 9 +++++++ 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 14cc8c1c01..c367ff8e58 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -28,8 +28,13 @@ static inline SCLPEventFacility *get_event_facility(void) NULL)); } +static inline SCLPDevice *get_sclp_device(void) +{ + 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; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); @@ -129,7 +134,7 @@ 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; @@ -155,7 +160,7 @@ 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(); @@ -176,7 +181,8 @@ 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; @@ -200,7 +206,7 @@ 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; @@ -255,7 +261,7 @@ 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; @@ -299,7 +305,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; @@ -326,34 +332,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); @@ -369,6 +376,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; @@ -403,7 +412,7 @@ 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)); @@ -474,12 +483,22 @@ static void sclp_init(Object *obj) 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; } static TypeInfo sclp_info = { diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index f243438dde..60db98cb91 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -181,8 +181,17 @@ typedef struct 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); } SCLPDeviceClass; typedef struct sclpMemoryHotplugDev sclpMemoryHotplugDev; From 1723a1b6313851d9704961e1f527312ee0a5fce4 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 13 May 2015 15:06:44 +0200 Subject: [PATCH 16/23] s390/sclp: move sclp_service_interrupt into the sclp device Let's make that function a method of the new sclp device, keeping the wrapper for existing users. We can now let go of get_event_facility(). Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/sclp.c | 21 ++++++++++++--------- include/hw/s390x/sclp.h | 1 + 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index c367ff8e58..87f4902b51 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -22,12 +22,6 @@ #include "hw/s390x/event-facility.h" #include "hw/s390x/s390-pci-bus.h" -static inline SCLPEventFacility *get_event_facility(void) -{ - return EVENT_FACILITY(object_resolve_path_type("", TYPE_SCLP_EVENT_FACILITY, - NULL)); -} - static inline SCLPDevice *get_sclp_device(void) { return SCLP(object_resolve_path_type("", TYPE_SCLP, NULL)); @@ -417,15 +411,15 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t 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; @@ -440,6 +434,14 @@ 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) @@ -499,6 +501,7 @@ static void sclp_class_init(ObjectClass *oc, void *data) 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 = { diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index 60db98cb91..50094ebcc8 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -192,6 +192,7 @@ typedef struct SCLPDeviceClass { /* public */ void (*execute)(SCLPDevice *sclp, SCCB *sccb, uint32_t code); + void (*service_interrupt)(SCLPDevice *sclp, uint32_t sccb); } SCLPDeviceClass; typedef struct sclpMemoryHotplugDev sclpMemoryHotplugDev; From 311467f77eab5c3e1f8e0f6f446201e3a1f46e70 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 29 May 2015 13:14:50 +0200 Subject: [PATCH 17/23] s390: no need to manually parse for slots and maxmem ram_slots and maxram_size has already been parsed and verified by common code for us. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 3 +-- hw/s390x/sclp.c | 11 +++-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index e2a26e95b9..d4afe7df2c 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -109,9 +109,8 @@ 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 maxmem = machine->maxram_size; ram_addr_t standby_mem_size = maxmem - my_ram_size; uint64_t kvm_limit; diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 87f4902b51..3ad5d3a5b9 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -17,7 +17,7 @@ #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" @@ -31,19 +31,14 @@ static inline SCLPDevice *get_sclp_device(void) 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++; From 2998ffee245e3a141ce1b6fca127744c3e19dc63 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 29 May 2015 13:22:12 +0200 Subject: [PATCH 18/23] s390: disallow memory hotplug for the s390-virtio machine That machine type doesn't currently support memory hotplug, so let's abort if it is requested. Reason is, that the virtio queues are allocated for now at the end of the initial ram - extending the ram is therefore not possible. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index 6cc6b5d5c4..b0f339e9fb 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" @@ -268,6 +269,10 @@ static void s390_init(MachineState *machine) hwaddr virtio_region_len; hwaddr virtio_region_start; + if (machine->ram_slots) { + error_report("Memory hotplug not supported by the selected machine."); + exit(EXIT_FAILURE); + } /* * 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 From b02ef3d92b19ad304a84433d3817f0903296ebc7 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 29 May 2015 14:06:39 +0200 Subject: [PATCH 19/23] s390/sclp: ignore memory hotplug operations if it is disabled If no memory hotplug device was created, the sclp command facility is not exposed (SCLP_FC_ASSIGN_ATTACH_READ_STOR). We therefore have no memory hotplug and should correctly report SCLP_RC_INVALID_SCLP_COMMAND if any such command is executed. This gets rid of these ugly asserts that could have been triggered for the s390-virtio machine. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/sclp.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 3ad5d3a5b9..b1a62c7180 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -130,7 +130,10 @@ static void read_storage_element0_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 ((ram_size >> mhd->increment_size) >= 0x10000) { sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); @@ -154,7 +157,10 @@ 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); @@ -177,7 +183,10 @@ static void attach_storage_element(SCLPDevice *sclp, SCCB *sccb, 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); @@ -201,10 +210,15 @@ static void assign_storage(SCLPDevice *sclp, SCCB *sccb) 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 */ @@ -255,10 +269,15 @@ 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)) { From 1cf065fb87e8787e3e9cebcdb4713b81e4e61422 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 29 May 2015 13:53:08 +0200 Subject: [PATCH 20/23] s390: move memory calculation into the sclp device The restrictions for memory calculation belong to the sclp device. Let's move the calculation to that point, so we are able to unify it for both s390 machines. The sclp device is the first device to be initialized. It performs the calculation and safely stores it in the machine, where other parts of the system can access an reuse it. The memory hotplug device is now only created when it is really needed. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 54 ++------------------------------- hw/s390x/s390-virtio.c | 18 ++--------- hw/s390x/sclp.c | 62 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 66 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index d4afe7df2c..eae1305eaf 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -102,54 +102,16 @@ static void virtio_ccw_register_hcalls(void) static void ccw_init(MachineState *machine) { - 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(); int ret; VirtualCssBus *css_bus; DeviceState *dev; - ram_addr_t pad_size = 0; - ram_addr_t maxmem = machine->maxram_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(); /* 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,21 +125,11 @@ static void ccw_init(MachineState *machine) virtio_ccw_register_hcalls(); /* allocate RAM for core */ - memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size, &error_abort); + memory_region_init_ram(ram, NULL, "s390.ram", machine->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(); diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index b0f339e9fb..c8e4737cba 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -261,10 +261,9 @@ 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; + ram_addr_t my_ram_size; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - int increment_size = 20; void *virtio_region; hwaddr virtio_region_len; hwaddr virtio_region_start; @@ -273,22 +272,11 @@ static void s390_init(MachineState *machine) error_report("Memory hotplug not supported by the selected machine."); exit(EXIT_FAILURE); } - /* - * 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++; - } - 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(); diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index b1a62c7180..ac582e804c 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -470,20 +470,80 @@ void s390_sclp_init(void) 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++; + } + } + + /* 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); @@ -495,6 +555,8 @@ static void sclp_init(Object *obj) 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) From 80d23275e3c4bc93fa6f123613d5ff389ed3fc62 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 29 May 2015 15:01:55 +0200 Subject: [PATCH 21/23] s390: unify allocation of initial memory Now that the calculation of the initial memory is hidden in the sclp device, we can unify the allocation of the initial memory. The remaining ugly part is the reserved memory for the virtio queues, but that can be cleaned up later. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 24 ++++++++++++++---------- hw/s390x/s390-virtio.c | 9 +-------- hw/s390x/s390-virtio.h | 1 + 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index eae1305eaf..27a8360207 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -100,15 +100,28 @@ 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) { MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); + + /* 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; s390_sclp_init(); + s390_memory_init(machine->ram_size); /* get a BUS */ css_bus = virtual_css_bus_init(); @@ -124,15 +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", machine->ram_size, - &error_abort); - vmstate_register_ram_global(ram); - memory_region_add_subregion(sysmem, 0, ram); - - /* 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 c8e4737cba..e4000c92e1 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -262,8 +262,6 @@ int gtod_load(QEMUFile *f, void *opaque, int version_id) static void s390_init(MachineState *machine) { ram_addr_t my_ram_size; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); void *virtio_region; hwaddr virtio_region_len; hwaddr virtio_region_start; @@ -285,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; @@ -298,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 cf687968b4..f389aa1a67 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 From 71a2fd355d8fa429bcc04740c260635e084255f2 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 1 Jun 2015 13:03:23 +0200 Subject: [PATCH 22/23] s390/sclp: store the increment_size in the sclp device Let's calculate it once and reuse it. Suggested-by: Matthew Rosato Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/sclp.c | 20 +++----------------- include/hw/s390x/sclp.h | 1 + 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index ac582e804c..0a7f4dd2f7 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -36,7 +36,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) CPUState *cpu; int cpu_count = 0; int i = 0; - int increment_size = 20; int rnsize, rnmax; int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state)); @@ -57,23 +56,9 @@ static void read_SCP_info(SCLPDevice *sclp, 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; - + rnmax = ram_size >> sclp->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) { @@ -105,7 +90,7 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) 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 { @@ -518,6 +503,7 @@ static void sclp_memory_init(SCLPDevice *sclp) 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 diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index 50094ebcc8..b0c71b5550 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -174,6 +174,7 @@ typedef struct SCLPDevice { /* private */ DeviceState parent_obj; SCLPEventFacility *event_facility; + int increment_size; /* public */ } SCLPDevice; From bd80a8ad555c2b5f79591b29edcf8196b8a5109b Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 1 Jun 2015 13:04:03 +0200 Subject: [PATCH 23/23] s390/sclp: simplify calculation of rnmax rnmax can be directly calculated using machine->maxram_size. Reviewed-by: Matthew Rosato Signed-off-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/sclp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 0a7f4dd2f7..fd277e1bf0 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -56,7 +56,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO | SCLP_HAS_PCI_RECONFIG); - rnmax = ram_size >> sclp->increment_size; /* Memory Hotplug is only supported for the ccw machine type */ if (mhd) { mhd->standby_subregion_size = MEM_SECTION_SIZE; @@ -84,8 +83,6 @@ static void read_SCP_info(SCLPDevice *sclp, 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); } @@ -98,6 +95,7 @@ static void read_SCP_info(SCLPDevice *sclp, 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 {