Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20140610' int…
Browse files Browse the repository at this point in the history
…o staging

Several patches for s390:

- bugfixes: A fix for a long-standing bug in the css code as well as
  a fixup for the recent I/O adapter support.
- Exploitation of the userspace cmma enablement/reset interface, if
  it is present.
- Some debuggability improvements by logging unmanageable conditions.
- virtio-ccw finally gets migration support for its structures.
- Some cleanup as to how floating interrupts are injected.

# gpg: Signature made Tue 10 Jun 2014 08:57:56 BST using RSA key ID C6F02FAF
# gpg: Can't check signature: public key not found

* remotes/cohuck/tags/s390x-20140610:
  s390x/kvm: inject via flic
  s390x: cleanup interrupt injection
  s390x/kvm: add alternative injection interface
  s390x: consolidate floating interrupts
  s390/virtio-ccw: migration support
  s390x/kvm: Log unmanageable program interruptions
  s390x/kvm: Log unmanageable external interruptions
  s390x/kvm: enable/reset cmma via vm attributes
  s390x/kvm: make flic play well with old kernels
  s390x/css: handle emw correctly for tsch

Signed-off-by: Peter Maydell <[email protected]>
  • Loading branch information
pm215 committed Jun 10, 2014
2 parents 7721a30 + bbd8bb8 commit 7b0140e
Show file tree
Hide file tree
Showing 10 changed files with 560 additions and 130 deletions.
16 changes: 14 additions & 2 deletions hw/intc/s390_flic_kvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ static int flic_enqueue_irqs(void *buf, uint64_t len,
return rc ? -errno : 0;
}

int kvm_s390_inject_flic(struct kvm_s390_irq *irq)
{
static KVMS390FLICState *flic;

if (unlikely(!flic)) {
flic = KVM_S390_FLIC(s390_get_flic());
}
return flic_enqueue_irqs(irq, sizeof(*irq), flic);
}

/**
* __get_all_irqs - store all pending irqs in buffer
* @flic: pointer to flic device state
Expand Down Expand Up @@ -170,7 +180,8 @@ static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
};

if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
return -ENOSYS;
/* nothing to do */
return 0;
}

r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
Expand All @@ -195,7 +206,8 @@ static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
int r;

if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
return -ENOSYS;
/* nothing to do */
return 0;
}

r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
Expand Down
150 changes: 135 additions & 15 deletions hw/s390x/css.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,11 @@ uint16_t css_build_subchannel_id(SubchDev *sch)

static void css_inject_io_interrupt(SubchDev *sch)
{
S390CPU *cpu = s390_cpu_addr2state(0);
uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11;

trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid,
sch->curr_status.pmcw.intparm, isc, "");
s390_io_interrupt(cpu,
css_build_subchannel_id(sch),
s390_io_interrupt(css_build_subchannel_id(sch),
sch->schid,
sch->curr_status.pmcw.intparm,
isc << 27);
Expand All @@ -147,7 +145,6 @@ void css_conditional_io_interrupt(SubchDev *sch)
* with alert status.
*/
if (!(sch->curr_status.scsw.ctrl & SCSW_STCTL_STATUS_PEND)) {
S390CPU *cpu = s390_cpu_addr2state(0);
uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11;

trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid,
Expand All @@ -157,8 +154,7 @@ void css_conditional_io_interrupt(SubchDev *sch)
sch->curr_status.scsw.ctrl |=
SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
/* Inject an I/O interrupt. */
s390_io_interrupt(cpu,
css_build_subchannel_id(sch),
s390_io_interrupt(css_build_subchannel_id(sch),
sch->schid,
sch->curr_status.pmcw.intparm,
isc << 27);
Expand All @@ -167,11 +163,10 @@ void css_conditional_io_interrupt(SubchDev *sch)

void css_adapter_interrupt(uint8_t isc)
{
S390CPU *cpu = s390_cpu_addr2state(0);
uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;

trace_css_adapter_interrupt(isc);
s390_io_interrupt(cpu, 0, 0, 0, io_int_word);
s390_io_interrupt(0, 0, 0, io_int_word);
}

static void sch_handle_clear_func(SubchDev *sch)
Expand Down Expand Up @@ -779,9 +774,11 @@ int css_do_ssch(SubchDev *sch, ORB *orb)
return ret;
}

static void copy_irb_to_guest(IRB *dest, const IRB *src)
static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw)
{
int i;
uint16_t stctl = src->scsw.ctrl & SCSW_CTRL_MASK_STCTL;
uint16_t actl = src->scsw.ctrl & SCSW_CTRL_MASK_ACTL;

copy_scsw_to_guest(&dest->scsw, &src->scsw);

Expand All @@ -791,8 +788,22 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src)
for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) {
dest->ecw[i] = cpu_to_be32(src->ecw[i]);
}
for (i = 0; i < ARRAY_SIZE(dest->emw); i++) {
dest->emw[i] = cpu_to_be32(src->emw[i]);
/* extended measurements enabled? */
if ((src->scsw.flags & SCSW_FLAGS_MASK_ESWF) ||
!(pmcw->flags & PMCW_FLAGS_MASK_TF) ||
!(pmcw->chars & PMCW_CHARS_MASK_XMWME)) {
return;
}
/* extended measurements pending? */
if (!(stctl & SCSW_STCTL_STATUS_PEND)) {
return;
}
if ((stctl & SCSW_STCTL_PRIMARY) ||
(stctl == SCSW_STCTL_SECONDARY) ||
((stctl & SCSW_STCTL_INTERMEDIATE) && (actl & SCSW_ACTL_SUSP))) {
for (i = 0; i < ARRAY_SIZE(dest->emw); i++) {
dest->emw[i] = cpu_to_be32(src->emw[i]);
}
}
}

