linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Tony Krowiak <akrowiak@linux.ibm.com>
To: linux-s390@vger.kernel.org, linux-kernel@vger.kernel.org,
	kvm@vger.kernel.org
Cc: freude@linux.ibm.com, borntraeger@de.ibm.com, cohuck@redhat.com,
	mjrosato@linux.ibm.com, pasic@linux.ibm.com,
	alex.williamson@redhat.com, kwankhede@nvidia.com,
	fiuczy@linux.ibm.com, frankja@linux.ibm.com, david@redhat.com,
	hca@linux.ibm.com, gor@linux.ibm.com,
	Tony Krowiak <akrowiak@linux.ibm.com>
Subject: [PATCH v11 08/14] s390/vfio-ap: hot plug/unplug queues on bind/unbind of queue device
Date: Thu, 22 Oct 2020 13:12:03 -0400	[thread overview]
Message-ID: <20201022171209.19494-9-akrowiak@linux.ibm.com> (raw)
In-Reply-To: <20201022171209.19494-1-akrowiak@linux.ibm.com>

In response to the probe or remove of a queue device, if a KVM guest is
using the matrix mdev to which the APQN of the queue device is assigned,
the vfio_ap device driver must respond accordingly. In an ideal world, the
queue device being probed would be hot plugged into the guest. Likewise,
the queue corresponding to the queue device being removed would
be hot unplugged from the guest. Unfortunately, the AP architecture
precludes plugging or unplugging individual queues. We must also
consider the fact that the linux device model precludes us from passing a
queue device through to a KVM guest that is not bound to the driver
facilitating the pass-through. Consequently, we are left with the choice of
plugging/unplugging the adapter or the domain. In the latter case, this
would result in taking access to the domain away for each adapter the
guest is using. In either case, the operation will alter a KVM guest's
access to one or more queues, so let's plug/unplug the adapter on
bind/unbind of the queue device since this corresponds to the hardware
entity that may be physically plugged/unplugged - i.e., a domain is not
a piece of hardware.

Example:
=======
Queue devices bound to vfio_ap device driver:
   04.0004
   04.0047
   04.0054

   05.0005
   05.0047

Adapters and domains assigned to matrix mdev:
   Adapters  Domains  -> Queues
   04        0004        04.0004
   05        0047        04.0047
             0054        04.0054
                         05.0004
                         05.0047
                         05.0054

KVM guest matrix at is startup:
   Adapters  Domains  -> Queues
   04        0004        04.0004
             0047        04.0047
             0054        04.0054

   Adapter 05 is filtered because queue 05.0054 is not bound.

KVM guest matrix after queue 05.0054 is bound to the vfio_ap driver:
   Adapters  Domains  -> Queues
   04        0004        04.0004
   05        0047        04.0047
             0054        04.0054
                         05.0004
                         05.0047
                         05.0054

   All queues assigned to the matrix mdev are now bound.

KVM guest matrix after queue 04.0004 is unbound:

   Adapters  Domains  -> Queues
   05        0004        05.0004
             0047        05.0047
             0054        05.0054

   Adapter 04 is filtered because 04.0004 is no longer bound.

Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com>
---
 drivers/s390/crypto/vfio_ap_ops.c | 158 +++++++++++++++++++++++++++++-
 1 file changed, 155 insertions(+), 3 deletions(-)

diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index 7bad70d7bcef..5b34bc8fca31 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -312,6 +312,13 @@ static int handle_pqap(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+static void vfio_ap_matrix_clear_masks(struct ap_matrix *matrix)
+{
+	bitmap_clear(matrix->apm, 0, AP_DEVICES);
+	bitmap_clear(matrix->aqm, 0, AP_DOMAINS);
+	bitmap_clear(matrix->adm, 0, AP_DOMAINS);
+}
+
 static void vfio_ap_matrix_init(struct ap_config_info *info,
 				struct ap_matrix *matrix)
 {
@@ -601,6 +608,104 @@ static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *matrix_mdev,
 	return 0;
 }
 
+static bool vfio_ap_mdev_matrixes_equal(struct ap_matrix *matrix1,
+					struct ap_matrix *matrix2)
+{
+	return (bitmap_equal(matrix1->apm, matrix2->apm, AP_DEVICES) &&
+		bitmap_equal(matrix1->aqm, matrix2->aqm, AP_DOMAINS) &&
+		bitmap_equal(matrix1->adm, matrix2->adm, AP_DOMAINS));
+}
+
+/**
+ * vfio_ap_mdev_filter_matrix
+ *
+ * Filters the matrix of adapters, domains, and control domains assigned to
+ * a matrix mdev's AP configuration and stores the result in the shadow copy of
+ * the APCB used to supply a KVM guest's AP configuration.
+ *
+ * @matrix_mdev:  the matrix mdev whose AP configuration is to be filtered
+ *
+ * Returns true if filtering has changed the shadow copy of the APCB used
+ * to supply a KVM guest's AP configuration; otherwise, returns false.
+ */
+static int vfio_ap_mdev_filter_guest_matrix(struct ap_matrix_mdev *matrix_mdev)
+{
+	struct ap_matrix shadow_apcb;
+	unsigned long apid, apqi, apqn;
+
+	memcpy(&shadow_apcb, &matrix_mdev->matrix, sizeof(struct ap_matrix));
+
+	for_each_set_bit_inv(apid, matrix_mdev->matrix.apm, AP_DEVICES) {
+		/*
+		 * If the APID is not assigned to the host AP configuration,
+		 * we can not assign it to the guest's AP configuration
+		 */
+		if (!test_bit_inv(apid,
+				  (unsigned long *)matrix_dev->info.apm)) {
+			clear_bit_inv(apid, shadow_apcb.apm);
+			continue;
+		}
+
+		for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm,
+				     AP_DOMAINS) {
+			/*
+			 * If the APQI is not assigned to the host AP
+			 * configuration, then it can not be assigned to the
+			 * guest's AP configuration
+			 */
+			if (!test_bit_inv(apqi, (unsigned long *)
+					  matrix_dev->info.aqm)) {
+				clear_bit_inv(apqi, shadow_apcb.aqm);
+				continue;
+			}
+
+			/*
+			 * If the APQN is not bound to the vfio_ap device
+			 * driver, then we can't assign it to the guest's
+			 * AP configuration. The AP architecture won't
+			 * allow filtering of a single APQN, so let's filter
+			 * the APID.
+			 */
+			apqn = AP_MKQID(apid, apqi);
+			if (!vfio_ap_mdev_get_queue(matrix_mdev, apqn)) {
+				clear_bit_inv(apid, shadow_apcb.apm);
+				break;
+			}
+		}
+
+		/*
+		 * If all APIDs have been cleared, then clear the APQIs from the
+		 * shadow APCB and quit filtering.
+		 */
+		if (bitmap_empty(shadow_apcb.apm, AP_DEVICES)) {
+			if (!bitmap_empty(shadow_apcb.aqm, AP_DOMAINS))
+				bitmap_clear(shadow_apcb.aqm, 0, AP_DOMAINS);
+
+			break;
+		}
+
+		/*
+		 * If all APQIs have been cleared, then clear the APIDs from the
+		 * shadow APCB and quit filtering.
+		 */
+		if (bitmap_empty(shadow_apcb.aqm, AP_DOMAINS)) {
+			if (!bitmap_empty(shadow_apcb.apm, AP_DEVICES))
+				bitmap_clear(shadow_apcb.apm, 0, AP_DEVICES);
+
+			break;
+		}
+	}
+
+	if (vfio_ap_mdev_matrixes_equal(&matrix_mdev->shadow_apcb,
+					&shadow_apcb))
+		return false;
+
+	memcpy(&matrix_mdev->shadow_apcb, &shadow_apcb,
+	       sizeof(struct ap_matrix));
+
+	return true;
+}
+
 enum qlink_type {
 	LINK_APID,
 	LINK_APQI,
@@ -1256,9 +1361,8 @@ static int vfio_ap_mdev_group_notifier(struct notifier_block *nb,
 	if (!vfio_ap_mdev_has_crycb(matrix_mdev))
 		return NOTIFY_DONE;
 
-	memcpy(&matrix_mdev->shadow_apcb, &matrix_mdev->matrix,
-	       sizeof(matrix_mdev->shadow_apcb));
-	vfio_ap_mdev_commit_shadow_apcb(matrix_mdev);
+	if (vfio_ap_mdev_filter_guest_matrix(matrix_mdev))
+		vfio_ap_mdev_commit_shadow_apcb(matrix_mdev);
 
 	return NOTIFY_OK;
 }
@@ -1369,6 +1473,18 @@ static void vfio_ap_mdev_release(struct mdev_device *mdev)
 		matrix_mdev->kvm = NULL;
 	}
 
