summaryrefslogtreecommitdiff
path: root/hw/s390x
diff options
context:
space:
mode:
Diffstat (limited to 'hw/s390x')
-rw-r--r--hw/s390x/Makefile.objs2
-rw-r--r--hw/s390x/css.c265
-rw-r--r--hw/s390x/css.h15
-rw-r--r--hw/s390x/event-facility.c2
-rw-r--r--hw/s390x/ipl.c20
-rw-r--r--hw/s390x/s390-pci-bus.c17
-rw-r--r--hw/s390x/s390-pci-bus.h3
-rw-r--r--hw/s390x/s390-pci-inst.c46
-rw-r--r--hw/s390x/s390-skeys-kvm.c3
-rw-r--r--hw/s390x/s390-skeys.c22
-rw-r--r--hw/s390x/s390-virtio-bus.c758
-rw-r--r--hw/s390x/s390-virtio-bus.h186
-rw-r--r--hw/s390x/s390-virtio-ccw.c143
-rw-r--r--hw/s390x/s390-virtio-hcall.c1
-rw-r--r--hw/s390x/s390-virtio.c209
-rw-r--r--hw/s390x/s390-virtio.h2
-rw-r--r--hw/s390x/sclp.c31
-rw-r--r--hw/s390x/sclpcpu.c1
-rw-r--r--hw/s390x/sclpquiesce.c1
-rw-r--r--hw/s390x/virtio-ccw.c68
-rw-r--r--hw/s390x/virtio-ccw.h13
21 files changed, 403 insertions, 1405 deletions
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index 527d75400..220361782 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -1,4 +1,4 @@
-obj-y = s390-virtio-bus.o s390-virtio.o
+obj-y += s390-virtio.o
obj-y += s390-virtio-hcall.o
obj-y += sclp.o
obj-y += event-facility.o
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index c6ca8bec4..3a1d91958 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -9,6 +9,7 @@
* directory.
*/
+#include "qemu/osdep.h"
#include <hw/qdev.h>
#include "qemu/bitops.h"
#include "exec/address-spaces.h"
@@ -49,6 +50,7 @@ typedef struct IoAdapter {
typedef struct ChannelSubSys {
QTAILQ_HEAD(, CrwContainer) pending_crws;
+ bool sei_pending;
bool do_crw_mchk;
bool crws_lost;
uint8_t max_cssid;
@@ -58,9 +60,81 @@ typedef struct ChannelSubSys {
CssImage *css[MAX_CSSID + 1];
uint8_t default_cssid;
QTAILQ_HEAD(, IoAdapter) io_adapters;
+ QTAILQ_HEAD(, IndAddr) indicator_addresses;
} ChannelSubSys;
-static ChannelSubSys *channel_subsys;
+static ChannelSubSys channel_subsys = {
+ .pending_crws = QTAILQ_HEAD_INITIALIZER(channel_subsys.pending_crws),
+ .do_crw_mchk = true,
+ .sei_pending = false,
+ .do_crw_mchk = true,
+ .crws_lost = false,
+ .chnmon_active = false,
+ .io_adapters = QTAILQ_HEAD_INITIALIZER(channel_subsys.io_adapters),
+ .indicator_addresses =
+ QTAILQ_HEAD_INITIALIZER(channel_subsys.indicator_addresses),
+};
+
+IndAddr *get_indicator(hwaddr ind_addr, int len)
+{
+ IndAddr *indicator;
+
+ QTAILQ_FOREACH(indicator, &channel_subsys.indicator_addresses, sibling) {
+ if (indicator->addr == ind_addr) {
+ indicator->refcnt++;
+ return indicator;
+ }
+ }
+ indicator = g_new0(IndAddr, 1);
+ indicator->addr = ind_addr;
+ indicator->len = len;
+ indicator->refcnt = 1;
+ QTAILQ_INSERT_TAIL(&channel_subsys.indicator_addresses,
+ indicator, sibling);
+ return indicator;
+}
+
+static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr,
+ bool do_map)
+{
+ S390FLICState *fs = s390_get_flic();
+ S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+
+ return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map);
+}
+
+void release_indicator(AdapterInfo *adapter, IndAddr *indicator)
+{
+ assert(indicator->refcnt > 0);
+ indicator->refcnt--;
+ if (indicator->refcnt > 0) {
+ return;
+ }
+ QTAILQ_REMOVE(&channel_subsys.indicator_addresses, indicator, sibling);
+ if (indicator->map) {
+ s390_io_adapter_map(adapter, indicator->map, false);
+ }
+ g_free(indicator);
+}
+
+int map_indicator(AdapterInfo *adapter, IndAddr *indicator)
+{
+ int ret;
+
+ if (indicator->map) {
+ return 0; /* already mapped is not an error */
+ }
+ indicator->map = indicator->addr;
+ ret = s390_io_adapter_map(adapter, indicator->map, true);
+ if ((ret != 0) && (ret != -ENOSYS)) {
+ goto out_err;
+ }
+ return 0;
+
+out_err:
+ indicator->map = 0;
+ return ret;
+}
int css_create_css_image(uint8_t cssid, bool default_image)
{
@@ -68,12 +142,12 @@ int css_create_css_image(uint8_t cssid, bool default_image)
if (cssid > MAX_CSSID) {
return -EINVAL;
}
- if (channel_subsys->css[cssid]) {
+ if (channel_subsys.css[cssid]) {
return -EBUSY;
}
- channel_subsys->css[cssid] = g_malloc0(sizeof(CssImage));
+ channel_subsys.css[cssid] = g_malloc0(sizeof(CssImage));
if (default_image) {
- channel_subsys->default_cssid = cssid;
+ channel_subsys.default_cssid = cssid;
}
return 0;
}
@@ -88,7 +162,7 @@ int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
*id = 0;
- QTAILQ_FOREACH(adapter, &channel_subsys->io_adapters, sibling) {
+ QTAILQ_FOREACH(adapter, &channel_subsys.io_adapters, sibling) {
if ((adapter->type == type) && (adapter->isc == isc)) {
*id = adapter->id;
found = true;
@@ -108,7 +182,7 @@ int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
adapter->id = *id;
adapter->isc = isc;
adapter->type = type;
- QTAILQ_INSERT_TAIL(&channel_subsys->io_adapters, adapter, sibling);
+ QTAILQ_INSERT_TAIL(&channel_subsys.io_adapters, adapter, sibling);
} else {
g_free(adapter);
fprintf(stderr, "Unexpected error %d when registering adapter %d\n",
@@ -120,7 +194,7 @@ out:
uint16_t css_build_subchannel_id(SubchDev *sch)
{
- if (channel_subsys->max_cssid > 0) {
+ if (channel_subsys.max_cssid > 0) {
return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1;
}
return (sch->ssid << 1) | 1;
@@ -268,7 +342,8 @@ static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1)
return ret;
}
-static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr)
+static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
+ bool suspend_allowed)
{
int ret;
bool check_len;
@@ -296,7 +371,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr)
}
if (ccw.flags & CCW_FLAG_SUSPEND) {
- return -EINPROGRESS;
+ return suspend_allowed ? -EINPROGRESS : -EINVAL;
}
check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC));
@@ -394,6 +469,7 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
SCSW *s = &sch->curr_status.scsw;
int path;
int ret;
+ bool suspend_allowed;
/* Path management: In our simple css, we always choose the only path. */
path = 0x80;
@@ -413,12 +489,15 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
}
sch->ccw_fmt_1 = !!(orb->ctrl0 & ORB_CTRL0_MASK_FMT);
sch->ccw_no_data_cnt = 0;
+ suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND);
} else {
s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND);
+ /* The channel program had been suspended before. */
+ suspend_allowed = true;
}
sch->last_cmd_valid = false;
do {
- ret = css_interpret_ccw(sch, sch->channel_prog);
+ ret = css_interpret_ccw(sch, sch->channel_prog, suspend_allowed);
switch (ret) {
case -EAGAIN:
/* ccw chain, continue processing */
@@ -776,12 +855,12 @@ static void css_update_chnmon(SubchDev *sch)
offset = sch->curr_status.pmcw.mbi << 5;
count = address_space_lduw(&address_space_memory,
- channel_subsys->chnmon_area + offset,
+ channel_subsys.chnmon_area + offset,
MEMTXATTRS_UNSPECIFIED,
NULL);
count++;
address_space_stw(&address_space_memory,
- channel_subsys->chnmon_area + offset, count,
+ channel_subsys.chnmon_area + offset, count,
MEMTXATTRS_UNSPECIFIED, NULL);
}
}
@@ -810,7 +889,7 @@ int css_do_ssch(SubchDev *sch, ORB *orb)
}
/* If monitoring is active, update counter. */
- if (channel_subsys->chnmon_active) {
+ if (channel_subsys.chnmon_active) {
css_update_chnmon(sch);
}
sch->channel_prog = orb->cpa;
@@ -969,16 +1048,16 @@ int css_do_stcrw(CRW *crw)
CrwContainer *crw_cont;
int ret;
- crw_cont = QTAILQ_FIRST(&channel_subsys->pending_crws);
+ crw_cont = QTAILQ_FIRST(&channel_subsys.pending_crws);
if (crw_cont) {
- QTAILQ_REMOVE(&channel_subsys->pending_crws, crw_cont, sibling);
+ QTAILQ_REMOVE(&channel_subsys.pending_crws, crw_cont, sibling);
copy_crw_to_guest(crw, &crw_cont->crw);
g_free(crw_cont);
ret = 0;
} else {
/* List was empty, turn crw machine checks on again. */
memset(crw, 0, sizeof(*crw));
- channel_subsys->do_crw_mchk = true;
+ channel_subsys.do_crw_mchk = true;
ret = 1;
}
@@ -997,12 +1076,12 @@ void css_undo_stcrw(CRW *crw)
crw_cont = g_try_malloc0(sizeof(CrwContainer));
if (!crw_cont) {
- channel_subsys->crws_lost = true;
+ channel_subsys.crws_lost = true;
return;
}
copy_crw_from_guest(&crw_cont->crw, crw);
- QTAILQ_INSERT_HEAD(&channel_subsys->pending_crws, crw_cont, sibling);
+ QTAILQ_INSERT_HEAD(&channel_subsys.pending_crws, crw_cont, sibling);
}
int css_do_tpi(IOIntCode *int_code, int lowcore)
@@ -1020,9 +1099,9 @@ int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid,
CssImage *css;
if (!m && !cssid) {
- css = channel_subsys->css[channel_subsys->default_cssid];
+ css = channel_subsys.css[channel_subsys.default_cssid];
} else {
- css = channel_subsys->css[cssid];
+ css = channel_subsys.css[cssid];
}
if (!css) {
return 0;
@@ -1057,15 +1136,15 @@ void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo)
{
/* dct is currently ignored (not really meaningful for our devices) */
/* TODO: Don't ignore mbk. */
- if (update && !channel_subsys->chnmon_active) {
+ if (update && !channel_subsys.chnmon_active) {
/* Enable measuring. */
- channel_subsys->chnmon_area = mbo;
- channel_subsys->chnmon_active = true;
+ channel_subsys.chnmon_area = mbo;
+ channel_subsys.chnmon_active = true;
}
- if (!update && channel_subsys->chnmon_active) {
+ if (!update && channel_subsys.chnmon_active) {
/* Disable measuring. */
- channel_subsys->chnmon_area = 0;
- channel_subsys->chnmon_active = false;
+ channel_subsys.chnmon_area = 0;
+ channel_subsys.chnmon_active = false;
}
}
@@ -1093,7 +1172,7 @@ int css_do_rsch(SubchDev *sch)
}
/* If monitoring is active, update counter. */
- if (channel_subsys->chnmon_active) {
+ if (channel_subsys.chnmon_active) {
css_update_chnmon(sch);
}
@@ -1109,23 +1188,23 @@ int css_do_rchp(uint8_t cssid, uint8_t chpid)
{
uint8_t real_cssid;
- if (cssid > channel_subsys->max_cssid) {
+ if (cssid > channel_subsys.max_cssid) {
return -EINVAL;
}
- if (channel_subsys->max_cssid == 0) {
- real_cssid = channel_subsys->default_cssid;
+ if (channel_subsys.max_cssid == 0) {
+ real_cssid = channel_subsys.default_cssid;
} else {
real_cssid = cssid;
}
- if (!channel_subsys->css[real_cssid]) {
+ if (!channel_subsys.css[real_cssid]) {
return -EINVAL;
}
- if (!channel_subsys->css[real_cssid]->chpids[chpid].in_use) {
+ if (!channel_subsys.css[real_cssid]->chpids[chpid].in_use) {
return -ENODEV;
}
- if (!channel_subsys->css[real_cssid]->chpids[chpid].is_virtual) {
+ if (!channel_subsys.css[real_cssid]->chpids[chpid].is_virtual) {
fprintf(stderr,
"rchp unsupported for non-virtual chpid %x.%02x!\n",
real_cssid, chpid);
@@ -1134,8 +1213,8 @@ int css_do_rchp(uint8_t cssid, uint8_t chpid)
/* We don't really use a channel path, so we're done here. */
css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT,
- channel_subsys->max_cssid > 0 ? 1 : 0, chpid);
- if (channel_subsys->max_cssid > 0) {
+ channel_subsys.max_cssid > 0 ? 1 : 0, chpid);
+ if (channel_subsys.max_cssid > 0) {
css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, 0, real_cssid << 8);
}
return 0;
@@ -1146,13 +1225,13 @@ bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid)
SubchSet *set;
uint8_t real_cssid;
- real_cssid = (!m && (cssid == 0)) ? channel_subsys->default_cssid : cssid;
+ real_cssid = (!m && (cssid == 0)) ? channel_subsys.default_cssid : cssid;
if (real_cssid > MAX_CSSID || ssid > MAX_SSID ||
- !channel_subsys->css[real_cssid] ||
- !channel_subsys->css[real_cssid]->sch_set[ssid]) {
+ !channel_subsys.css[real_cssid] ||
+ !channel_subsys.css[real_cssid]->sch_set[ssid]) {
return true;
}
- set = channel_subsys->css[real_cssid]->sch_set[ssid];
+ set = channel_subsys.css[real_cssid]->sch_set[ssid];
return schid > find_last_bit(set->schids_used,
(MAX_SCHID + 1) / sizeof(unsigned long));
}
@@ -1165,7 +1244,7 @@ static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type)
if (cssid > MAX_CSSID) {
return -EINVAL;
}
- css = channel_subsys->css[cssid];
+ css = channel_subsys.css[cssid];
if (!css) {
return -EINVAL;
}
@@ -1186,7 +1265,7 @@ void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type)
PMCW *p = &sch->curr_status.pmcw;
SCSW *s = &sch->curr_status.scsw;
int i;
- CssImage *css = channel_subsys->css[sch->cssid];
+ CssImage *css = channel_subsys.css[sch->cssid];
assert(css != NULL);
memset(p, 0, sizeof(PMCW));
@@ -1212,27 +1291,27 @@ SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid)
{
uint8_t real_cssid;
- real_cssid = (!m && (cssid == 0)) ? channel_subsys->default_cssid : cssid;
+ real_cssid = (!m && (cssid == 0)) ? channel_subsys.default_cssid : cssid;
- if (!channel_subsys->css[real_cssid]) {
+ if (!channel_subsys.css[real_cssid]) {
return NULL;
}
- if (!channel_subsys->css[real_cssid]->sch_set[ssid]) {
+ if (!channel_subsys.css[real_cssid]->sch_set[ssid]) {
return NULL;
}
- return channel_subsys->css[real_cssid]->sch_set[ssid]->sch[schid];
+ return channel_subsys.css[real_cssid]->sch_set[ssid]->sch[schid];
}
bool css_subch_visible(SubchDev *sch)
{
- if (sch->ssid > channel_subsys->max_ssid) {
+ if (sch->ssid > channel_subsys.max_ssid) {
return false;
}
- if (sch->cssid != channel_subsys->default_cssid) {
- return (channel_subsys->max_cssid > 0);
+ if (sch->cssid != channel_subsys.default_cssid) {
+ return (channel_subsys.max_cssid > 0);
}
return true;
@@ -1240,20 +1319,20 @@ bool css_subch_visible(SubchDev *sch)
bool css_present(uint8_t cssid)
{
- return (channel_subsys->css[cssid] != NULL);
+ return (channel_subsys.css[cssid] != NULL);
}
bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno)
{
- if (!channel_subsys->css[cssid]) {
+ if (!channel_subsys.css[cssid]) {
return false;
}
- if (!channel_subsys->css[cssid]->sch_set[ssid]) {
+ if (!channel_subsys.css[cssid]->sch_set[ssid]) {
return false;
}
return !!test_bit(devno,
- channel_subsys->css[cssid]->sch_set[ssid]->devnos_used);
+ channel_subsys.css[cssid]->sch_set[ssid]->devnos_used);
}
void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
@@ -1264,13 +1343,13 @@ void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
trace_css_assign_subch(sch ? "assign" : "deassign", cssid, ssid, schid,
devno);
- if (!channel_subsys->css[cssid]) {
+ if (!channel_subsys.css[cssid]) {
fprintf(stderr,
"Suspicious call to %s (%x.%x.%04x) for non-existing css!\n",
__func__, cssid, ssid, schid);
return;
}
- css = channel_subsys->css[cssid];
+ css = channel_subsys.css[cssid];
if (!css->sch_set[ssid]) {
css->sch_set[ssid] = g_malloc0(sizeof(SubchSet));
@@ -1295,7 +1374,7 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid)
/* TODO: Maybe use a static crw pool? */
crw_cont = g_try_malloc0(sizeof(CrwContainer));
if (!crw_cont) {
- channel_subsys->crws_lost = true;
+ channel_subsys.crws_lost = true;
return;
}
crw_cont->crw.flags = (rsc << 8) | erc;
@@ -1303,15 +1382,15 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid)
crw_cont->crw.flags |= CRW_FLAGS_MASK_C;
}
crw_cont->crw.rsid = rsid;
- if (channel_subsys->crws_lost) {
+ if (channel_subsys.crws_lost) {
crw_cont->crw.flags |= CRW_FLAGS_MASK_R;
- channel_subsys->crws_lost = false;
+ channel_subsys.crws_lost = false;
}
- QTAILQ_INSERT_TAIL(&channel_subsys->pending_crws, crw_cont, sibling);
+ QTAILQ_INSERT_TAIL(&channel_subsys.pending_crws, crw_cont, sibling);
- if (channel_subsys->do_crw_mchk) {
- channel_subsys->do_crw_mchk = false;
+ if (channel_subsys.do_crw_mchk) {
+ channel_subsys.do_crw_mchk = false;
/* Inject crw pending machine check. */
s390_crw_mchk();
}
@@ -1326,9 +1405,9 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
if (add && !hotplugged) {
return;
}
- if (channel_subsys->max_cssid == 0) {
+ if (channel_subsys.max_cssid == 0) {
/* Default cssid shows up as 0. */
- guest_cssid = (cssid == channel_subsys->default_cssid) ? 0 : cssid;
+ guest_cssid = (cssid == channel_subsys.default_cssid) ? 0 : cssid;
} else {
/* Show real cssid to the guest. */
guest_cssid = cssid;
@@ -1337,14 +1416,14 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
* Only notify for higher subchannel sets/channel subsystems if the
* guest has enabled it.
*/
- if ((ssid > channel_subsys->max_ssid) ||
- (guest_cssid > channel_subsys->max_cssid) ||
- ((channel_subsys->max_cssid == 0) &&
- (cssid != channel_subsys->default_cssid))) {
+ if ((ssid > channel_subsys.max_ssid) ||
+ (guest_cssid > channel_subsys.max_cssid) ||
+ ((channel_subsys.max_cssid == 0) &&
+ (cssid != channel_subsys.default_cssid))) {
return;
}
- chain_crw = (channel_subsys->max_ssid > 0) ||
- (channel_subsys->max_cssid > 0);
+ chain_crw = (channel_subsys.max_ssid > 0) ||
+ (channel_subsys.max_cssid > 0);
css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, chain_crw ? 1 : 0, schid);
if (chain_crw) {
css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0,
@@ -1359,20 +1438,28 @@ void css_generate_chp_crws(uint8_t cssid, uint8_t chpid)
void css_generate_css_crws(uint8_t cssid)
{
- css_queue_crw(CRW_RSC_CSS, 0, 0, cssid);
+ if (!channel_subsys.sei_pending) {
+ css_queue_crw(CRW_RSC_CSS, 0, 0, cssid);
+ }
+ channel_subsys.sei_pending = true;
+}
+
+void css_clear_sei_pending(void)
+{
+ channel_subsys.sei_pending = false;
}
int css_enable_mcsse(void)
{
trace_css_enable_facility("mcsse");
- channel_subsys->max_cssid = MAX_CSSID;
+ channel_subsys.max_cssid = MAX_CSSID;
return 0;
}
int css_enable_mss(void)
{
trace_css_enable_facility("mss");
- channel_subsys->max_ssid = MAX_SSID;
+ channel_subsys.max_ssid = MAX_SSID;
return 0;
}
@@ -1430,7 +1517,6 @@ void subch_device_save(SubchDev *s, QEMUFile *f)
}
qemu_put_byte(f, s->ccw_fmt_1);
qemu_put_byte(f, s->ccw_no_data_cnt);
- return;
}
int subch_device_load(SubchDev *s, QEMUFile *f)
@@ -1496,27 +1582,15 @@ int subch_device_load(SubchDev *s, QEMUFile *f)
*/
if (s->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA) {
if (s->ssid) {
- channel_subsys->max_ssid = MAX_SSID;
+ channel_subsys.max_ssid = MAX_SSID;
}
- if (s->cssid != channel_subsys->default_cssid) {
- channel_subsys->max_cssid = MAX_CSSID;
+ if (s->cssid != channel_subsys.default_cssid) {
+ channel_subsys.max_cssid = MAX_CSSID;
}
}
return 0;
}
-
-static void css_init(void)
-{
- channel_subsys = g_malloc0(sizeof(*channel_subsys));
- QTAILQ_INIT(&channel_subsys->pending_crws);
- channel_subsys->do_crw_mchk = true;
- channel_subsys->crws_lost = false;
- channel_subsys->chnmon_active = false;
- QTAILQ_INIT(&channel_subsys->io_adapters);
-}
-machine_init(css_init);
-
void css_reset_sch(SubchDev *sch)
{
PMCW *p = &sch->curr_status.pmcw;
@@ -1554,18 +1628,19 @@ void css_reset(void)
CrwContainer *crw_cont;
/* Clean up monitoring. */
- channel_subsys->chnmon_active = false;
- channel_subsys->chnmon_area = 0;
+ channel_subsys.chnmon_active = false;
+ channel_subsys.chnmon_area = 0;
/* Clear pending CRWs. */
- while ((crw_cont = QTAILQ_FIRST(&channel_subsys->pending_crws))) {
- QTAILQ_REMOVE(&channel_subsys->pending_crws, crw_cont, sibling);
+ while ((crw_cont = QTAILQ_FIRST(&channel_subsys.pending_crws))) {
+ QTAILQ_REMOVE(&channel_subsys.pending_crws, crw_cont, sibling);
g_free(crw_cont);
}
- channel_subsys->do_crw_mchk = true;
- channel_subsys->crws_lost = false;
+ channel_subsys.sei_pending = false;
+ channel_subsys.do_crw_mchk = true;
+ channel_subsys.crws_lost = false;
/* Reset maximum ids. */
- channel_subsys->max_cssid = 0;
- channel_subsys->max_ssid = 0;
+ channel_subsys.max_cssid = 0;
+ channel_subsys.max_ssid = 0;
}
diff --git a/hw/s390x/css.h b/hw/s390x/css.h
index a09bb1f87..a320eea59 100644
--- a/hw/s390x/css.h
+++ b/hw/s390x/css.h
@@ -12,6 +12,8 @@
#ifndef CSS_H
#define CSS_H
+#include "hw/s390x/adapter.h"
+#include "hw/s390x/s390_flic.h"
#include "ioinst.h"
/* Channel subsystem constants. */
@@ -86,6 +88,18 @@ struct SubchDev {
void *driver_data;
};
+typedef struct IndAddr {
+ hwaddr addr;
+ uint64_t map;
+ unsigned long refcnt;
+ int len;
+ QTAILQ_ENTRY(IndAddr) sibling;
+} IndAddr;
+
+IndAddr *get_indicator(hwaddr ind_addr, int len);
+void release_indicator(AdapterInfo *adapter, IndAddr *indicator);
+int map_indicator(AdapterInfo *adapter, IndAddr *indicator);
+
typedef SubchDev *(*css_subch_cb_func)(uint8_t m, uint8_t cssid, uint8_t ssid,
uint16_t schid);
void subch_device_save(SubchDev *s, QEMUFile *f);
@@ -103,6 +117,7 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
int hotplugged, int add);
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
void css_generate_css_crws(uint8_t cssid);
+void css_clear_sei_pending(void);
void css_adapter_interrupt(uint8_t isc);
#define CSS_IO_ADAPTER_VIRTIO 1
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index 907b48560..34b2faf01 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -15,6 +15,8 @@
*
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "hw/s390x/sclp.h"
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index b91fcc6e7..f10420027 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -11,6 +11,8 @@
*
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "cpu.h"
#include "elf.h"
@@ -76,7 +78,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
S390IPLState *ipl = S390_IPL(dev);
uint64_t pentry = KERN_IMAGE_START;
int kernel_size;
- Error *l_err = NULL;
+ Error *err = NULL;
int bios_size;
char *bios_filename;
@@ -94,18 +96,18 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (bios_filename == NULL) {
- error_setg(&l_err, "could not find stage1 bootloader\n");
+ error_setg(&err, "could not find stage1 bootloader");
goto error;
}
bios_size = load_elf(bios_filename, bios_translate_addr, &fwbase,
&ipl->bios_start_addr, NULL, NULL, 1,
- EM_S390, 0);
+ EM_S390, 0, 0);
if (bios_size > 0) {
/* Adjust ELF start address to final location */
ipl->bios_start_addr += fwbase;
} else {
- /* Try to load non-ELF file (e.g. s390-zipl.rom) */
+ /* Try to load non-ELF file (e.g. s390-ccw.img) */
bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
4096);
ipl->bios_start_addr = ZIPL_IMAGE_START;
@@ -113,7 +115,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
g_free(bios_filename);
if (bios_size == -1) {
- error_setg(&l_err, "could not load bootloader '%s'\n", bios_name);
+ error_setg(&err, "could not load bootloader '%s'", bios_name);
goto error;
}
@@ -123,12 +125,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
if (ipl->kernel) {
kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
- NULL, 1, EM_S390, 0);
+ NULL, 1, EM_S390, 0, 0);
if (kernel_size < 0) {
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
}
if (kernel_size < 0) {
- error_setg(&l_err, "could not load kernel '%s'\n", ipl->kernel);
+ error_setg(&err, "could not load kernel '%s'", ipl->kernel);
goto error;
}
/*
@@ -156,7 +158,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
initrd_size = load_image_targphys(ipl->initrd, initrd_offset,
ram_size - initrd_offset);
if (initrd_size == -1) {
- error_setg(&l_err, "could not load initrd '%s'\n", ipl->initrd);
+ error_setg(&err, "could not load initrd '%s'", ipl->initrd);
goto error;
}
@@ -170,7 +172,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
}
qemu_register_reset(qdev_reset_all_fn, dev);
error:
- error_propagate(errp, l_err);
+ error_propagate(errp, err);
}
static Property s390_ipl_properties[] = {
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 98c726cfc..918b58543 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -11,6 +11,9 @@
* directory.
*/
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
#include "s390-pci-bus.h"
#include <hw/pci/pci_bus.h>
#include <hw/pci/msi.h>
@@ -123,7 +126,6 @@ void s390_pci_sclp_configure(int configure, SCCB *sccb)
}
psccb->header.response_code = cpu_to_be16(rc);
- return;
}
static uint32_t s390_pci_get_pfid(PCIDevice *pdev)
@@ -318,7 +320,7 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
.perm = IOMMU_NONE,
};
- if (!pbdev->configured || !pbdev->pdev) {
+ if (!pbdev->configured || !pbdev->pdev || !(pbdev->fh & FH_ENABLED)) {
return ret;
}
@@ -429,6 +431,10 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
return;
}
+ if (!(pbdev->fh & FH_ENABLED)) {
+ return;
+ }
+
ind_bit = pbdev->routes.adapter.ind_offset;
sum_bit = pbdev->routes.adapter.summary_offset;
@@ -439,8 +445,6 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
io_int_word = (pbdev->isc << 27) | IO_INT_WORD_AI;
s390_io_interrupt(0, 0, 0, io_int_word);
}
-
- return;
}
static uint64_t s390_msi_ctrl_read(void *opaque, hwaddr addr, unsigned size)
@@ -522,7 +526,7 @@ static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev)
return 0;
}
- ctrl = pci_host_config_read_common(pbdev->pdev, pos + PCI_CAP_FLAGS,
+ ctrl = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_FLAGS,
pci_config_size(pbdev->pdev), sizeof(ctrl));
table = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_TABLE,
pci_config_size(pbdev->pdev), sizeof(table));
@@ -561,7 +565,6 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED,
pbdev->fh, pbdev->fid);
}
- return;
}
static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
@@ -596,7 +599,7 @@ static void s390_pcihost_class_init(ObjectClass *klass, void *data)
k->init = s390_pcihost_init;
hc->plug = s390_pcihost_hot_plug;
hc->unplug = s390_pcihost_hot_unplug;
- msi_supported = true;
+ msi_nonbroken = true;
}
static const TypeInfo s390_pcihost_info = {
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index 80345dacb..59fd5c958 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -23,6 +23,7 @@
#define TYPE_S390_PCI_HOST_BRIDGE "s390-pcihost"
#define FH_VIRT 0x00ff0000
#define ENABLE_BIT_OFFSET 31
+#define FH_ENABLED (1 << ENABLE_BIT_OFFSET)
#define S390_PCIPT_ADAPTER 2
#define S390_PCI_HOST_BRIDGE(obj) \
@@ -232,6 +233,8 @@ typedef struct S390PCIBusDevice {
AddressSpace as;
MemoryRegion mr;
MemoryRegion iommu_mr;
+ IndAddr *summary_ind;
+ IndAddr *indicator;
} S390PCIBusDevice;
typedef struct S390pciState {
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 8c1dc82b1..b28e7d14f 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -11,6 +11,9 @@
* directory.
*/
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
#include "s390-pci-inst.h"
#include "s390-pci-bus.h"
#include <exec/memory-internal.h>
@@ -105,7 +108,8 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID));
stw_p(&rrb->response.fh_list[idx - resume_token].vendor_id,
pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID));
- stl_p(&rrb->response.fh_list[idx - resume_token].config, 0x80000000);
+ stl_p(&rrb->response.fh_list[idx - resume_token].config,
+ pbdev->configured << 31);
stl_p(&rrb->response.fh_list[idx - resume_token].fid, pbdev->fid);
stl_p(&rrb->response.fh_list[idx - resume_token].fh, pbdev->fh);
@@ -208,12 +212,12 @@ int clp_service_call(S390CPU *cpu, uint8_t r2)
switch (reqsetpci->oc) {
case CLP_SET_ENABLE_PCI_FN:
- pbdev->fh = pbdev->fh | 1 << ENABLE_BIT_OFFSET;
+ pbdev->fh = pbdev->fh | FH_ENABLED;
stl_p(&ressetpci->fh, pbdev->fh);
stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
break;
case CLP_SET_DISABLE_PCI_FN:
- pbdev->fh = pbdev->fh & ~(1 << ENABLE_BIT_OFFSET);
+ pbdev->fh = pbdev->fh & ~FH_ENABLED;
pbdev->error_state = false;
pbdev->lgstg_blocked = false;
stl_p(&ressetpci->fh, pbdev->fh);
@@ -313,7 +317,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
offset = env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev) {
+ if (!pbdev || !(pbdev->fh & FH_ENABLED)) {
DPRINTF("pcilg no pci dev\n");
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
@@ -430,7 +434,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
offset = env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev) {
+ if (!pbdev || !(pbdev->fh & FH_ENABLED)) {
DPRINTF("pcistg no pci dev\n");
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
@@ -521,8 +525,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
end = start + env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(fh);
-
- if (!pbdev) {
+ if (!pbdev || !(pbdev->fh & FH_ENABLED)) {
DPRINTF("rpcit no pci dev\n");
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
goto out;
@@ -586,7 +589,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
}
pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev) {
+ if (!pbdev || !(pbdev->fh & FH_ENABLED)) {
DPRINTF("pcistb no pci dev fh 0x%x\n", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
@@ -620,19 +623,19 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
{
- int ret;
- S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+ int ret, len;
ret = css_register_io_adapter(S390_PCIPT_ADAPTER,
FIB_DATA_ISC(ldl_p(&fib.data)), true, false,
&pbdev->routes.adapter.adapter_id);
assert(ret == 0);
- fsc->io_adapter_map(fs, pbdev->routes.adapter.adapter_id,
- ldq_p(&fib.aisb), true);
- fsc->io_adapter_map(fs, pbdev->routes.adapter.adapter_id,
- ldq_p(&fib.aibv), true);
+ pbdev->summary_ind = get_indicator(ldq_p(&fib.aisb), sizeof(uint64_t));
+ len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long);
+ pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len);
+
+ map_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
+ map_indicator(&pbdev->routes.adapter, pbdev->indicator);
pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb);
pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data));
@@ -648,12 +651,11 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
static int dereg_irqs(S390PCIBusDevice *pbdev)
{
- S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
-
- fsc->io_adapter_map(fs, pbdev->routes.adapter.adapter_id,
- pbdev->routes.adapter.ind_addr, false);
+ release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
+ release_indicator(&pbdev->routes.adapter, pbdev->indicator);
+ pbdev->summary_ind = NULL;
+ pbdev->indicator = NULL;
pbdev->routes.adapter.summary_addr = 0;
pbdev->routes.adapter.summary_offset = 0;
pbdev->routes.adapter.ind_addr = 0;
@@ -727,7 +729,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
}
pbdev = s390_pci_find_dev_by_fh(fh);
- if (!pbdev) {
+ if (!pbdev || !(pbdev->fh & FH_ENABLED)) {
DPRINTF("mpcifc no pci dev fh 0x%x\n", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
@@ -819,7 +821,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset;
stl_p(&fib.data, data);
- if (pbdev->fh >> ENABLE_BIT_OFFSET) {
+ if (pbdev->fh & FH_ENABLED) {
fib.fc |= 0x80;
}
diff --git a/hw/s390x/s390-skeys-kvm.c b/hw/s390x/s390-skeys-kvm.c
index 682949afb..131da56bb 100644
--- a/hw/s390x/s390-skeys-kvm.c
+++ b/hw/s390x/s390-skeys-kvm.c
@@ -9,6 +9,7 @@
* directory.
*/
+#include "qemu/osdep.h"
#include "hw/s390x/storage-keys.h"
#include "sysemu/kvm.h"
#include "qemu/error-report.h"
@@ -21,7 +22,7 @@ static int kvm_s390_skeys_enabled(S390SKeysState *ss)
r = skeyclass->get_skeys(ss, 0, 1, &single_key);
if (r != 0 && r != KVM_S390_GET_SKEYS_NONE) {
- error_report("S390_GET_KEYS error %d\n", r);
+ error_report("S390_GET_KEYS error %d", r);
}
return (r == 0);
}
diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
index 539ef6d3a..6528ffed1 100644
--- a/hw/s390x/s390-skeys.c
+++ b/hw/s390x/s390-skeys.c
@@ -9,6 +9,7 @@
* directory.
*/
+#include "qemu/osdep.h"
#include "hw/boards.h"
#include "qmp-commands.h"
#include "migration/qemu-file.h"
@@ -100,8 +101,7 @@ void hmp_dump_skeys(Monitor *mon, const QDict *qdict)
qmp_dump_skeys(filename, &err);
if (err) {
- monitor_printf(mon, "%s\n", error_get_pretty(err));
- error_free(err);
+ error_report_err(err);
}
}
@@ -192,8 +192,8 @@ static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
/* Check for uint64 overflow and access beyond end of key data */
if (start_gfn + count > skeydev->key_count || start_gfn + count < count) {
error_report("Error: Setting storage keys for page beyond the end "
- "of memory: gfn=%" PRIx64 " count=%" PRId64 "\n", start_gfn,
- count);
+ "of memory: gfn=%" PRIx64 " count=%" PRId64,
+ start_gfn, count);
return -EINVAL;
}
@@ -212,8 +212,8 @@ static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
/* Check for uint64 overflow and access beyond end of key data */
if (start_gfn + count > skeydev->key_count || start_gfn + count < count) {
error_report("Error: Getting storage keys for page beyond the end "
- "of memory: gfn=%" PRIx64 " count=%" PRId64 "\n", start_gfn,
- count);
+ "of memory: gfn=%" PRIx64 " count=%" PRId64,
+ start_gfn, count);
return -EINVAL;
}
@@ -238,7 +238,7 @@ static const TypeInfo qemu_s390_skeys_info = {
.instance_init = qemu_s390_skeys_init,
.instance_size = sizeof(QEMUS390SKeysState),
.class_init = qemu_s390_skeys_class_init,
- .instance_size = sizeof(S390SKeysClass),
+ .class_size = sizeof(S390SKeysClass),
};
static void s390_storage_keys_save(QEMUFile *f, void *opaque)
@@ -257,7 +257,7 @@ static void s390_storage_keys_save(QEMUFile *f, void *opaque)
buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
if (!buf) {
- error_report("storage key save could not allocate memory\n");
+ error_report("storage key save could not allocate memory");
goto end_stream;
}
@@ -277,7 +277,7 @@ static void s390_storage_keys_save(QEMUFile *f, void *opaque)
* use S390_SKEYS_SAVE_FLAG_ERROR to indicate failure to the
* reading side.
*/
- error_report("S390_GET_KEYS error %d\n", error);
+ error_report("S390_GET_KEYS error %d", error);
memset(buf, 0, S390_SKEYS_BUFFER_SIZE);
eos = S390_SKEYS_SAVE_FLAG_ERROR;
}
@@ -315,7 +315,7 @@ static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
uint8_t *buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
if (!buf) {
- error_report("storage key load could not allocate memory\n");
+ error_report("storage key load could not allocate memory");
ret = -ENOMEM;
break;
}
@@ -327,7 +327,7 @@ static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
ret = skeyclass->set_skeys(ss, cur_gfn, cur_count, buf);
if (ret < 0) {
- error_report("S390_SET_KEYS error %d\n", ret);
+ error_report("S390_SET_KEYS error %d", ret);
break;
}
handled_count += cur_count;
diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
deleted file mode 100644
index 98cb1293c..000000000
--- a/hw/s390x/s390-virtio-bus.c
+++ /dev/null
@@ -1,758 +0,0 @@
-/*
- * QEMU S390 virtio target
- *
- * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/hw.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-rng.h"
-#include "hw/virtio/virtio-serial.h"
-#include "hw/virtio/virtio-net.h"
-#include "hw/virtio/vhost-scsi.h"
-#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
-
-#include "hw/s390x/s390-virtio-bus.h"
-#include "hw/virtio/virtio-bus.h"
-
-/* #define DEBUG_S390 */
-
-#ifdef DEBUG_S390
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
-#define VIRTIO_S390_QUEUE_MAX 64
-
-static void virtio_s390_bus_new(VirtioBusState *bus, size_t bus_size,
- VirtIOS390Device *dev);
-
-static const TypeInfo s390_virtio_bus_info = {
- .name = TYPE_S390_VIRTIO_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(VirtIOS390Bus),
-};
-
-static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev);
-
-/* length of VirtIO device pages */
-const hwaddr virtio_size = S390_DEVICE_PAGES * TARGET_PAGE_SIZE;
-
-static void s390_virtio_bus_reset(void *opaque)
-{
- VirtIOS390Bus *bus = opaque;
- bus->next_ring = bus->dev_page + TARGET_PAGE_SIZE;
-}
-
-void s390_virtio_reset_idx(VirtIOS390Device *dev)
-{
- int i;
- hwaddr idx_addr;
- uint8_t num_vq;
-
- num_vq = s390_virtio_device_num_vq(dev);
- for (i = 0; i < num_vq; i++) {
- idx_addr = virtio_queue_get_avail_addr(dev->vdev, i) +
- VIRTIO_VRING_AVAIL_IDX_OFFS;
- address_space_stw(&address_space_memory, idx_addr, 0,
- MEMTXATTRS_UNSPECIFIED, NULL);
- idx_addr = virtio_queue_get_avail_addr(dev->vdev, i) +
- virtio_queue_get_avail_size(dev->vdev, i);
- address_space_stw(&address_space_memory, idx_addr, 0,
- MEMTXATTRS_UNSPECIFIED, NULL);
- idx_addr = virtio_queue_get_used_addr(dev->vdev, i) +
- VIRTIO_VRING_USED_IDX_OFFS;
- address_space_stw(&address_space_memory, idx_addr, 0,
- MEMTXATTRS_UNSPECIFIED, NULL);
- idx_addr = virtio_queue_get_used_addr(dev->vdev, i) +
- virtio_queue_get_used_size(dev->vdev, i);
- address_space_stw(&address_space_memory, idx_addr, 0,
- MEMTXATTRS_UNSPECIFIED, NULL);
- }
-}
-
-VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size)
-{
- VirtIOS390Bus *bus;
- BusState *_bus;
- DeviceState *dev;
-
- /* Create bridge device */
- dev = qdev_create(NULL, "s390-virtio-bridge");
- qdev_init_nofail(dev);
-
- /* Create bus on bridge device */
-
- _bus = qbus_create(TYPE_S390_VIRTIO_BUS, dev, "s390-virtio");
- bus = DO_UPCAST(VirtIOS390Bus, bus, _bus);
-
- bus->dev_page = *ram_size;
- bus->dev_offs = bus->dev_page;
- bus->next_ring = bus->dev_page + TARGET_PAGE_SIZE;
-
- /* Enable hotplugging */
- qbus_set_hotplug_handler(_bus, dev, &error_abort);
-
- /* Allocate RAM for VirtIO device pages (descriptors, queues, rings) */
- *ram_size += S390_DEVICE_PAGES * TARGET_PAGE_SIZE;
-
- qemu_register_reset(s390_virtio_bus_reset, bus);
- return bus;
-}
-
-static void s390_virtio_device_init(VirtIOS390Device *dev,
- VirtIODevice *vdev)
-{
- VirtIOS390Bus *bus;
- int dev_len;
-
- bus = DO_UPCAST(VirtIOS390Bus, bus, dev->qdev.parent_bus);
- dev->vdev = vdev;
- dev->dev_offs = bus->dev_offs;
- dev->feat_len = sizeof(uint32_t); /* always keep 32 bits features */
-
- dev_len = VIRTIO_DEV_OFFS_CONFIG;
- dev_len += s390_virtio_device_num_vq(dev) * VIRTIO_VQCONFIG_LEN;
- dev_len += dev->feat_len * 2;
- dev_len += virtio_bus_get_vdev_config_len(&dev->bus);
-
- bus->dev_offs += dev_len;
-
- s390_virtio_device_sync(dev);
- s390_virtio_reset_idx(dev);
- if (dev->qdev.hotplugged) {
- s390_virtio_irq(VIRTIO_PARAM_DEV_ADD, dev->dev_offs);
- }
-}
-
-static void s390_virtio_net_realize(VirtIOS390Device *s390_dev, Error **errp)
-{
- DeviceState *qdev = DEVICE(s390_dev);
- VirtIONetS390 *dev = VIRTIO_NET_S390(s390_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- Error *err = NULL;
-
- virtio_net_set_netclient_name(&dev->vdev, qdev->id,
- object_get_typename(OBJECT(qdev)));
- qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
-}
-
-static void s390_virtio_net_instance_init(Object *obj)
-{
- VirtIONetS390 *dev = VIRTIO_NET_S390(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_NET);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static void s390_virtio_blk_realize(VirtIOS390Device *s390_dev, Error **errp)
-{
- VirtIOBlkS390 *dev = VIRTIO_BLK_S390(s390_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- Error *err = NULL;
-
- qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
-}
-
-static void s390_virtio_blk_instance_init(Object *obj)
-{
- VirtIOBlkS390 *dev = VIRTIO_BLK_S390(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_BLK);
- object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
- &error_abort);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static void s390_virtio_serial_realize(VirtIOS390Device *s390_dev, Error **errp)
-{
- VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(s390_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- DeviceState *qdev = DEVICE(s390_dev);
- Error *err = NULL;
- VirtIOS390Bus *bus;
- char *bus_name;
-
- bus = DO_UPCAST(VirtIOS390Bus, bus, qdev->parent_bus);
-
- /*
- * For command line compatibility, this sets the virtio-serial-device bus
- * name as before.
- */
- if (qdev->id) {
- bus_name = g_strdup_printf("%s.0", qdev->id);
- virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
- g_free(bus_name);
- }
-
- qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
- bus->console = s390_dev;
-}
-
-static void s390_virtio_serial_instance_init(Object *obj)
-{
- VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_SERIAL);
-}
-
-static void s390_virtio_scsi_realize(VirtIOS390Device *s390_dev, Error **errp)
-{
- VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(s390_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- DeviceState *qdev = DEVICE(s390_dev);
- Error *err = NULL;
- char *bus_name;
-
- /*
- * For command line compatibility, this sets the virtio-scsi-device bus
- * name as before.
- */
- if (qdev->id) {
- bus_name = g_strdup_printf("%s.0", qdev->id);
- virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
- g_free(bus_name);
- }
-
- qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
-}
-
-static void s390_virtio_scsi_instance_init(Object *obj)
-{
- VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_SCSI);
-}
-
-#ifdef CONFIG_VHOST_SCSI
-static void s390_vhost_scsi_realize(VirtIOS390Device *s390_dev, Error **errp)
-{
- VHostSCSIS390 *dev = VHOST_SCSI_S390(s390_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- Error *err = NULL;
-
- qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
-}
-
-static void s390_vhost_scsi_instance_init(Object *obj)
-{
- VHostSCSIS390 *dev = VHOST_SCSI_S390(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VHOST_SCSI);
-}
-#endif
-
-
-static void s390_virtio_rng_realize(VirtIOS390Device *s390_dev, Error **errp)
-{
- VirtIORNGS390 *dev = VIRTIO_RNG_S390(s390_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- Error *err = NULL;
-
- qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- object_property_set_link(OBJECT(dev),
- OBJECT(dev->vdev.conf.rng), "rng",
- NULL);
-
- s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
-}
-
-static void s390_virtio_rng_instance_init(Object *obj)
-{
- VirtIORNGS390 *dev = VIRTIO_RNG_S390(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_RNG);
- object_property_add_alias(obj, "rng", OBJECT(&dev->vdev),
- "rng", &error_abort);
-}
-
-static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
-{
- ram_addr_t token_off;
-
- token_off = (dev->dev_offs + VIRTIO_DEV_OFFS_CONFIG) +
- (vq * VIRTIO_VQCONFIG_LEN) +
- VIRTIO_VQCONFIG_OFFS_TOKEN;
-
- return address_space_ldq_be(&address_space_memory, token_off,
- MEMTXATTRS_UNSPECIFIED, NULL);
-}
-
-static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev)
-{
- VirtIODevice *vdev = dev->vdev;
- int num_vq;
-
- for (num_vq = 0; num_vq < VIRTIO_S390_QUEUE_MAX; num_vq++) {
- if (!virtio_queue_get_num(vdev, num_vq)) {
- break;
- }
- }
-
- return num_vq;
-}
-
-static ram_addr_t s390_virtio_next_ring(VirtIOS390Bus *bus)
-{
- ram_addr_t r = bus->next_ring;
-
- bus->next_ring += VIRTIO_RING_LEN;
- return r;
-}
-
-void s390_virtio_device_sync(VirtIOS390Device *dev)
-{
- VirtIOS390Bus *bus = DO_UPCAST(VirtIOS390Bus, bus, dev->qdev.parent_bus);
- ram_addr_t cur_offs;
- uint8_t num_vq;
- int i;
-
- virtio_reset(dev->vdev);
-
- /* Sync dev space */
- address_space_stb(&address_space_memory,
- dev->dev_offs + VIRTIO_DEV_OFFS_TYPE,
- dev->vdev->device_id,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
-
- address_space_stb(&address_space_memory,
- dev->dev_offs + VIRTIO_DEV_OFFS_NUM_VQ,
- s390_virtio_device_num_vq(dev),
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- address_space_stb(&address_space_memory,
- dev->dev_offs + VIRTIO_DEV_OFFS_FEATURE_LEN,
- dev->feat_len,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
-
- address_space_stb(&address_space_memory,
- dev->dev_offs + VIRTIO_DEV_OFFS_CONFIG_LEN,
- dev->vdev->config_len,
- MEMTXATTRS_UNSPECIFIED,
- NULL);
-
- num_vq = s390_virtio_device_num_vq(dev);
- address_space_stb(&address_space_memory,
- dev->dev_offs + VIRTIO_DEV_OFFS_NUM_VQ, num_vq,
- MEMTXATTRS_UNSPECIFIED, NULL);
-
- /* Sync virtqueues */
- for (i = 0; i < num_vq; i++) {
- ram_addr_t vq = (dev->dev_offs + VIRTIO_DEV_OFFS_CONFIG) +
- (i * VIRTIO_VQCONFIG_LEN);
- ram_addr_t vring;
-
- vring = s390_virtio_next_ring(bus);
- virtio_queue_set_addr(dev->vdev, i, vring);
- virtio_queue_set_vector(dev->vdev, i, i);
- address_space_stq_be(&address_space_memory,
- vq + VIRTIO_VQCONFIG_OFFS_ADDRESS, vring,
- MEMTXATTRS_UNSPECIFIED, NULL);
- address_space_stw_be(&address_space_memory,
- vq + VIRTIO_VQCONFIG_OFFS_NUM,
- virtio_queue_get_num(dev->vdev, i),
- MEMTXATTRS_UNSPECIFIED,
- NULL);
- }
-
- cur_offs = dev->dev_offs;
- cur_offs += VIRTIO_DEV_OFFS_CONFIG;
- cur_offs += num_vq * VIRTIO_VQCONFIG_LEN;
-
- /* Sync feature bitmap */
- address_space_stl_le(&address_space_memory, cur_offs,
- dev->vdev->host_features,
- MEMTXATTRS_UNSPECIFIED, NULL);
-
- dev->feat_offs = cur_offs + dev->feat_len;
- cur_offs += dev->feat_len * 2;
-
- /* Sync config space */
- virtio_bus_get_vdev_config(&dev->bus, dev->vdev->config);
-
- cpu_physical_memory_write(cur_offs,
- dev->vdev->config, dev->vdev->config_len);
- cur_offs += dev->vdev->config_len;
-}
-
-void s390_virtio_device_update_status(VirtIOS390Device *dev)
-{
- VirtIODevice *vdev = dev->vdev;
- uint32_t features;
-
- virtio_set_status(vdev,
- address_space_ldub(&address_space_memory,
- dev->dev_offs + VIRTIO_DEV_OFFS_STATUS,
- MEMTXATTRS_UNSPECIFIED, NULL));
-
- /* Update guest supported feature bitmap */
-
- features = bswap32(address_space_ldl_be(&address_space_memory,
- dev->feat_offs,
- MEMTXATTRS_UNSPECIFIED, NULL));
- virtio_set_features(vdev, features);
-}
-
-/* Find a device by vring address */
-VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
- ram_addr_t mem,
- int *vq_num)
-{
- BusChild *kid;
- int i;
-
- QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- VirtIOS390Device *dev = (VirtIOS390Device *)kid->child;
-
- for (i = 0; i < VIRTIO_S390_QUEUE_MAX; i++) {
- if (!virtio_queue_get_addr(dev->vdev, i))
- break;
- if (virtio_queue_get_addr(dev->vdev, i) == mem) {
- if (vq_num) {
- *vq_num = i;
- }
- return dev;
- }
- }
- }
-
- return NULL;
-}
-
-/* Find a device by device descriptor location */
-VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem)
-{
- BusChild *kid;
-
- QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- VirtIOS390Device *dev = (VirtIOS390Device *)kid->child;
- if (dev->dev_offs == mem) {
- return dev;
- }
- }
-
- return NULL;
-}
-
-/* DeviceState to VirtIOS390Device. Note: used on datapath,
- * be careful and test performance if you change this.
- */
-static inline VirtIOS390Device *to_virtio_s390_device_fast(DeviceState *d)
-{
- return container_of(d, VirtIOS390Device, qdev);
-}
-
-/* DeviceState to VirtIOS390Device. TODO: use QOM. */
-static inline VirtIOS390Device *to_virtio_s390_device(DeviceState *d)
-{
- return container_of(d, VirtIOS390Device, qdev);
-}
-
-static void virtio_s390_notify(DeviceState *d, uint16_t vector)
-{
- VirtIOS390Device *dev = to_virtio_s390_device_fast(d);
- uint64_t token = s390_virtio_device_vq_token(dev, vector);
-
- s390_virtio_irq(0, token);
-}
-
-static void virtio_s390_device_plugged(DeviceState *d, Error **errp)
-{
- VirtIOS390Device *dev = to_virtio_s390_device(d);
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
- int n = virtio_get_num_queues(vdev);
-
- if (n > VIRTIO_S390_QUEUE_MAX) {
- error_setg(errp, "The nubmer of virtqueues %d "
- "exceeds s390 limit %d", n,
- VIRTIO_S390_QUEUE_MAX);
- }
-}
-
-/**************** S390 Virtio Bus Device Descriptions *******************/
-
-static void s390_virtio_net_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
-
- k->realize = s390_virtio_net_realize;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
-}
-
-static const TypeInfo s390_virtio_net = {
- .name = TYPE_VIRTIO_NET_S390,
- .parent = TYPE_VIRTIO_S390_DEVICE,
- .instance_size = sizeof(VirtIONetS390),
- .instance_init = s390_virtio_net_instance_init,
- .class_init = s390_virtio_net_class_init,
-};
-
-static void s390_virtio_blk_class_init(ObjectClass *klass, void *data)
-{
- VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = s390_virtio_blk_realize;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo s390_virtio_blk = {
- .name = "virtio-blk-s390",
- .parent = TYPE_VIRTIO_S390_DEVICE,
- .instance_size = sizeof(VirtIOBlkS390),
- .instance_init = s390_virtio_blk_instance_init,
- .class_init = s390_virtio_blk_class_init,
-};
-
-static void s390_virtio_serial_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
-
- k->realize = s390_virtio_serial_realize;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo s390_virtio_serial = {
- .name = TYPE_VIRTIO_SERIAL_S390,
- .parent = TYPE_VIRTIO_S390_DEVICE,
- .instance_size = sizeof(VirtIOSerialS390),
- .instance_init = s390_virtio_serial_instance_init,
- .class_init = s390_virtio_serial_class_init,
-};
-
-static void s390_virtio_rng_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
-
- k->realize = s390_virtio_rng_realize;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo s390_virtio_rng = {
- .name = TYPE_VIRTIO_RNG_S390,
- .parent = TYPE_VIRTIO_S390_DEVICE,
- .instance_size = sizeof(VirtIORNGS390),
- .instance_init = s390_virtio_rng_instance_init,
- .class_init = s390_virtio_rng_class_init,
-};
-
-static void s390_virtio_busdev_realize(DeviceState *dev, Error **errp)
-{
- VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
- VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev);
-
- virtio_s390_bus_new(&_dev->bus, sizeof(_dev->bus), _dev);
-
- _info->realize(_dev, errp);
-}
-
-static void s390_virtio_busdev_reset(DeviceState *dev)
-{
- VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
-
- virtio_reset(_dev->vdev);
-}
-
-static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = s390_virtio_busdev_realize;
- dc->bus_type = TYPE_S390_VIRTIO_BUS;
- dc->reset = s390_virtio_busdev_reset;
-}
-
-static const TypeInfo virtio_s390_device_info = {
- .name = TYPE_VIRTIO_S390_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(VirtIOS390Device),
- .class_init = virtio_s390_device_class_init,
- .class_size = sizeof(VirtIOS390DeviceClass),
- .abstract = true,
-};
-
-static void s390_virtio_scsi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
-
- k->realize = s390_virtio_scsi_realize;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo s390_virtio_scsi = {
- .name = TYPE_VIRTIO_SCSI_S390,
- .parent = TYPE_VIRTIO_S390_DEVICE,
- .instance_size = sizeof(VirtIOSCSIS390),
- .instance_init = s390_virtio_scsi_instance_init,
- .class_init = s390_virtio_scsi_class_init,
-};
-
-#ifdef CONFIG_VHOST_SCSI
-static void s390_vhost_scsi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
-
- k->realize = s390_vhost_scsi_realize;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo s390_vhost_scsi = {
- .name = TYPE_VHOST_SCSI_S390,
- .parent = TYPE_VIRTIO_S390_DEVICE,
- .instance_size = sizeof(VHostSCSIS390),
- .instance_init = s390_vhost_scsi_instance_init,
- .class_init = s390_vhost_scsi_class_init,
-};
-#endif
-
-/***************** S390 Virtio Bus Bridge Device *******************/
-/* Only required to have the virtio bus as child in the system bus */
-
-static int s390_virtio_bridge_init(SysBusDevice *dev)
-{
- /* nothing */
- return 0;
-}
-
-static void s390_virtio_bridge_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->init = s390_virtio_bridge_init;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo s390_virtio_bridge_info = {
- .name = "s390-virtio-bridge",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysBusDevice),
- .class_init = s390_virtio_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-/* virtio-s390-bus */
-
-static void virtio_s390_bus_new(VirtioBusState *bus, size_t bus_size,
- VirtIOS390Device *dev)
-{
- DeviceState *qdev = DEVICE(dev);
- char virtio_bus_name[] = "virtio-bus";
-
- qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_S390_BUS,
- qdev, virtio_bus_name);
-}
-
-static void virtio_s390_bus_class_init(ObjectClass *klass, void *data)
-{
- VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
- BusClass *bus_class = BUS_CLASS(klass);
- bus_class->max_dev = 1;
- k->notify = virtio_s390_notify;
- k->device_plugged = virtio_s390_device_plugged;
-}
-
-static const TypeInfo virtio_s390_bus_info = {
- .name = TYPE_VIRTIO_S390_BUS,
- .parent = TYPE_VIRTIO_BUS,
- .instance_size = sizeof(VirtioS390BusState),
- .class_init = virtio_s390_bus_class_init,
-};
-
-static void s390_virtio_register_types(void)
-{
- type_register_static(&virtio_s390_bus_info);
- type_register_static(&s390_virtio_bus_info);
- type_register_static(&virtio_s390_device_info);
- type_register_static(&s390_virtio_serial);
- type_register_static(&s390_virtio_blk);
- type_register_static(&s390_virtio_net);
- type_register_static(&s390_virtio_scsi);
-#ifdef CONFIG_VHOST_SCSI
- type_register_static(&s390_vhost_scsi);
-#endif
- type_register_static(&s390_virtio_rng);
- type_register_static(&s390_virtio_bridge_info);
-}
-
-type_init(s390_virtio_register_types)
diff --git a/hw/s390x/s390-virtio-bus.h b/hw/s390x/s390-virtio-bus.h
deleted file mode 100644
index 7ad295e68..000000000
--- a/hw/s390x/s390-virtio-bus.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * QEMU S390x VirtIO BUS definitions
- *
- * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef HW_S390_VIRTIO_BUS_H
-#define HW_S390_VIRTIO_BUS_H 1
-
-#include <stddef.h>
-
-#include "standard-headers/asm-s390/kvm_virtio.h"
-#include "standard-headers/linux/virtio_ring.h"
-#include "hw/virtio/virtio-blk.h"
-#include "hw/virtio/virtio-net.h"
-#include "hw/virtio/virtio-rng.h"
-#include "hw/virtio/virtio-serial.h"
-#include "hw/virtio/virtio-scsi.h"
-#include "hw/virtio/virtio-bus.h"
-#ifdef CONFIG_VHOST_SCSI
-#include "hw/virtio/vhost-scsi.h"
-#endif
-
-typedef struct kvm_device_desc KvmDeviceDesc;
-
-#define VIRTIO_DEV_OFFS_TYPE offsetof(KvmDeviceDesc, type)
-#define VIRTIO_DEV_OFFS_NUM_VQ offsetof(KvmDeviceDesc, num_vq)
-#define VIRTIO_DEV_OFFS_FEATURE_LEN offsetof(KvmDeviceDesc, feature_len)
-#define VIRTIO_DEV_OFFS_CONFIG_LEN offsetof(KvmDeviceDesc, config_len)
-#define VIRTIO_DEV_OFFS_STATUS offsetof(KvmDeviceDesc, status)
-#define VIRTIO_DEV_OFFS_CONFIG offsetof(KvmDeviceDesc, config)
-
-typedef struct kvm_vqconfig KvmVqConfig;
-#define VIRTIO_VQCONFIG_OFFS_TOKEN offsetof(KvmVqConfig,token) /* 64 bit */
-#define VIRTIO_VQCONFIG_OFFS_ADDRESS offsetof(KvmVqConfig, address) /* 64 bit */
-#define VIRTIO_VQCONFIG_OFFS_NUM offsetof(KvmVqConfig, num) /* 16 bit */
-#define VIRTIO_VQCONFIG_LEN sizeof(KvmVqConfig)
-
-#define VIRTIO_RING_LEN (TARGET_PAGE_SIZE * 3)
-#define VIRTIO_VRING_AVAIL_IDX_OFFS offsetof(struct vring_avail, idx)
-#define VIRTIO_VRING_USED_IDX_OFFS offsetof(struct vring_used, idx)
-#define S390_DEVICE_PAGES 512
-
-#define TYPE_VIRTIO_S390_DEVICE "virtio-s390-device"
-#define VIRTIO_S390_DEVICE(obj) \
- OBJECT_CHECK(VirtIOS390Device, (obj), TYPE_VIRTIO_S390_DEVICE)
-#define VIRTIO_S390_DEVICE_CLASS(klass) \
- OBJECT_CLASS_CHECK(VirtIOS390DeviceClass, (klass), TYPE_VIRTIO_S390_DEVICE)
-#define VIRTIO_S390_DEVICE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(VirtIOS390DeviceClass, (obj), TYPE_VIRTIO_S390_DEVICE)
-
-#define TYPE_S390_VIRTIO_BUS "s390-virtio-bus"
-#define S390_VIRTIO_BUS(obj) \
- OBJECT_CHECK(VirtIOS390Bus, (obj), TYPE_S390_VIRTIO_BUS)
-
-/* virtio-s390-bus */
-
-typedef struct VirtioBusState VirtioS390BusState;
-typedef struct VirtioBusClass VirtioS390BusClass;
-
-#define TYPE_VIRTIO_S390_BUS "virtio-s390-bus"
-#define VIRTIO_S390_BUS(obj) \
- OBJECT_CHECK(VirtioS390BusState, (obj), TYPE_VIRTIO_S390_BUS)
-#define VIRTIO_S390_BUS_GET_CLASS(obj) \
- OBJECT_GET_CLASS(VirtioS390BusClass, obj, TYPE_VIRTIO_S390_BUS)
-#define VIRTIO_S390_BUS_CLASS(klass) \
- OBJECT_CLASS_CHECK(VirtioS390BusClass, klass, TYPE_VIRTIO_S390_BUS)
-
-
-typedef struct VirtIOS390Device VirtIOS390Device;
-
-typedef struct VirtIOS390DeviceClass {
- DeviceClass qdev;
- void (*realize)(VirtIOS390Device *dev, Error **errp);
-} VirtIOS390DeviceClass;
-
-struct VirtIOS390Device {
- DeviceState qdev;
- ram_addr_t dev_offs;
- ram_addr_t feat_offs;
- uint8_t feat_len;
- VirtIODevice *vdev;
- VirtioBusState bus;
-};
-
-typedef struct VirtIOS390Bus {
- BusState bus;
-
- VirtIOS390Device *console;
- ram_addr_t dev_page;
- ram_addr_t dev_offs;
- ram_addr_t next_ring;
-} VirtIOS390Bus;
-
-
-void s390_virtio_device_update_status(VirtIOS390Device *dev);
-
-VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size);
-
-VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
- ram_addr_t mem, int *vq_num);
-VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem);
-void s390_virtio_device_sync(VirtIOS390Device *dev);
-void s390_virtio_reset_idx(VirtIOS390Device *dev);
-
-/* virtio-blk-s390 */
-
-#define TYPE_VIRTIO_BLK_S390 "virtio-blk-s390"
-#define VIRTIO_BLK_S390(obj) \
- OBJECT_CHECK(VirtIOBlkS390, (obj), TYPE_VIRTIO_BLK_S390)
-
-typedef struct VirtIOBlkS390 {
- VirtIOS390Device parent_obj;
- VirtIOBlock vdev;
-} VirtIOBlkS390;
-
-/* virtio-scsi-s390 */
-
-#define TYPE_VIRTIO_SCSI_S390 "virtio-scsi-s390"
-#define VIRTIO_SCSI_S390(obj) \
- OBJECT_CHECK(VirtIOSCSIS390, (obj), TYPE_VIRTIO_SCSI_S390)
-
-typedef struct VirtIOSCSIS390 {
- VirtIOS390Device parent_obj;
- VirtIOSCSI vdev;
-} VirtIOSCSIS390;
-
-/* virtio-serial-s390 */
-
-#define TYPE_VIRTIO_SERIAL_S390 "virtio-serial-s390"
-#define VIRTIO_SERIAL_S390(obj) \
- OBJECT_CHECK(VirtIOSerialS390, (obj), TYPE_VIRTIO_SERIAL_S390)
-
-typedef struct VirtIOSerialS390 {
- VirtIOS390Device parent_obj;
- VirtIOSerial vdev;
-} VirtIOSerialS390;
-
-/* virtio-net-s390 */
-
-#define TYPE_VIRTIO_NET_S390 "virtio-net-s390"
-#define VIRTIO_NET_S390(obj) \
- OBJECT_CHECK(VirtIONetS390, (obj), TYPE_VIRTIO_NET_S390)
-
-typedef struct VirtIONetS390 {
- VirtIOS390Device parent_obj;
- VirtIONet vdev;
-} VirtIONetS390;
-
-/* vhost-scsi-s390 */
-
-#ifdef CONFIG_VHOST_SCSI
-#define TYPE_VHOST_SCSI_S390 "vhost-scsi-s390"
-#define VHOST_SCSI_S390(obj) \
- OBJECT_CHECK(VHostSCSIS390, (obj), TYPE_VHOST_SCSI_S390)
-
-typedef struct VHostSCSIS390 {
- VirtIOS390Device parent_obj;
- VHostSCSI vdev;
-} VHostSCSIS390;
-#endif
-
-/* virtio-rng-s390 */
-
-#define TYPE_VIRTIO_RNG_S390 "virtio-rng-s390"
-#define VIRTIO_RNG_S390(obj) \
- OBJECT_CHECK(VirtIORNGS390, (obj), TYPE_VIRTIO_RNG_S390)
-
-typedef struct VirtIORNGS390 {
- VirtIOS390Device parent_obj;
- VirtIORNG vdev;
-} VirtIORNGS390;
-
-#endif
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 5a52ff26e..e3df9c78b 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -9,6 +9,10 @@
* directory.
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "cpu.h"
#include "hw/boards.h"
#include "exec/address-spaces.h"
#include "s390-virtio.h"
@@ -21,20 +25,7 @@
#include "s390-pci-bus.h"
#include "hw/s390x/storage-keys.h"
#include "hw/compat.h"
-
-#define TYPE_S390_CCW_MACHINE "s390-ccw-machine"
-
-#define S390_CCW_MACHINE(obj) \
- OBJECT_CHECK(S390CcwMachineState, (obj), TYPE_S390_CCW_MACHINE)
-
-typedef struct S390CcwMachineState {
- /*< private >*/
- MachineState parent_obj;
-
- /*< public >*/
- bool aes_key_wrap;
- bool dea_key_wrap;
-} S390CcwMachineState;
+#include "hw/s390x/s390-virtio-ccw.h"
static const char *const reset_dev_types[] = {
"virtual-css-bridge",
@@ -135,7 +126,7 @@ static void ccw_init(MachineState *machine)
virtio_ccw_register_hcalls();
/* init CPUs */
- s390_init_cpus(machine->cpu_model);
+ s390_init_cpus(machine);
if (kvm_enabled()) {
kvm_s390_enable_css_support(s390_cpu_addr2state(0));
@@ -155,13 +146,54 @@ static void ccw_init(MachineState *machine)
gtod_save, gtod_load, kvm_state);
}
+static void s390_cpu_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ gchar *name;
+ S390CPU *cpu = S390_CPU(dev);
+ CPUState *cs = CPU(dev);
+
+ name = g_strdup_printf("cpu[%i]", cpu->env.cpu_num);
+ object_property_set_link(OBJECT(hotplug_dev), OBJECT(cs), name,
+ errp);
+ g_free(name);
+}
+
+static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ s390_cpu_plug(hotplug_dev, dev, errp);
+ }
+}
+
+static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
+ DeviceState *dev)
+{
+ if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ return HOTPLUG_HANDLER(machine);
+ }
+ return NULL;
+}
+
+static void s390_hot_add_cpu(const int64_t id, Error **errp)
+{
+ MachineState *machine = MACHINE(qdev_get_machine());
+ Error *err = NULL;
+
+ s390x_new_cpu(machine->cpu_model, id, &err);
+ error_propagate(errp, err);
+}
+
static void ccw_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
mc->init = ccw_init;
mc->reset = s390_machine_reset;
+ mc->hot_add_cpu = s390_hot_add_cpu;
mc->block_default_type = IF_VIRTIO;
mc->no_cdrom = 1;
mc->no_floppy = 1;
@@ -170,6 +202,8 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
mc->no_sdcard = 1;
mc->use_sclp = 1;
mc->max_cpus = 255;
+ mc->get_hotplug_handler = s390_get_hotplug_handler;
+ hc->plug = s390_machine_device_plug;
nc->nmi_monitor_handler = s390_nmi;
}
@@ -231,11 +265,45 @@ static const TypeInfo ccw_machine_info = {
.class_init = ccw_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_NMI },
+ { TYPE_HOTPLUG_HANDLER},
{ }
},
};
+#define DEFINE_CCW_MACHINE(suffix, verstr, latest) \
+ static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \
+ void *data) \
+ { \
+ MachineClass *mc = MACHINE_CLASS(oc); \
+ ccw_machine_##suffix##_class_options(mc); \
+ mc->desc = "VirtIO-ccw based S390 machine v" verstr; \
+ if (latest) { \
+ mc->alias = "s390-ccw-virtio"; \
+ mc->is_default = 1; \
+ } \
+ } \
+ static void ccw_machine_##suffix##_instance_init(Object *obj) \
+ { \
+ MachineState *machine = MACHINE(obj); \
+ ccw_machine_##suffix##_instance_options(machine); \
+ } \
+ static const TypeInfo ccw_machine_##suffix##_info = { \
+ .name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr), \
+ .parent = TYPE_S390_CCW_MACHINE, \
+ .class_init = ccw_machine_##suffix##_class_init, \
+ .instance_init = ccw_machine_##suffix##_instance_init, \
+ }; \
+ static void ccw_machine_register_##suffix(void) \
+ { \
+ type_register_static(&ccw_machine_##suffix##_info); \
+ } \
+ type_init(ccw_machine_register_##suffix)
+
+#define CCW_COMPAT_2_5 \
+ HW_COMPAT_2_5
+
#define CCW_COMPAT_2_4 \
+ CCW_COMPAT_2_5 \
HW_COMPAT_2_4 \
{\
.driver = TYPE_S390_SKEYS,\
@@ -275,44 +343,39 @@ static const TypeInfo ccw_machine_info = {
.value = "0",\
},
-static void ccw_machine_2_4_class_init(ObjectClass *oc, void *data)
+static void ccw_machine_2_6_instance_options(MachineState *machine)
{
- MachineClass *mc = MACHINE_CLASS(oc);
- static GlobalProperty compat_props[] = {
- CCW_COMPAT_2_4
- { /* end of list */ }
- };
+}
- mc->desc = "VirtIO-ccw based S390 machine v2.4";
- mc->compat_props = compat_props;
+static void ccw_machine_2_6_class_options(MachineClass *mc)
+{
}
+DEFINE_CCW_MACHINE(2_6, "2.6", true);
-static const TypeInfo ccw_machine_2_4_info = {
- .name = MACHINE_TYPE_NAME("s390-ccw-virtio-2.4"),
- .parent = TYPE_S390_CCW_MACHINE,
- .class_init = ccw_machine_2_4_class_init,
-};
+static void ccw_machine_2_5_instance_options(MachineState *machine)
+{
+}
-static void ccw_machine_2_5_class_init(ObjectClass *oc, void *data)
+static void ccw_machine_2_5_class_options(MachineClass *mc)
{
- MachineClass *mc = MACHINE_CLASS(oc);
+ SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5);
+}
+DEFINE_CCW_MACHINE(2_5, "2.5", false);
- mc->alias = "s390-ccw-virtio";
- mc->desc = "VirtIO-ccw based S390 machine v2.5";
- mc->is_default = 1;
+static void ccw_machine_2_4_instance_options(MachineState *machine)
+{
+ ccw_machine_2_5_instance_options(machine);
}
-static const TypeInfo ccw_machine_2_5_info = {
- .name = MACHINE_TYPE_NAME("s390-ccw-virtio-2.5"),
- .parent = TYPE_S390_CCW_MACHINE,
- .class_init = ccw_machine_2_5_class_init,
-};
+static void ccw_machine_2_4_class_options(MachineClass *mc)
+{
+ SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4);
+}
+DEFINE_CCW_MACHINE(2_4, "2.4", false);
static void ccw_machine_register_types(void)
{
type_register_static(&ccw_machine_info);
- type_register_static(&ccw_machine_2_4_info);
- type_register_static(&ccw_machine_2_5_info);
}
type_init(ccw_machine_register_types)
diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c
index c7bdc2005..23d67d617 100644
--- a/hw/s390x/s390-virtio-hcall.c
+++ b/hw/s390x/s390-virtio-hcall.c
@@ -9,6 +9,7 @@
* directory.
*/
+#include "qemu/osdep.h"
#include "cpu.h"
#include "hw/s390x/s390-virtio.h"
diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c
index ae55760d6..544c61643 100644
--- a/hw/s390x/s390-virtio.c
+++ b/hw/s390x/s390-virtio.c
@@ -21,6 +21,8 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/hw.h"
#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
@@ -35,7 +37,6 @@
#include "exec/address-spaces.h"
#include "sysemu/qtest.h"
-#include "hw/s390x/s390-virtio-bus.h"
#include "hw/s390x/sclp.h"
#include "hw/s390x/s390_flic.h"
#include "hw/s390x/s390-virtio.h"
@@ -54,95 +55,20 @@
#endif
#define MAX_BLK_DEVS 10
-#define ZIPL_FILENAME "s390-zipl.rom"
-#define S390_MACHINE "s390-virtio"
-#define TYPE_S390_MACHINE MACHINE_TYPE_NAME(S390_MACHINE)
#define S390_TOD_CLOCK_VALUE_MISSING 0x00
#define S390_TOD_CLOCK_VALUE_PRESENT 0x01
-static VirtIOS390Bus *s390_bus;
-static S390CPU **ipi_states;
+static S390CPU **cpu_states;
S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
{
- if (cpu_addr >= smp_cpus) {
+ if (cpu_addr >= max_cpus) {
return NULL;
}
- return ipi_states[cpu_addr];
-}
-
-static int s390_virtio_hcall_notify(const uint64_t *args)
-{
- uint64_t mem = args[0];
- int r = 0, i;
-
- if (mem > ram_size) {
- VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus, mem, &i);
- if (dev) {
- /*
- * Older kernels will use the virtqueue before setting DRIVER_OK.
- * In this case the feature bits are not yet up to date, meaning
- * that several funny things can happen, e.g. the guest thinks
- * EVENT_IDX is on and QEMU thinks it is off. Let's force a feature
- * and status sync.
- */
- if (!(dev->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- s390_virtio_device_update_status(dev);
- }
- virtio_queue_notify(dev->vdev, i);
- } else {
- r = -EINVAL;
- }
- } else {
- /* Early printk */
- }
- return r;
-}
-
-static int s390_virtio_hcall_reset(const uint64_t *args)
-{
- uint64_t mem = args[0];
- VirtIOS390Device *dev;
-
- dev = s390_virtio_bus_find_mem(s390_bus, mem);
- if (dev == NULL) {
- return -EINVAL;
- }
- virtio_reset(dev->vdev);
- address_space_stb(&address_space_memory,
- dev->dev_offs + VIRTIO_DEV_OFFS_STATUS, 0,
- MEMTXATTRS_UNSPECIFIED, NULL);
- s390_virtio_device_sync(dev);
- s390_virtio_reset_idx(dev);
-
- return 0;
-}
-
-static int s390_virtio_hcall_set_status(const uint64_t *args)
-{
- uint64_t mem = args[0];
- int r = 0;
- VirtIOS390Device *dev;
-
- dev = s390_virtio_bus_find_mem(s390_bus, mem);
- if (dev) {
- s390_virtio_device_update_status(dev);
- } else {
- r = -EINVAL;
- }
- return r;
-}
-
-static void s390_virtio_register_hcalls(void)
-{
- s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY,
- s390_virtio_hcall_notify);
- s390_register_virtio_hypercall(KVM_S390_VIRTIO_RESET,
- s390_virtio_hcall_reset);
- s390_register_virtio_hypercall(KVM_S390_VIRTIO_SET_STATUS,
- s390_virtio_hcall_set_status);
+ /* Fast lookup via CPU ID */
+ return cpu_states[cpu_addr];
}
void s390_init_ipl_dev(const char *kernel_filename,
@@ -169,26 +95,29 @@ void s390_init_ipl_dev(const char *kernel_filename,
qdev_init_nofail(dev);
}
-void s390_init_cpus(const char *cpu_model)
+void s390_init_cpus(MachineState *machine)
{
int i;
+ gchar *name;
- if (cpu_model == NULL) {
- cpu_model = "host";
+ if (machine->cpu_model == NULL) {
+ machine->cpu_model = "host";
}
- ipi_states = g_malloc(sizeof(S390CPU *) * smp_cpus);
+ cpu_states = g_new0(S390CPU *, max_cpus);
- for (i = 0; i < smp_cpus; i++) {
- S390CPU *cpu;
- CPUState *cs;
-
- cpu = cpu_s390x_init(cpu_model);
- cs = CPU(cpu);
+ for (i = 0; i < max_cpus; i++) {
+ name = g_strdup_printf("cpu[%i]", i);
+ object_property_add_link(OBJECT(machine), name, TYPE_S390_CPU,
+ (Object **) &cpu_states[i],
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_UNREF_ON_RELEASE,
+ &error_abort);
+ g_free(name);
+ }
- ipi_states[i] = cpu;
- cs->halted = 1;
- cs->exception_index = EXCP_HLT;
+ for (i = 0; i < smp_cpus; i++) {
+ s390x_new_cpu(machine->cpu_model, i, &error_fatal);
}
}
@@ -205,10 +134,7 @@ void s390_create_virtio_net(BusState *bus, const char *name)
nd->model = g_strdup("virtio");
}
- if (strcmp(nd->model, "virtio")) {
- fprintf(stderr, "S390 only supports VirtIO nics\n");
- exit(1);
- }
+ qemu_check_nic_model(nd, "virtio");
dev = qdev_create(bus, name);
qdev_set_nic_properties(dev, nd);
@@ -261,58 +187,6 @@ int gtod_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-/* PC hardware initialisation */
-static void s390_init(MachineState *machine)
-{
- ram_addr_t my_ram_size;
- void *virtio_region;
- hwaddr virtio_region_len;
- hwaddr virtio_region_start;
-
- if (!qtest_enabled()) {
- error_printf("WARNING\n"
- "The s390-virtio machine (non-ccw) is deprecated.\n"
- "It will be removed in 2.6. Please use s390-ccw-virtio\n");
- }
-
- if (machine->ram_slots) {
- error_report("Memory hotplug not supported by the selected machine.");
- exit(EXIT_FAILURE);
- }
- s390_sclp_init();
- my_ram_size = machine->ram_size;
-
- /* get a BUS */
- s390_bus = s390_virtio_bus_init(&my_ram_size);
- s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
- machine->initrd_filename, ZIPL_FILENAME, false);
- s390_flic_init();
-
- /* register hypercalls */
- s390_virtio_register_hcalls();
-
- /* allocate RAM */
- s390_memory_init(my_ram_size);
-
- /* clear virtio region */
- virtio_region_len = my_ram_size - ram_size;
- virtio_region_start = ram_size;
- virtio_region = cpu_physical_memory_map(virtio_region_start,
- &virtio_region_len, true);
- memset(virtio_region, 0, virtio_region_len);
- cpu_physical_memory_unmap(virtio_region, virtio_region_len, 1,
- virtio_region_len);
-
- /* init CPUs */
- s390_init_cpus(machine->cpu_model);
-
- /* Create VirtIO network adapters */
- s390_create_virtio_net((BusState *)s390_bus, "virtio-net-s390");
-
- /* Register savevm handler for guest TOD clock */
- register_savevm(NULL, "todclock", 0, 1, gtod_save, gtod_load, NULL);
-}
-
void s390_nmi(NMIState *n, int cpu_index, Error **errp)
{
CPUState *cs = qemu_get_cpu(cpu_index);
@@ -334,40 +208,3 @@ void s390_machine_reset(void)
s390_ipl_prepare_cpu(ipl_cpu);
s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu);
}
-
-static void s390_machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- NMIClass *nc = NMI_CLASS(oc);
-
- mc->alias = "s390";
- mc->desc = "VirtIO based S390 machine (deprecated)";
- mc->init = s390_init;
- mc->reset = s390_machine_reset;
- mc->block_default_type = IF_VIRTIO;
- mc->max_cpus = 255;
- mc->no_serial = 1;
- mc->no_parallel = 1;
- mc->use_virtcon = 1;
- mc->no_floppy = 1;
- mc->no_cdrom = 1;
- mc->no_sdcard = 1;
- nc->nmi_monitor_handler = s390_nmi;
-}
-
-static const TypeInfo s390_machine_info = {
- .name = TYPE_S390_MACHINE,
- .parent = TYPE_MACHINE,
- .class_init = s390_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_NMI },
- { }
- },
-};
-
-static void s390_machine_register_types(void)
-{
- type_register_static(&s390_machine_info);
-}
-
-type_init(s390_machine_register_types)
diff --git a/hw/s390x/s390-virtio.h b/hw/s390x/s390-virtio.h
index eebce8e5e..ffd014cb5 100644
--- a/hw/s390x/s390-virtio.h
+++ b/hw/s390x/s390-virtio.h
@@ -19,7 +19,7 @@
typedef int (*s390_virtio_fn)(const uint64_t *args);
void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn);
-void s390_init_cpus(const char *cpu_model);
+void s390_init_cpus(MachineState *machine);
void s390_init_ipl_dev(const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename,
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index a061b49f1..85dbe1b60 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -12,6 +12,8 @@
*
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "cpu.h"
#include "sysemu/kvm.h"
#include "exec/memory.h"
@@ -456,29 +458,32 @@ static void sclp_realize(DeviceState *dev, Error **errp)
{
MachineState *machine = MACHINE(qdev_get_machine());
SCLPDevice *sclp = SCLP(dev);
- Error *l_err = NULL;
+ Error *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;
+ &err);
+ if (err) {
+ goto out;
}
+ /*
+ * qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS. As long
+ * as we can't find a fitting bus via the qom tree, we have to add the
+ * event facility to the sysbus, so e.g. a sclp console can be created.
+ */
+ qdev_set_parent_bus(DEVICE(sclp->event_facility), sysbus_get_default());
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",
+ error_setg(&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;
+ error_setg(&err, "qemu: setting the guest size failed");
}
- return;
-error:
- assert(l_err);
- error_propagate(errp, l_err);
+
+out:
+ error_propagate(errp, err);
}
static void sclp_memory_init(SCLPDevice *sclp)
@@ -536,8 +541,6 @@ static void sclp_init(Object *obj)
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);
diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c
index 322eb31d9..b1f3ef8c7 100644
--- a/hw/s390x/sclpcpu.c
+++ b/hw/s390x/sclpcpu.c
@@ -12,6 +12,7 @@
* option) any later version. See the COPYING file in the top-level directory.
*
*/
+#include "qemu/osdep.h"
#include "sysemu/sysemu.h"
#include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h"
diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c
index 15b06e108..c0ecab9c3 100644
--- a/hw/s390x/sclpquiesce.c
+++ b/hw/s390x/sclpquiesce.c
@@ -11,6 +11,7 @@
* option) any later version. See the COPYING file in the top-level directory.
*
*/
+#include "qemu/osdep.h"
#include <hw/qdev.h>
#include "sysemu/sysemu.h"
#include "hw/s390x/sclp.h"
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 63da30386..d51642db0 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -10,6 +10,8 @@
* directory.
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/hw.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
@@ -31,69 +33,6 @@
#include "virtio-ccw.h"
#include "trace.h"
-static QTAILQ_HEAD(, IndAddr) indicator_addresses =
- QTAILQ_HEAD_INITIALIZER(indicator_addresses);
-
-static IndAddr *get_indicator(hwaddr ind_addr, int len)
-{
- IndAddr *indicator;
-
- QTAILQ_FOREACH(indicator, &indicator_addresses, sibling) {
- if (indicator->addr == ind_addr) {
- indicator->refcnt++;
- return indicator;
- }
- }
- indicator = g_new0(IndAddr, 1);
- indicator->addr = ind_addr;
- indicator->len = len;
- indicator->refcnt = 1;
- QTAILQ_INSERT_TAIL(&indicator_addresses, indicator, sibling);
- return indicator;
-}
-
-static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr,
- bool do_map)
-{
- S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
-
- return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map);
-}
-
-static void release_indicator(AdapterInfo *adapter, IndAddr *indicator)
-{
- assert(indicator->refcnt > 0);
- indicator->refcnt--;
- if (indicator->refcnt > 0) {
- return;
- }
- QTAILQ_REMOVE(&indicator_addresses, indicator, sibling);
- if (indicator->map) {
- s390_io_adapter_map(adapter, indicator->map, false);
- }
- g_free(indicator);
-}
-
-static int map_indicator(AdapterInfo *adapter, IndAddr *indicator)
-{
- int ret;
-
- if (indicator->map) {
- return 0; /* already mapped is not an error */
- }
- indicator->map = indicator->addr;
- ret = s390_io_adapter_map(adapter, indicator->map, true);
- if ((ret != 0) && (ret != -ENOSYS)) {
- goto out_err;
- }
- return 0;
-
-out_err:
- indicator->map = 0;
- return ret;
-}
-
static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
VirtioCcwDevice *dev);
@@ -1177,7 +1116,8 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
SubchDev *sch = dev->sch;
uint64_t indicators;
- if (vector >= 128) {
+ /* queue indicators + secondary indicators */
+ if (vector >= VIRTIO_CCW_QUEUE_MAX + 64) {
return;
}
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 7ab8367ba..66c831ba8 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -23,7 +23,8 @@
#include <hw/virtio/virtio-balloon.h>
#include <hw/virtio/virtio-rng.h>
#include <hw/virtio/virtio-bus.h>
-#include <hw/s390x/s390_flic.h>
+
+#include "css.h"
#define VIRTUAL_CSSID 0xfe
@@ -75,14 +76,6 @@ typedef struct VirtIOCCWDeviceClass {
#define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1
#define VIRTIO_CCW_FLAG_USE_IOEVENTFD (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT)
-typedef struct IndAddr {
- hwaddr addr;
- uint64_t map;
- unsigned long refcnt;
- int len;
- QTAILQ_ENTRY(IndAddr) sibling;
-} IndAddr;
-
struct VirtioCcwDevice {
DeviceState parent_obj;
SubchDev *sch;
@@ -210,7 +203,7 @@ VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch);
typedef struct V9fsCCWState {
VirtioCcwDevice parent_obj;
- V9fsState vdev;
+ V9fsVirtioState vdev;
} V9fsCCWState;
#endif /* CONFIG_VIRTFS */