Expand Down Expand Up @@ -838,7 +849,7 @@ int css_do_tsch(SubchDev *sch, IRB *target_irb)
}
}
/* Store the irb to the guest. */
copy_irb_to_guest(target_irb, &irb);
copy_irb_to_guest(target_irb, &irb, p);

/* Clear conditions on subchannel, if applicable. */
if (stctl & SCSW_STCTL_STATUS_PEND) {
Expand Down Expand Up @@ -1215,11 +1226,9 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid)
QTAILQ_INSERT_TAIL(&channel_subsys->pending_crws, crw_cont, sibling);

if (channel_subsys->do_crw_mchk) {
S390CPU *cpu = s390_cpu_addr2state(0);

channel_subsys->do_crw_mchk = false;
/* Inject crw pending machine check. */
s390_crw_mchk(cpu);
s390_crw_mchk();
}
}

Expand Down Expand Up @@ -1277,6 +1286,117 @@ int css_enable_mss(void)
return 0;
}

void subch_device_save(SubchDev *s, QEMUFile *f)
{
int i;

qemu_put_byte(f, s->cssid);
qemu_put_byte(f, s->ssid);
qemu_put_be16(f, s->schid);
qemu_put_be16(f, s->devno);
qemu_put_byte(f, s->thinint_active);
/* SCHIB */
/* PMCW */
qemu_put_be32(f, s->curr_status.pmcw.intparm);
qemu_put_be16(f, s->curr_status.pmcw.flags);
qemu_put_be16(f, s->curr_status.pmcw.devno);
qemu_put_byte(f, s->curr_status.pmcw.lpm);
qemu_put_byte(f, s->curr_status.pmcw.pnom);
qemu_put_byte(f, s->curr_status.pmcw.lpum);
qemu_put_byte(f, s->curr_status.pmcw.pim);
qemu_put_be16(f, s->curr_status.pmcw.mbi);
qemu_put_byte(f, s->curr_status.pmcw.pom);
qemu_put_byte(f, s->curr_status.pmcw.pam);
qemu_put_buffer(f, s->curr_status.pmcw.chpid, 8);
qemu_put_be32(f, s->curr_status.pmcw.chars);
/* SCSW */
qemu_put_be16(f, s->curr_status.scsw.flags);
qemu_put_be16(f, s->curr_status.scsw.ctrl);
qemu_put_be32(f, s->curr_status.scsw.cpa);
qemu_put_byte(f, s->curr_status.scsw.dstat);
qemu_put_byte(f, s->curr_status.scsw.cstat);
qemu_put_be16(f, s->curr_status.scsw.count);
qemu_put_be64(f, s->curr_status.mba);
qemu_put_buffer(f, s->curr_status.mda, 4);
/* end SCHIB */
qemu_put_buffer(f, s->sense_data, 32);
qemu_put_be64(f, s->channel_prog);
/* last cmd */
qemu_put_byte(f, s->last_cmd.cmd_code);
qemu_put_byte(f, s->last_cmd.flags);
qemu_put_be16(f, s->last_cmd.count);
qemu_put_be32(f, s->last_cmd.cda);
qemu_put_byte(f, s->last_cmd_valid);
qemu_put_byte(f, s->id.reserved);
qemu_put_be16(f, s->id.cu_type);
qemu_put_byte(f, s->id.cu_model);
qemu_put_be16(f, s->id.dev_type);
qemu_put_byte(f, s->id.dev_model);
qemu_put_byte(f, s->id.unused);
for (i = 0; i < ARRAY_SIZE(s->id.ciw); i++) {
qemu_put_byte(f, s->id.ciw[i].type);
qemu_put_byte(f, s->id.ciw[i].command);
qemu_put_be16(f, s->id.ciw[i].count);
}
return;
}