+	/*
+	 * The shadow_apcb must be cleared.
+	 *
+	 * The shadow_apcb is committed to the guest only if the masks resulting
+	 * from filtering the matrix_mdev->matrix differs from the masks in the
+	 * shadow_apcb. Consequently, if we don't clear the masks here and a
+	 * guest is subsequently started, the filtering may not result in a
+	 * change to the shadow_apcb which will not get committed to the guest;
+	 * in that case, the guest will be left without any queues.
+	 */
+	vfio_ap_matrix_clear_masks(&matrix_mdev->shadow_apcb);
+
 	mutex_unlock(&matrix_dev->lock);
 
 	vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
@@ -1466,6 +1582,16 @@ static void vfio_ap_queue_link_mdev(struct vfio_ap_queue *q)
 	}
 }
 
+static void vfio_ap_mdev_hot_plug_queue(struct vfio_ap_queue *q)
+{
+
+	if ((q->matrix_mdev == NULL) || !vfio_ap_mdev_has_crycb(q->matrix_mdev))
+		return;
+
+	if (vfio_ap_mdev_filter_guest_matrix(q->matrix_mdev))
+		vfio_ap_mdev_commit_shadow_apcb(q->matrix_mdev);
+}
+
 int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
 {
 	struct vfio_ap_queue *q;
@@ -1482,11 +1608,36 @@ int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
 	q->apqn = queue->qid;
 	q->saved_isc = VFIO_AP_ISC_INVALID;
 	vfio_ap_queue_link_mdev(q);
+	vfio_ap_mdev_hot_plug_queue(q);
 	mutex_unlock(&matrix_dev->lock);
 
 	return 0;
 }
 
