From: Tony Krowiak <akrowiak@linux.ibm.com>
To: Pierre Morel <pmorel@linux.ibm.com>, borntraeger@de.ibm.com
Cc: cohuck@redhat.com, agraf@suse.de, rth@twiddle.net,
david@redhat.com, qemu-s390x@nongnu.org, qemu-devel@nongnu.org,
peter.maydell@linaro.org, pbonzini@redhat.com, mst@redhat.com,
eric.auger@redhat.com, pasic@linux.ibm.com
Subject: Re: [Qemu-devel] [PATCH v2 6/6] s390x/vfio: ap: Implementing AP Queue Interrupt Control
Date: Thu, 29 Nov 2018 16:53:28 -0500 [thread overview]
Message-ID: <555d039d-16ef-f279-fd48-f0d422f7905a@linux.ibm.com> (raw)
In-Reply-To: <1542904555-1136-7-git-send-email-pmorel@linux.ibm.com>
On 11/22/18 11:35 AM, Pierre Morel wrote:
> We intercept the PQAP(AQIC) instruction and transform
> the guest's AQIC command parameters for the host AQIC
> parameters.
>
> Doing this we use the standard adapter interface to provide
> the adapter NIB, indicator and ISC.
>
> We define new structures, APCard and APQueue to keep track of
> the ISC, route and indicator address and we add an array of
> APCards in the APDevice.
>
> We call the VFIO ioctl to set or clear the interruption
> according to the "i" bit of the parameter.
>
> Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
> ---
> hw/vfio/ap.c | 117 ++++++++++++++++++++++++++++++++++++++++++-
> include/hw/s390x/ap-device.h | 63 +++++++++++++++++++++++
> target/s390x/kvm.c | 31 ++++++++++++
> 3 files changed, 210 insertions(+), 1 deletion(-)
>
> diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c
> index 94e5a1a..20d2e5f 100644
> --- a/hw/vfio/ap.c
> +++ b/hw/vfio/ap.c
> @@ -4,6 +4,7 @@
> * Copyright 2018 IBM Corp.
> * Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
> * Halil Pasic <pasic@linux.ibm.com>
> + * Pierre Morel <pmorel@linux.ibm.com>
> *
> * This work is licensed under the terms of the GNU GPL, version 2 or (at
> * your option) any later version. See the COPYING file in the top-level
> @@ -14,7 +15,6 @@
> #include <sys/ioctl.h>
> #include "qemu/osdep.h"
> #include "qapi/error.h"
> -#include "hw/sysbus.h"
> #include "hw/vfio/vfio.h"
> #include "hw/vfio/vfio-common.h"
> #include "hw/s390x/ap-device.h"
> @@ -27,6 +27,8 @@
> #include "sysemu/sysemu.h"
> #include "hw/s390x/ap-bridge.h"
> #include "exec/address-spaces.h"
> +#include "hw/s390x/s390_flic.h"
> +#include "hw/s390x/css.h"
>
> #define VFIO_AP_DEVICE_TYPE "vfio-ap"
>
> @@ -35,6 +37,117 @@ typedef struct VFIOAPDevice {
> VFIODevice vdev;
> } VFIOAPDevice;
>
> +static uint32_t ap_pqap_clear_irq(VFIODevice *vdev, APQueue *apq)
> +{
> + struct vfio_ap_aqic param;
> + uint32_t retval;
> +
> + param.apqn = apq->apqn;
> + param.isc = apq->isc;
> + param.argsz = sizeof(param);
> +
> + retval = ioctl(vdev->fd, VFIO_AP_CLEAR_IRQ, ¶m);
> + switch (retval) {
> + case 0: /* Fall through and return the instruction status */
Unnecessary comment, we can see the code is going to fall through and
return status. Sorry, I know its a nit.
> + release_indicator(&apq->routes.adapter, apq->nib);
> + case -EIO: /* The case the PQAP instruction failed with status */
We know it's a case statement, so leave off the "The case the".
> + return param.status;
> + default: /* The case the ioctl call failed without isuing instruction */
Same here.
> + break;
> + }
> + return ap_reg_set_status(AP_RC_INVALID_ADDR);
> +}
> +
> +static uint32_t ap_pqap_set_irq(VFIODevice *vdev, APQueue *apq, uint64_t g_nib)
> +{
> + struct vfio_ap_aqic param;
> + uint32_t retval;
> + uint32_t id;
> +
> + id = css_get_adapter_id(CSS_IO_ADAPTER_AP, apq->isc);
> + if (id == -1) {
> + return ap_reg_set_status(AP_RC_INVALID_ADDR);
> + }
> + apq->routes.adapter.adapter_id = id;
> + apq->nib = get_indicator(ldq_p(&g_nib), 8);
> +
> + retval = map_indicator(&apq->routes.adapter, apq->nib);
> + if (retval) {
> + return ap_reg_set_status(AP_RC_INVALID_ADDR);
> + }
> +
> + param.apqn = apq->apqn;
> + param.isc = apq->isc;
> + param.nib = g_nib;
> + param.adapter_id = id;
> + param.argsz = sizeof(param);
> +
> + retval = ioctl(vdev->fd, VFIO_AP_SET_IRQ, ¶m);
> + switch (retval) {
> + case -EIO: /* The case the PQAP instruction failed with status */
We know it's a case statement, so leave off the "The case the".
> + release_indicator(&apq->routes.adapter, apq->nib);
> + case 0: /* Fall through and return the instruction status */
Unnecessary comment, the code speaks for itself.
> + return param.status;
> + default: /* The case the ioctl call failed without isuing instruction */
We know it's a case statement, so leave off the "The case the".
> + break;
> + }
> + release_indicator(&apq->routes.adapter, apq->nib);
> + return ap_reg_set_status(AP_RC_INVALID_ADDR);
> +}
> +
> +static int ap_pqap_aqic(CPUS390XState *env)
> +{
> + uint64_t g_nib = env->regs[2];
> + uint8_t apid = ap_reg_get_apid(env->regs[0]);
> + uint8_t apqi = ap_reg_get_apqi(env->regs[0]);
> + uint32_t retval;
> + APDevice *ap = s390_get_ap();
To be consistent with the naming convention in the rest of
this file, can you name this variable 'apdev'?
> + VFIODevice *vdev;
> + VFIOAPDevice *ap_vdev;
To be consistent with the naming convention in the rest of
this file, can you name this variable 'vapdev'?
> + APQueue *apq;
> +
> + ap_vdev = DO_UPCAST(VFIOAPDevice, apdev, ap);
Where is 'apdev' defined/initialized?
> + vdev = &ap_vdev->vdev;
> + apq = &ap->card[apid].queue[apqi];
> + apq->isc = ap_reg_get_isc(env->regs[1]);
> + apq->apqn = (apid << 8) | apqi;
> +
> + if (ap_reg_get_ir(env->regs[1])) {
> + retval = ap_pqap_set_irq(vdev, apq, g_nib);
> + } else {
> + retval = ap_pqap_clear_irq(vdev, apq);
> + }
> +
> + env->regs[1] = retval;
> + if (retval & AP_STATUS_RC_MASK) {
> + return 3;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * ap_pqap
> + * @env: environment pointing to registers
> + * return value: Code Condition
> + */
> +int ap_pqap(CPUS390XState *env)
> +{
> + int cc = 0;
> +
> + switch (ap_reg_get_fc(env->regs[0])) {
> + case AQIC:
> + if (!s390_has_feat(S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL)) {
> + return -PGM_OPERATION;
Shouldn't this be PGM_SPECIFICATION?
> + }
> + cc = ap_pqap_aqic(env);
> + break;
> + default:
> + return -PGM_OPERATION;
> + }
> + return cc;
> +}
> +
> static void vfio_ap_compute_needs_reset(VFIODevice *vdev)
> {
> vdev->needs_reset = false;
> @@ -106,6 +219,8 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp)
> goto out_get_dev_err;
> }
>
> + css_register_io_adapters(CSS_IO_ADAPTER_AP, true, false,
> + 0, &error_abort);
> return;
>
> out_get_dev_err:
> diff --git a/include/hw/s390x/ap-device.h b/include/hw/s390x/ap-device.h
> index 5f3c840..8a36780 100644
> --- a/include/hw/s390x/ap-device.h
> +++ b/include/hw/s390x/ap-device.h
> @@ -12,8 +12,25 @@
>
> #define AP_DEVICE_TYPE "ap-device"
>
> +#define MAX_AP_CARD 256
> +#define MAX_AP_DOMAIN 256
> +
> +#include "hw/s390x/s390_flic.h"
> +#include "hw/s390x/css.h"
> +typedef struct APQueue {
> + AdapterRoutes routes;
> + IndAddr *nib;
> + uint16_t apqn;
> + uint8_t isc;
> +} APQueue;
> +
> +typedef struct APCard {
> + APQueue queue[MAX_AP_DOMAIN];
This seems to be an unnecessary allocation of memory, particularly
if there is only a few queues. I understand this
maps to the concept of a matrix and makes for quick retrieval of
an APQueue, but I think it would be more efficient to use something
like a GTree, or a GHashTable both of which would save you space and
allow for fairly quick retrieval.
> +} APCard;
> +
> typedef struct APDevice {
> DeviceState parent_obj;
> + APCard card[MAX_AP_CARD];
See comment above concerning the 'queue' field in the
APCard structure. I would also name this field 'cards'
since it represents all APCard objects.
> } APDevice;
>
> #define AP_DEVICE(obj) \
> @@ -21,4 +38,50 @@ typedef struct APDevice {
>
> APDevice *s390_get_ap(void);
>
> +#include "cpu.h"
> +int ap_pqap(CPUS390XState *env);
> +
> +/* AP PQAP commands definitions */
> +#define AQIC 0x03
> +
> +#define AP_AQIC_ZERO_BITS 0x0ff0000
> +
> +/* Register 0 hold the command and APQN */
> +static inline uint8_t ap_reg_get_apid(uint64_t r)
> +{
> + return (r >> 8) & 0xff;
> +}
> +
> +static inline uint8_t ap_reg_get_apqi(uint64_t r)
> +{
> + return r & 0xff;
> +}
> +
> +static inline uint16_t ap_reg_get_fc(uint64_t r)
> +{
> + return (r >> 24) & 0xff;
> +}
> +
> +static inline uint16_t ap_reg_get_ir(uint64_t r)
> +{
> + return (r >> 47) & 0x01;
> +}
> +
> +static inline uint16_t ap_reg_get_isc(uint64_t r)
> +{
> + return r & 0x7;
> +}
> +
> +/* AP status returned by the AP PQAP commands */
> +#define AP_STATUS_RC_MASK 0x00ff0000
> +#define AP_RC_APQN_INVALID 0x01
> +#define AP_RC_INVALID_ADDR 0x06
> +#define AP_RC_BAD_STATE 0x07
> +
> +/* Register 1 as input hold the AQIC information */
> +static inline uint32_t ap_reg_set_status(uint8_t status)
This function does not set anything, but returns an APQSW.
Maybe it should be named ap_reg_get_status_word or ap_reg_get_apqsw
or ap_reg_get_status.
> +{
> + return status << 16;
> +}
> +
> #endif /* HW_S390X_AP_DEVICE_H */
> diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
> index 2ebf26a..a4b5d90 100644
> --- a/target/s390x/kvm.c
> +++ b/target/s390x/kvm.c
> @@ -45,6 +45,7 @@
> #include "trace.h"
> #include "hw/s390x/s390-pci-inst.h"
> #include "hw/s390x/s390-pci-bus.h"
> +#include "hw/s390x/ap-device.h"
> #include "hw/s390x/ipl.h"
> #include "hw/s390x/ebcdic.h"
> #include "exec/memattrs.h"
> @@ -88,6 +89,7 @@
> #define PRIV_B2_CHSC 0x5f
> #define PRIV_B2_SIGA 0x74
> #define PRIV_B2_XSCH 0x76
> +#define PRIV_B2_PQAP 0xaf
>
> #define PRIV_EB_SQBS 0x8a
> #define PRIV_EB_PCISTB 0xd0
> @@ -1154,6 +1156,32 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
> return 0;
> }
>
> +static int kvm_ap_pqap(S390CPU *cpu, uint16_t ipbh0)
> +{
> + CPUS390XState *env = &cpu->env;
> + int r;
> +
> + if (env->psw.mask & PSW_MASK_PSTATE) {
> + kvm_s390_program_interrupt(cpu, PGM_PRIVILEGED);
> + return 0;
> + }
> +
> + if (env->regs[0] & AP_AQIC_ZERO_BITS) {
> + kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
> + return 0;
> + }
This check does not belong here; for example, if the PQAP(TAPQ)
instruction is intercepted and the T bit (bit 40) is set, a
specification exception would be erroneously recognized. This check
should be done in the ap_pqap_aqic() function.
> +
> + r = ap_pqap(&cpu->env);
> +
> + if (r < 0) {
> + kvm_s390_program_interrupt(cpu, -r);
> + } else {
> + setcc(cpu, r);
> + }
> +
> + return 0;
> +}
> +
> static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
> {
> CPUS390XState *env = &cpu->env;
> @@ -1216,6 +1244,9 @@ static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
> case PRIV_B2_SCLP_CALL:
> rc = kvm_sclp_service_call(cpu, run, ipbh0);
> break;
> + case PRIV_B2_PQAP:
> + rc = kvm_ap_pqap(cpu, ipbh0);
> + break;
> default:
> rc = -1;
> DPRINTF("KVM: unhandled PRIV: 0xb2%x\n", ipa1);
>
next prev parent reply other threads:[~2018-11-29 21:53 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-11-22 16:35 [Qemu-devel] [PATCH v2 0/6] s390x/vfio: VFIO-AP interrupt control interception Pierre Morel
2018-11-22 16:35 ` [Qemu-devel] [PATCH v2 1/6] s390x/vfio: ap: Finding the AP bridge Pierre Morel
2018-11-29 11:41 ` Cornelia Huck
2018-11-29 20:30 ` Tony Krowiak
2018-11-30 9:09 ` Pierre Morel
2018-11-22 16:35 ` [Qemu-devel] [PATCH v2 2/6] s390x/vfio: ap: Use the APdevice as a child of the APBus Pierre Morel
2018-11-29 11:45 ` Cornelia Huck
2018-11-29 12:36 ` Pierre Morel
2018-11-29 15:02 ` Tony Krowiak
2018-11-29 15:11 ` Cornelia Huck
2018-11-29 16:26 ` Pierre Morel
2018-11-29 20:42 ` Tony Krowiak
2018-11-30 9:31 ` Pierre Morel
2018-11-30 12:03 ` Pierre Morel
2018-11-30 15:58 ` Tony Krowiak
2018-12-03 8:02 ` Pierre Morel
2018-12-05 17:22 ` [Qemu-devel] [qemu-s390x] " Halil Pasic
2018-11-22 16:35 ` [Qemu-devel] [PATCH v2 3/6] s390x/vfio: ap: Linux uapi VFIO place holder Pierre Morel
2018-11-22 16:35 ` [Qemu-devel] [PATCH v2 4/6] s390x/cpumodel: Set up CPU model for AQIC interception Pierre Morel
2018-11-29 20:43 ` Tony Krowiak
2018-11-22 16:35 ` [Qemu-devel] [PATCH v2 5/6] s390x/vfio: ap: Definition for AP Adapter type Pierre Morel
2018-11-22 16:35 ` [Qemu-devel] [PATCH v2 6/6] s390x/vfio: ap: Implementing AP Queue Interrupt Control Pierre Morel
2018-11-29 21:53 ` Tony Krowiak [this message]
2018-11-30 8:36 ` Cornelia Huck
2018-11-30 11:54 ` Pierre Morel
2018-11-29 15:55 ` [Qemu-devel] [PATCH v2 0/6] s390x/vfio: VFIO-AP interrupt control interception Halil Pasic
2018-11-30 13:01 ` Pierre Morel
2018-11-30 13:31 ` Halil Pasic
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=555d039d-16ef-f279-fd48-f0d422f7905a@linux.ibm.com \
--to=akrowiak@linux.ibm.com \
--cc=agraf@suse.de \
--cc=borntraeger@de.ibm.com \
--cc=cohuck@redhat.com \
--cc=david@redhat.com \
--cc=eric.auger@redhat.com \
--cc=mst@redhat.com \
--cc=pasic@linux.ibm.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=pmorel@linux.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=rth@twiddle.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).