int subch_device_load(SubchDev *s, QEMUFile *f)
{
int i;

s->cssid = qemu_get_byte(f);
s->ssid = qemu_get_byte(f);
s->schid = qemu_get_be16(f);
s->devno = qemu_get_be16(f);
s->thinint_active = qemu_get_byte(f);
/* SCHIB */
/* PMCW */
s->curr_status.pmcw.intparm = qemu_get_be32(f);
s->curr_status.pmcw.flags = qemu_get_be16(f);
s->curr_status.pmcw.devno = qemu_get_be16(f);
s->curr_status.pmcw.lpm = qemu_get_byte(f);
s->curr_status.pmcw.pnom = qemu_get_byte(f);
s->curr_status.pmcw.lpum = qemu_get_byte(f);
s->curr_status.pmcw.pim = qemu_get_byte(f);
s->curr_status.pmcw.mbi = qemu_get_be16(f);
s->curr_status.pmcw.pom = qemu_get_byte(f);
s->curr_status.pmcw.pam = qemu_get_byte(f);
qemu_get_buffer(f, s->curr_status.pmcw.chpid, 8);
s->curr_status.pmcw.chars = qemu_get_be32(f);
/* SCSW */
s->curr_status.scsw.flags = qemu_get_be16(f);
s->curr_status.scsw.ctrl = qemu_get_be16(f);
s->curr_status.scsw.cpa = qemu_get_be32(f);
s->curr_status.scsw.dstat = qemu_get_byte(f);
s->curr_status.scsw.cstat = qemu_get_byte(f);
s->curr_status.scsw.count = qemu_get_be16(f);
s->curr_status.mba = qemu_get_be64(f);
qemu_get_buffer(f, s->curr_status.mda, 4);
/* end SCHIB */
qemu_get_buffer(f, s->sense_data, 32);
s->channel_prog = qemu_get_be64(f);
/* last cmd */
s->last_cmd.cmd_code = qemu_get_byte(f);
s->last_cmd.flags = qemu_get_byte(f);
s->last_cmd.count = qemu_get_be16(f);
s->last_cmd.cda = qemu_get_be32(f);
s->last_cmd_valid = qemu_get_byte(f);
s->id.reserved = qemu_get_byte(f);
s->id.cu_type = qemu_get_be16(f);
s->id.cu_model = qemu_get_byte(f);
s->id.dev_type = qemu_get_be16(f);
s->id.dev_model = qemu_get_byte(f);
s->id.unused = qemu_get_byte(f);
for (i = 0; i < ARRAY_SIZE(s->id.ciw); i++) {
s->id.ciw[i].type = qemu_get_byte(f);
s->id.ciw[i].command = qemu_get_byte(f);
s->id.ciw[i].count = qemu_get_be16(f);
}
return 0;
}


static void css_init(void)
{
channel_subsys = g_malloc0(sizeof(*channel_subsys));
Expand Down
2 changes: 2 additions & 0 deletions hw/s390x/css.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ struct SubchDev {

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);
int subch_device_load(SubchDev *s, QEMUFile *f);
int css_create_css_image(uint8_t cssid, bool default_image);
bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno);
void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
Expand Down
17 changes: 2 additions & 15 deletions hw/s390x/s390-virtio-bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@
do { } while (0)
#endif

#define VIRTIO_EXT_CODE 0x2603

static void virtio_s390_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOS390Device *dev);

Expand Down Expand Up @@ -113,15 +111,6 @@ VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size)
return bus;
}

static void s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token)
{
if (kvm_enabled()) {
kvm_s390_virtio_irq(cpu, config_change, token);
} else {
cpu_inject_ext(cpu, VIRTIO_EXT_CODE, config_change, token);
}
}

static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev)
{
VirtIOS390Bus *bus;
Expand All @@ -144,8 +133,7 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev)
s390_virtio_device_sync(dev);
s390_virtio_reset_idx(dev);
if (dev->qdev.hotplugged) {
S390CPU *cpu = s390_cpu_addr2state(0);
s390_virtio_irq(cpu, VIRTIO_PARAM_DEV_ADD, dev->dev_offs);
s390_virtio_irq(VIRTIO_PARAM_DEV_ADD, dev->dev_offs);
}

return 0;
Expand Down Expand Up @@ -489,9 +477,8 @@ 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);
S390CPU *cpu = s390_cpu_addr2state(0);

s390_virtio_irq(cpu, 0, token);
s390_virtio_irq(0, token);
}

static unsigned virtio_s390_get_features(DeviceState *d)
Expand Down
Loading

0 comments on commit 7b0140e

Please sign in to comment.