+void vfio_ap_mdev_hot_unplug_queue(struct vfio_ap_queue *q)
+{
+	unsigned long apid = AP_QID_CARD(q->apqn);
+
+	if ((q->matrix_mdev == NULL) || !vfio_ap_mdev_has_crycb(q->matrix_mdev))
+		return;
+
+	/*
+	 * If the APID is assigned to the guest, then let's
+	 * go ahead and unplug the adapter since the
+	 * architecture does not provide a means to unplug
+	 * an individual queue.
+	 */
+	if (test_bit_inv(apid, q->matrix_mdev->shadow_apcb.apm)) {
+		clear_bit_inv(apid, q->matrix_mdev->shadow_apcb.apm);
+
+		if (bitmap_empty(q->matrix_mdev->shadow_apcb.apm, AP_DEVICES))
+			bitmap_clear(q->matrix_mdev->shadow_apcb.aqm, 0,
+				     AP_DOMAINS);
+
+		vfio_ap_mdev_commit_shadow_apcb(q->matrix_mdev);
+	}
+}
+
 void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
 {
 	struct vfio_ap_queue *q;
@@ -1497,6 +1648,7 @@ void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
 
 	mutex_lock(&matrix_dev->lock);
 	q = dev_get_drvdata(&queue->ap_dev.device);
+	vfio_ap_mdev_hot_unplug_queue(q);
 	dev_set_drvdata(&queue->ap_dev.device, NULL);
 	apid = AP_QID_CARD(q->apqn);
 	apqi = AP_QID_QUEUE(q->apqn);
-- 
2.21.1


  parent reply	other threads:[~2020-10-22 17:12 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-22 17:11 [PATCH v11 00/14] s390/vfio-ap: dynamic configuration support Tony Krowiak
2020-10-22 17:11 ` [PATCH v11 01/14] s390/vfio-ap: No need to disable IRQ after queue reset Tony Krowiak
2020-10-22 19:44   ` kernel test robot
2020-10-26 16:57     ` Tony Krowiak
2020-10-27  6:48   ` Halil Pasic
2020-10-29 23:29     ` Tony Krowiak
2020-10-30 16:13       ` Tony Krowiak
2020-10-30 17:27       ` Halil Pasic
2020-10-30 20:45         ` Tony Krowiak
2020-10-30 17:42       ` Halil Pasic
2020-10-30 20:37         ` Tony Krowiak
2020-10-31  3:43           ` Halil Pasic
2020-11-02 14:35             ` Tony Krowiak
2020-10-30 17:54       ` Halil Pasic
2020-10-30 20:53         ` Tony Krowiak
2020-10-30 21:13           ` Tony Krowiak
2020-10-30 17:56       ` Halil Pasic
2020-10-30 21:17         ` Tony Krowiak
2020-10-22 17:11 ` [PATCH v11 02/14] 390/vfio-ap: use new AP bus interface to search for queue devices Tony Krowiak
2020-10-27  7:01   ` Halil Pasic
2020-11-02 21:57     ` Tony Krowiak
2020-10-22 17:11 ` [PATCH v11 03/14] s390/vfio-ap: manage link between queue struct and matrix mdev Tony Krowiak
2020-10-27  9:33   ` Halil Pasic
2020-10-22 17:11 ` [PATCH v11 04/14] s390/zcrypt: driver callback to indicate resource in use Tony Krowiak
2020-10-27 13:01   ` Halil Pasic
2020-10-27 16:55   ` Harald Freudenberger
2020-11-13 21:30     ` Tony Krowiak
2020-11-14  0:00       ` Halil Pasic
2020-11-16 16:23         ` Tony Krowiak
2020-10-22 17:12 ` [PATCH v11 05/14] s390/vfio-ap: implement in-use callback for vfio_ap driver Tony Krowiak
2020-10-27 13:27   ` Halil Pasic
2020-11-13 17:14     ` Tony Krowiak
2020-11-13 23:47       ` Halil Pasic
2020-11-16 16:58         ` Tony Krowiak
2020-11-23 17:03         ` Cornelia Huck
2020-11-23 19:23           ` Tony Krowiak
2020-10-22 17:12 ` [PATCH v11 06/14] s390/vfio-ap: introduce shadow APCB Tony Krowiak
2020-10-28  8:11   ` Halil Pasic
2020-11-13 17:18     ` Tony Krowiak
2020-10-22 17:12 ` [PATCH v11 07/14] s390/vfio-ap: sysfs attribute to display the guest's matrix Tony Krowiak
2020-10-28  8:17   ` Halil Pasic
2020-11-13 17:27     ` Tony Krowiak
2020-11-13 23:12       ` Halil Pasic
2020-11-19 18:15         ` Tony Krowiak
2020-10-22 17:12 ` Tony Krowiak [this message]
2020-10-22 20:30   ` [PATCH v11 08/14] s390/vfio-ap: hot plug/unplug queues on bind/unbind of queue device kernel test robot
2020-10-26 17:04     ` Tony Krowiak
2020-10-28 13:57   ` Halil Pasic
2020-11-03 22:49     ` Tony Krowiak
2020-11-04 12:52       ` Halil Pasic
2020-11-04 21:20         ` Tony Krowiak
2020-11-05 12:27           ` Halil Pasic
2020-11-13 20:36             ` Tony Krowiak
2020-11-04 13:23       ` Halil Pasic
2020-10-22 17:12 ` [PATCH v11 09/14] s390/vfio-ap: allow assignment of unavailable AP queues to mdev device Tony Krowiak
2020-10-28 15:03   ` Halil Pasic
2020-10-22 17:12 ` [PATCH v11 10/14] s390/vfio-ap: allow hot plug/unplug of AP resources using " Tony Krowiak
2020-10-22 17:12 ` [PATCH v11 11/14] s390/zcrypt: Notify driver on config changed and scan complete callbacks Tony Krowiak
2020-10-27 17:28   ` Harald Freudenberger
2020-11-13 20:58     ` Tony Krowiak
2020-10-22 17:12 ` [PATCH v11 12/14] s390/vfio-ap: handle host AP config change notification Tony Krowiak
2020-10-22 21:17   ` kernel test robot
2020-10-26 17:07     ` Tony Krowiak
2020-10-26 17:21     ` Tony Krowiak
2020-11-03  9:48   ` kernel test robot
2020-11-13 21:06     ` Tony Krowiak
2020-10-22 17:12 ` [PATCH v11 13/14] s390/vfio-ap: handle AP bus scan completed notification Tony Krowiak
2020-10-22 17:12 ` [PATCH v11 14/14] s390/vfio-ap: update docs to include dynamic config support Tony Krowiak

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=20201022171209.19494-9-akrowiak@linux.ibm.com \
    --to=akrowiak@linux.ibm.com \
    --cc=alex.williamson@redhat.com \
    --cc=borntraeger@de.ibm.com \
    --cc=cohuck@redhat.com \
    --cc=david@redhat.com \
    --cc=fiuczy@linux.ibm.com \
    --cc=frankja@linux.ibm.com \
    --cc=freude@linux.ibm.com \
    --cc=gor@linux.ibm.com \
    --cc=hca@linux.ibm.com \
    --cc=kvm@vger.kernel.org \
    --cc=kwankhede@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=mjrosato@linux.ibm.com \
    --cc=pasic@linux.ibm.com \
    /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).