Skip to contentSkip to conversation

vfio: ap: ioctl definitions for AP Queue Interrupt Control

RFC PATCH Superseded Pierre Morel 5 participants 65 messages Feb 14, 2019 – Feb 22, 2019

Subsystems (5)

v3 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

v3 cover vfio: ap: ioctl definitions for AP Queue Interrupt Control

This patch implement PQAP/AQIC interception in KVM.

To implement this we need to add a new structure, vfio_ap_queue,to be able to retrieve the mediated device associated with a queue and specific values needed to register/unregister the interrupt structures:
- APQN: to be able to issue the commands and search for queue structures
- NIB : to unpin the NIB on clear IRQ
- ISC : to unregister with the GIB interface
- MATRIX: a pointer to the matrix mediated device
- DEV: a pointer to the AP queue device from AP bus.

1) Phase 1, probe and remove from vfio_ap_queue

The vfio_ap_queue structures are dynamically allocated when a queue is probed by the ap_vfio_driver.
It is linked to the ap_queue device as the driver data. We store the APQN of the ap_queue device inside the vfio_ap_queue. The vfio_ap_queue are free during remove.

2) Phase 2, assignment of vfio_ap_queue to a mediated device

When the VFIO device is opened the queues are associated to the mediated device, at the same time the CRYCB is setup.

When the device is closed or if a queue is removed the queue is dissociated from the mediated device, as the same time the CRYCB is cleared.

Two new functions are used for this: associate/disassociate.

3) Phase 3 intercepting the PQAP/AQIC instruction

On interception of the PQAP/AQIC instruction, the interception code makes sure the pqap_hook is initialized and allowed to be called and call it.
Otherwise it reports the usual -EOPNOTSUPP return code to let QEMU handle the fault.

the pqap callback search for the queue asociated with the APQN stored in the register 0, setting the code to "illegal APQN" if the vfio_ap_queue can not be found.

Depending on the "i" bit of the register 1, the pqap callback setup or clear the interruption by calling the host format PQAP/AQIC instruction.
When seting up the interruption it uses the NIB and the guest ISC provided by the guest and the host ISC provided by the registration to the GIB code, pin the NIB and also stores ISC and NIB inside the vfio_ap_queue structure.
When clearing the interrupt it retrieves the host ISC to unregister with the GIB code and unpin the NIB.

There is a QEMU patch which is needed to enable the PQAP/AQIC facility in the guest.

Posted in [email protected] as:
Message-Id: <[email protected]>

4) Phase 4 clean dissociation from the mediated device on remove

On removing of the AP device the remove callback is called. To be sure that the guest will not access the queue anymore we clear the APID CRYCB bit.
Cleaning the APID, over the APQI, is chosen because the architecture specifies that only the APID can be dynamically changed outside IPL. After this the queue is zeroes, care is taken to correctly wait until the queue is empty.

Pierre Morel (9):
s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem
s390: ap: kvm: setting a hook for PQAP instructions
s390: ap: new vfio_ap_queue structure
s390: ap: tools to find a queue with a specific APQN
s390: ap: tools to associate a queue to a matrix
vfio: ap: register IOMMU VFIO notifier
s390: ap: implement PAPQ AQIC interception in kernel
s390: ap: Cleanup on removing the AP device
s390: ap: kvm: add AP Queue Interruption Control facility

 arch/s390/include/asm/kvm_host.h      |   1 +
 arch/s390/kvm/priv.c                  |  50 +++++
 arch/s390/tools/gen_facilities.c      |   1 +
 drivers/s390/crypto/ap_bus.h          |   1 +
 drivers/s390/crypto/vfio_ap_drv.c     | 178 ++++++++++++++++-
 drivers/s390/crypto/vfio_ap_ops.c     | 363 +++++++++++++++++++++++++++++++++-
 drivers/s390/crypto/vfio_ap_private.h |  12 ++
 7 files changed, 593 insertions(+), 13 deletions(-)
Signature · 1 line
2.7.4
#1 lore raw

PATCH v3 1/9 s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Libudev relies on having a subsystem link for non-root devices. To avoid libudev (and potentially other userspace tools) choking on the matrix device let us introduce a vfio_ap bus and with that the vfio_ap bus subsytem, and make the matrix device reside within it.

We restrict the number of allowed devices to a single one.

Doing this we need to suppress the forced link from the matrix device to the vfio_ap driver and we suppress the device_type we do not need anymore.

Since the associated matrix driver is not the vfio_ap driver any more, we have to change the search for the devices on the vfio_ap driver in the function vfio_ap_verify_queue_reserved.

---
 drivers/s390/crypto/vfio_ap_drv.c     | 63 +++++++++++++++++++++++++++++++----
 drivers/s390/crypto/vfio_ap_ops.c     |  4 +--
 drivers/s390/crypto/vfio_ap_private.h |  1 +
 3 files changed, 60 insertions(+), 8 deletions(-)
drivers/s390/crypto/vfio_ap_drv.c +57 -6
index 31c6c84..1fd5fe6 100644
@@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");
 
 static struct ap_driver vfio_ap_drv;
 
-static struct device_type vfio_ap_dev_type = {
-	.name = VFIO_AP_DEV_TYPE_NAME,
+struct matrix_driver {
+	struct device_driver drv;
+	int device_count;
 };
 
 struct ap_matrix_dev *matrix_dev;
@@ -62,6 +63,41 @@ static void vfio_ap_matrix_dev_release(struct device *dev)
 	kfree(matrix_dev);
 }
 
+static int matrix_bus_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static struct bus_type matrix_bus = {
+	.name = "vfio_ap",
+	.match = &matrix_bus_match,
+};
+
+static int matrix_probe(struct device *dev);
+static int matrix_remove(struct device *dev);
+static struct matrix_driver matrix_driver = {
+	.drv = {
+		.name = "vfio_ap",
+		.bus = &matrix_bus,
+		.probe = matrix_probe,
+		.remove = matrix_remove,
+	},
+};
+
+static int matrix_probe(struct device *dev)
+{
+	if (matrix_driver.device_count)
+		return -EEXIST;
+	matrix_driver.device_count++;
+	return 0;
+}
+
+static int matrix_remove(struct device *dev)
+{
+	matrix_driver.device_count--;
+	return 0;
+}
+
 static int vfio_ap_matrix_dev_create(void)
 {
 	int ret;
@@ -71,6 +107,10 @@ static int vfio_ap_matrix_dev_create(void)
 	if (IS_ERR(root_device))
 		return PTR_ERR(root_device);
 
+	ret = bus_register(&matrix_bus);
+	if (ret)
+		goto bus_register_err;
+
 	matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
 	if (!matrix_dev) {
 		ret = -ENOMEM;
@@ -87,30 +127,41 @@ static int vfio_ap_matrix_dev_create(void)
 	mutex_init(&matrix_dev->lock);
 	INIT_LIST_HEAD(&matrix_dev->mdev_list);
 
-	matrix_dev->device.type = &vfio_ap_dev_type;
 	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
 	matrix_dev->device.parent = root_device;
+	matrix_dev->device.bus = &matrix_bus;
 	matrix_dev->device.release = vfio_ap_matrix_dev_release;
-	matrix_dev->device.driver = &vfio_ap_drv.driver;
+	matrix_dev->vfio_ap_drv = &vfio_ap_drv;
 
 	ret = device_register(&matrix_dev->device);
 	if (ret)
 		goto matrix_reg_err;
 
+	ret = driver_register(&matrix_driver.drv);
+	if (ret)
+		goto matrix_drv_err;
+
 	return 0;
 
+matrix_drv_err:
+	device_unregister(&matrix_dev->device);
 matrix_reg_err:
 	put_device(&matrix_dev->device);
 matrix_alloc_err:
+	bus_unregister(&matrix_bus);
+bus_register_err:
 	root_device_unregister(root_device);
-
 	return ret;
 }
 
 static void vfio_ap_matrix_dev_destroy(void)
 {
+	struct device *root_device = matrix_dev->device.parent;
+
+	driver_unregister(&matrix_driver.drv);
 	device_unregister(&matrix_dev->device);
-	root_device_unregister(matrix_dev->device.parent);
+	bus_unregister(&matrix_bus);
+	root_device_unregister(root_device);
 }
 
 static int __init vfio_ap_init(void)
drivers/s390/crypto/vfio_ap_ops.c +2 -2
index 272ef42..900b9cf 100644
@@ -198,8 +198,8 @@ static int vfio_ap_verify_queue_reserved(unsigned long *apid,
 	qres.apqi = apqi;
 	qres.reserved = false;
 
-	ret = driver_for_each_device(matrix_dev->device.driver, NULL, &qres,
-				     vfio_ap_has_queue);
+	ret = driver_for_each_device(&matrix_dev->vfio_ap_drv->driver, NULL,
+				     &qres, vfio_ap_has_queue);
 	if (ret)
 		return ret;
 
drivers/s390/crypto/vfio_ap_private.h +1 -0
index 5675492..76b7f98 100644
@@ -40,6 +40,7 @@ struct ap_matrix_dev {
 	struct ap_config_info info;
 	struct list_head mdev_list;
 	struct mutex lock;
+	struct ap_driver  *vfio_ap_drv;
 };
 
 extern struct ap_matrix_dev *matrix_dev;
Signature · 1 line
2.7.4
#2 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 4 lines · On Thu, 14 Feb 2019 14:51:01 +0100 Pierre Morel <[email protected]> wrote:

Libudev relies on having a subsystem link for non-root devices. To avoid libudev (and potentially other userspace tools) choking on the matrix device let us introduce a vfio_ap bus and with that the vfio_ap bus subsytem, and make the matrix device reside within it.

How does libudev choke on this? It feels wrong to introduce a bus that basically does nothing...

Quoted 23 lines

We restrict the number of allowed devices to a single one.

Doing this we need to suppress the forced link from the matrix device to the vfio_ap driver and we suppress the device_type we do not need anymore.

Since the associated matrix driver is not the vfio_ap driver any more, we have to change the search for the devices on the vfio_ap driver in the function vfio_ap_verify_queue_reserved.

---
 drivers/s390/crypto/vfio_ap_drv.c     | 63 +++++++++++++++++++++++++++++++----
 drivers/s390/crypto/vfio_ap_ops.c     |  4 +--
 drivers/s390/crypto/vfio_ap_private.h |  1 +
 3 files changed, 60 insertions(+), 8 deletions(-)
drivers/s390/crypto/vfio_ap_drv.c +0 -0
index 31c6c84..1fd5fe6 100644

drivers/s390/crypto/vfio_ap_drv.c MODULE_LICENSE("GPL v2"); · line 29

Quoted 8 lines
drivers/s390/crypto/vfio_ap_drv.c +3 -2
@@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");
 
 static struct ap_driver vfio_ap_drv;
 
-static struct device_type vfio_ap_dev_type = {
-	.name = VFIO_AP_DEV_TYPE_NAME,
+struct matrix_driver {
+	struct device_driver drv;
+	int device_count;

This counter basically ensures that at most one device may bind with this driver... you'd still have that device on the bus, though.

Quoted 57 lines
drivers/s390/crypto/vfio_ap_drv.c +39 -0
 };
 
 struct ap_matrix_dev *matrix_dev;
@@ -62,6 +63,41 @@ static void vfio_ap_matrix_dev_release(struct device *dev)
 	kfree(matrix_dev);
 }
 
+static int matrix_bus_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static struct bus_type matrix_bus = {
+	.name = "vfio_ap",
+	.match = &matrix_bus_match,
+};
+
+static int matrix_probe(struct device *dev);
+static int matrix_remove(struct device *dev);
+static struct matrix_driver matrix_driver = {
+	.drv = {
+		.name = "vfio_ap",
+		.bus = &matrix_bus,
+		.probe = matrix_probe,
+		.remove = matrix_remove,
+	},
+};
+
+static int matrix_probe(struct device *dev)
+{
+	if (matrix_driver.device_count)
+		return -EEXIST;
+	matrix_driver.device_count++;
+	return 0;
+}
+
+static int matrix_remove(struct device *dev)
+{
+	matrix_driver.device_count--;
+	return 0;
+}
+
 static int vfio_ap_matrix_dev_create(void)
 {
 	int ret;
@@ -71,6 +107,10 @@ static int vfio_ap_matrix_dev_create(void)
 	if (IS_ERR(root_device))
 		return PTR_ERR(root_device);
 
+	ret = bus_register(&matrix_bus);
+	if (ret)
+		goto bus_register_err;
+
 	matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
 	if (!matrix_dev) {
 		ret = -ENOMEM;

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 134

Quoted 10 lines
drivers/s390/crypto/vfio_ap_drv.c +2 -2
@@ -87,30 +127,41 @@ static int vfio_ap_matrix_dev_create(void)
 	mutex_init(&matrix_dev->lock);
 	INIT_LIST_HEAD(&matrix_dev->mdev_list);
 
-	matrix_dev->device.type = &vfio_ap_dev_type;
 	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
 	matrix_dev->device.parent = root_device;
+	matrix_dev->device.bus = &matrix_bus;
 	matrix_dev->device.release = vfio_ap_matrix_dev_release;
-	matrix_dev->device.driver = &vfio_ap_drv.driver;
+	matrix_dev->vfio_ap_drv = &vfio_ap_drv;

Can't you get that structure through matrix_dev->device.driver instead when you need it in the function below?

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 143

Quoted 9 lines
drivers/s390/crypto/vfio_ap_drv.c +4 -0
 	ret = device_register(&matrix_dev->device);
 	if (ret)
 		goto matrix_reg_err;
 
+	ret = driver_register(&matrix_driver.drv);
+	if (ret)
+		goto matrix_drv_err;
+

As you already have several structures that can be registered exactly once (the root device, the bus, the driver, ...), you can already be sure that there's only one device on the bus, can't you?

Quoted 46 lines
drivers/s390/crypto/vfio_ap_drv.c +9 -2
 	return 0;
 
+matrix_drv_err:
+	device_unregister(&matrix_dev->device);
 matrix_reg_err:
 	put_device(&matrix_dev->device);
 matrix_alloc_err:
+	bus_unregister(&matrix_bus);
+bus_register_err:
 	root_device_unregister(root_device);
-
 	return ret;
 }
 
 static void vfio_ap_matrix_dev_destroy(void)
 {
+	struct device *root_device = matrix_dev->device.parent;
+
+	driver_unregister(&matrix_driver.drv);
 	device_unregister(&matrix_dev->device);
-	root_device_unregister(matrix_dev->device.parent);
+	bus_unregister(&matrix_bus);
+	root_device_unregister(root_device);
 }
 
 static int __init vfio_ap_init(void)
drivers/s390/crypto/vfio_ap_ops.c +2 -2
index 272ef42..900b9cf 100644
@@ -198,8 +198,8 @@ static int vfio_ap_verify_queue_reserved(unsigned long *apid,
 	qres.apqi = apqi;
 	qres.reserved = false;
 
-	ret = driver_for_each_device(matrix_dev->device.driver, NULL, &qres,
-				     vfio_ap_has_queue);
+	ret = driver_for_each_device(&matrix_dev->vfio_ap_drv->driver, NULL,
+				     &qres, vfio_ap_has_queue);
 	if (ret)
 		return ret;
 
drivers/s390/crypto/vfio_ap_private.h +0 -0
index 5675492..76b7f98 100644

drivers/s390/crypto/vfio_ap_private.h struct ap_matrix_dev { · line 46

Quoted 7 lines
drivers/s390/crypto/vfio_ap_private.h +1 -0
@@ -40,6 +40,7 @@ struct ap_matrix_dev {
 	struct ap_config_info info;
 	struct list_head mdev_list;
 	struct mutex lock;
+	struct ap_driver  *vfio_ap_drv;
 };
 
 extern struct ap_matrix_dev *matrix_dev;

This feels like a lot of boilerplate code, just to create a bus that basically doesn't do anything. I'm surprised that libudev can't deal with bus-less devices properly...

#3 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 2 lines · Cornelia Huck

On Thu, 14 Feb 2019 14:51:01 +0100
Pierre Morel <[email protected]> wrote:

Pierre,
this is independent from this series and should have been sent separately. In the end (when we have the final solution) this will require cc stable.

Quoted 8 lines
Quoted 5 lines

Libudev relies on having a subsystem link for non-root devices. To avoid libudev (and potentially other userspace tools) choking on the matrix device let us introduce a vfio_ap bus and with that the vfio_ap bus subsytem, and make the matrix device reside within it.

How does libudev choke on this? It feels wrong to introduce a bus that basically does nothing...

I have seen libvirt looping when a matrix device was available before the libvirt start.
Marc Hartmayer debugged this and circumvented this in libvirt:
https://www.redhat.com/archives/libvir-list/2019-February/msg00837.html

Still libudev expects a subsystem link in the matrix folder when doing the udev_enumerate_scan_devices call.

Having a bus is one way of adding a subsystem link.

Quoted 179 lines
Quoted 24 lines

We restrict the number of allowed devices to a single one.

Doing this we need to suppress the forced link from the matrix device to the vfio_ap driver and we suppress the device_type we do not need anymore.

Since the associated matrix driver is not the vfio_ap driver any more, we have to change the search for the devices on the vfio_ap driver in the function vfio_ap_verify_queue_reserved.

---
 drivers/s390/crypto/vfio_ap_drv.c     | 63 +++++++++++++++++++++++++++++++----
 drivers/s390/crypto/vfio_ap_ops.c     |  4 +--
 drivers/s390/crypto/vfio_ap_private.h |  1 +
 3 files changed, 60 insertions(+), 8 deletions(-)
drivers/s390/crypto/vfio_ap_drv.c +0 -0
index 31c6c84..1fd5fe6 100644

drivers/s390/crypto/vfio_ap_drv.c MODULE_LICENSE("GPL v2"); · line 29

Quoted 8 lines
drivers/s390/crypto/vfio_ap_drv.c +3 -2
@@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");
 
 static struct ap_driver vfio_ap_drv;
 
-static struct device_type vfio_ap_dev_type = {
-	.name = VFIO_AP_DEV_TYPE_NAME,
+struct matrix_driver {
+	struct device_driver drv;
+	int device_count;

This counter basically ensures that at most one device may bind with this driver... you'd still have that device on the bus, though.

Quoted 57 lines
drivers/s390/crypto/vfio_ap_drv.c +39 -0
 };
 
 struct ap_matrix_dev *matrix_dev;
@@ -62,6 +63,41 @@ static void vfio_ap_matrix_dev_release(struct device *dev)
 	kfree(matrix_dev);
 }
 
+static int matrix_bus_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static struct bus_type matrix_bus = {
+	.name = "vfio_ap",
+	.match = &matrix_bus_match,
+};
+
+static int matrix_probe(struct device *dev);
+static int matrix_remove(struct device *dev);
+static struct matrix_driver matrix_driver = {
+	.drv = {
+		.name = "vfio_ap",
+		.bus = &matrix_bus,
+		.probe = matrix_probe,
+		.remove = matrix_remove,
+	},
+};
+
+static int matrix_probe(struct device *dev)
+{
+	if (matrix_driver.device_count)
+		return -EEXIST;
+	matrix_driver.device_count++;
+	return 0;
+}
+
+static int matrix_remove(struct device *dev)
+{
+	matrix_driver.device_count--;
+	return 0;
+}
+
 static int vfio_ap_matrix_dev_create(void)
 {
 	int ret;
@@ -71,6 +107,10 @@ static int vfio_ap_matrix_dev_create(void)
 	if (IS_ERR(root_device))
 		return PTR_ERR(root_device);
 
+	ret = bus_register(&matrix_bus);
+	if (ret)
+		goto bus_register_err;
+
 	matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
 	if (!matrix_dev) {
 		ret = -ENOMEM;

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 134

Quoted 10 lines
drivers/s390/crypto/vfio_ap_drv.c +2 -2
@@ -87,30 +127,41 @@ static int vfio_ap_matrix_dev_create(void)
 	mutex_init(&matrix_dev->lock);
 	INIT_LIST_HEAD(&matrix_dev->mdev_list);
 
-	matrix_dev->device.type = &vfio_ap_dev_type;
 	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
 	matrix_dev->device.parent = root_device;
+	matrix_dev->device.bus = &matrix_bus;
 	matrix_dev->device.release = vfio_ap_matrix_dev_release;
-	matrix_dev->device.driver = &vfio_ap_drv.driver;
+	matrix_dev->vfio_ap_drv = &vfio_ap_drv;

Can't you get that structure through matrix_dev->device.driver instead when you need it in the function below?

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 143

Quoted 9 lines
drivers/s390/crypto/vfio_ap_drv.c +4 -0
 	ret = device_register(&matrix_dev->device);
 	if (ret)
 		goto matrix_reg_err;
 
+	ret = driver_register(&matrix_driver.drv);
+	if (ret)
+		goto matrix_drv_err;
+

As you already have several structures that can be registered exactly once (the root device, the bus, the driver, ...), you can already be sure that there's only one device on the bus, can't you?

Quoted 46 lines
drivers/s390/crypto/vfio_ap_drv.c +9 -2
 	return 0;
 
+matrix_drv_err:
+	device_unregister(&matrix_dev->device);
 matrix_reg_err:
 	put_device(&matrix_dev->device);
 matrix_alloc_err:
+	bus_unregister(&matrix_bus);
+bus_register_err:
 	root_device_unregister(root_device);
-
 	return ret;
 }
 
 static void vfio_ap_matrix_dev_destroy(void)
 {
+	struct device *root_device = matrix_dev->device.parent;
+
+	driver_unregister(&matrix_driver.drv);
 	device_unregister(&matrix_dev->device);
-	root_device_unregister(matrix_dev->device.parent);
+	bus_unregister(&matrix_bus);
+	root_device_unregister(root_device);
 }
 
 static int __init vfio_ap_init(void)
drivers/s390/crypto/vfio_ap_ops.c +2 -2
index 272ef42..900b9cf 100644
@@ -198,8 +198,8 @@ static int vfio_ap_verify_queue_reserved(unsigned long *apid,
 	qres.apqi = apqi;
 	qres.reserved = false;
 
-	ret = driver_for_each_device(matrix_dev->device.driver, NULL, &qres,
-				     vfio_ap_has_queue);
+	ret = driver_for_each_device(&matrix_dev->vfio_ap_drv->driver, NULL,
+				     &qres, vfio_ap_has_queue);
 	if (ret)
 		return ret;
 
drivers/s390/crypto/vfio_ap_private.h +0 -0
index 5675492..76b7f98 100644

drivers/s390/crypto/vfio_ap_private.h struct ap_matrix_dev { · line 46

Quoted 7 lines
drivers/s390/crypto/vfio_ap_private.h +1 -0
@@ -40,6 +40,7 @@ struct ap_matrix_dev {
 	struct ap_config_info info;
 	struct list_head mdev_list;
 	struct mutex lock;
+	struct ap_driver  *vfio_ap_drv;
 };
 
 extern struct ap_matrix_dev *matrix_dev;

This feels like a lot of boilerplate code, just to create a bus that basically doesn't do anything. I'm surprised that libudev can't deal with bus-less devices properly...

#4 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 21 lines · On Thu, 14 Feb 2019 16:05:35 +0100 Christian Borntraeger…
Quoted 2 lines · Cornelia Huck

On Thu, 14 Feb 2019 14:51:01 +0100
Pierre Morel <[email protected]> wrote:

Pierre,
this is independent from this series and should have been sent separately. In the end (when we have the final solution) this will require cc stable.

Quoted 8 lines
Quoted 5 lines

Libudev relies on having a subsystem link for non-root devices. To avoid libudev (and potentially other userspace tools) choking on the matrix device let us introduce a vfio_ap bus and with that the vfio_ap bus subsytem, and make the matrix device reside within it.

How does libudev choke on this? It feels wrong to introduce a bus that basically does nothing...

I have seen libvirt looping when a matrix device was available before the libvirt start.
Marc Hartmayer debugged this and circumvented this in libvirt:
https://www.redhat.com/archives/libvir-list/2019-February/msg00837.html

Quoted 4 lines

Still libudev expects a subsystem link in the matrix folder when doing the udev_enumerate_scan_devices call.

Having a bus is one way of adding a subsystem link.

Ugh, that feels really broken. Adding a bus is probably the easiest way to get this working, though :/

maintainer
#5 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

In reply to Christian Borntraeger
Quoted 7 lines · Christian Borntraeger
Quoted 2 lines · Cornelia Huck

On Thu, 14 Feb 2019 14:51:01 +0100
Pierre Morel <[email protected]> wrote:

Pierre,
this is independent from this series and should have been sent separately. In the end (when we have the final solution) this will require cc stable.

I agree wholeheartedly with this statement. It has nothing to do with interrupt processing.

Quoted 199 lines
Quoted 8 lines
Quoted 5 lines

Libudev relies on having a subsystem link for non-root devices. To avoid libudev (and potentially other userspace tools) choking on the matrix device let us introduce a vfio_ap bus and with that the vfio_ap bus subsytem, and make the matrix device reside within it.

How does libudev choke on this? It feels wrong to introduce a bus that basically does nothing...

I have seen libvirt looping when a matrix device was available before the libvirt start.
Marc Hartmayer debugged this and circumvented this in libvirt:
https://www.redhat.com/archives/libvir-list/2019-February/msg00837.html

Still libudev expects a subsystem link in the matrix folder when doing the udev_enumerate_scan_devices call.

Having a bus is one way of adding a subsystem link.

Quoted 179 lines
Quoted 24 lines

We restrict the number of allowed devices to a single one.

Doing this we need to suppress the forced link from the matrix device to the vfio_ap driver and we suppress the device_type we do not need anymore.

Since the associated matrix driver is not the vfio_ap driver any more, we have to change the search for the devices on the vfio_ap driver in the function vfio_ap_verify_queue_reserved.

---
  drivers/s390/crypto/vfio_ap_drv.c     | 63 +++++++++++++++++++++++++++++++----
  drivers/s390/crypto/vfio_ap_ops.c     |  4 +--
  drivers/s390/crypto/vfio_ap_private.h |  1 +
  3 files changed, 60 insertions(+), 8 deletions(-)
drivers/s390/crypto/vfio_ap_drv.c +0 -0
index 31c6c84..1fd5fe6 100644

drivers/s390/crypto/vfio_ap_drv.c MODULE_LICENSE("GPL v2"); · line 29

Quoted 8 lines
drivers/s390/crypto/vfio_ap_drv.c +3 -2
@@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");
 
  static struct ap_driver vfio_ap_drv;
 
-static struct device_type vfio_ap_dev_type = {
-	.name = VFIO_AP_DEV_TYPE_NAME,
+struct matrix_driver {
+	struct device_driver drv;
+	int device_count;

This counter basically ensures that at most one device may bind with this driver... you'd still have that device on the bus, though.

Quoted 57 lines
drivers/s390/crypto/vfio_ap_drv.c +39 -0
  };
 
  struct ap_matrix_dev *matrix_dev;
@@ -62,6 +63,41 @@ static void vfio_ap_matrix_dev_release(struct device *dev)
  	kfree(matrix_dev);
  }
 
+static int matrix_bus_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static struct bus_type matrix_bus = {
+	.name = "vfio_ap",
+	.match = &matrix_bus_match,
+};
+
+static int matrix_probe(struct device *dev);
+static int matrix_remove(struct device *dev);
+static struct matrix_driver matrix_driver = {
+	.drv = {
+		.name = "vfio_ap",
+		.bus = &matrix_bus,
+		.probe = matrix_probe,
+		.remove = matrix_remove,
+	},
+};
+
+static int matrix_probe(struct device *dev)
+{
+	if (matrix_driver.device_count)
+		return -EEXIST;
+	matrix_driver.device_count++;
+	return 0;
+}
+
+static int matrix_remove(struct device *dev)
+{
+	matrix_driver.device_count--;
+	return 0;
+}
+
  static int vfio_ap_matrix_dev_create(void)
  {
  	int ret;
@@ -71,6 +107,10 @@ static int vfio_ap_matrix_dev_create(void)
  	if (IS_ERR(root_device))
  		return PTR_ERR(root_device);
 
+	ret = bus_register(&matrix_bus);
+	if (ret)
+		goto bus_register_err;
+
  	matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
  	if (!matrix_dev) {
  		ret = -ENOMEM;

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 134

Quoted 10 lines
drivers/s390/crypto/vfio_ap_drv.c +2 -2
@@ -87,30 +127,41 @@ static int vfio_ap_matrix_dev_create(void)
  	mutex_init(&matrix_dev->lock);
  	INIT_LIST_HEAD(&matrix_dev->mdev_list);
 
-	matrix_dev->device.type = &vfio_ap_dev_type;
  	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
  	matrix_dev->device.parent = root_device;
+	matrix_dev->device.bus = &matrix_bus;
  	matrix_dev->device.release = vfio_ap_matrix_dev_release;
-	matrix_dev->device.driver = &vfio_ap_drv.driver;
+	matrix_dev->vfio_ap_drv = &vfio_ap_drv;

Can't you get that structure through matrix_dev->device.driver instead when you need it in the function below?

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 143

Quoted 9 lines
drivers/s390/crypto/vfio_ap_drv.c +4 -0
  	ret = device_register(&matrix_dev->device);
  	if (ret)
  		goto matrix_reg_err;
 
+	ret = driver_register(&matrix_driver.drv);
+	if (ret)
+		goto matrix_drv_err;
+

As you already have several structures that can be registered exactly once (the root device, the bus, the driver, ...), you can already be sure that there's only one device on the bus, can't you?

Quoted 46 lines
drivers/s390/crypto/vfio_ap_drv.c +9 -2
  	return 0;
 
+matrix_drv_err:
+	device_unregister(&matrix_dev->device);
  matrix_reg_err:
  	put_device(&matrix_dev->device);
  matrix_alloc_err:
+	bus_unregister(&matrix_bus);
+bus_register_err:
  	root_device_unregister(root_device);
-
  	return ret;
  }
 
  static void vfio_ap_matrix_dev_destroy(void)
  {
+	struct device *root_device = matrix_dev->device.parent;
+
+	driver_unregister(&matrix_driver.drv);
  	device_unregister(&matrix_dev->device);
-	root_device_unregister(matrix_dev->device.parent);
+	bus_unregister(&matrix_bus);
+	root_device_unregister(root_device);
  }
 
  static int __init vfio_ap_init(void)
drivers/s390/crypto/vfio_ap_ops.c +2 -2
index 272ef42..900b9cf 100644
@@ -198,8 +198,8 @@ static int vfio_ap_verify_queue_reserved(unsigned long *apid,
  	qres.apqi = apqi;
  	qres.reserved = false;
 
-	ret = driver_for_each_device(matrix_dev->device.driver, NULL, &qres,
-				     vfio_ap_has_queue);
+	ret = driver_for_each_device(&matrix_dev->vfio_ap_drv->driver, NULL,
+				     &qres, vfio_ap_has_queue);
  	if (ret)
  		return ret;
 
drivers/s390/crypto/vfio_ap_private.h +0 -0
index 5675492..76b7f98 100644

drivers/s390/crypto/vfio_ap_private.h struct ap_matrix_dev { · line 46

Quoted 7 lines
drivers/s390/crypto/vfio_ap_private.h +1 -0
@@ -40,6 +40,7 @@ struct ap_matrix_dev {
  	struct ap_config_info info;
  	struct list_head mdev_list;
  	struct mutex lock;
+	struct ap_driver  *vfio_ap_drv;
  };
 
  extern struct ap_matrix_dev *matrix_dev;

This feels like a lot of boilerplate code, just to create a bus that basically doesn't do anything. I'm surprised that libudev can't deal with bus-less devices properly...

#6 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

In reply to Christian Borntraeger
Quoted 7 lines · Christian Borntraeger
Quoted 2 lines · Cornelia Huck

On Thu, 14 Feb 2019 14:51:01 +0100
Pierre Morel <[email protected]> wrote:

Pierre,
this is independent from this series and should have been sent separately. In the end (when we have the final solution) this will require cc stable.

Yes, I will wait until tomorrow for more feed back and I will send a separate v2 for this patch.

Regards,
Pierre

Quoted 199 lines
Quoted 8 lines
Quoted 5 lines

Libudev relies on having a subsystem link for non-root devices. To avoid libudev (and potentially other userspace tools) choking on the matrix device let us introduce a vfio_ap bus and with that the vfio_ap bus subsytem, and make the matrix device reside within it.

How does libudev choke on this? It feels wrong to introduce a bus that basically does nothing...

I have seen libvirt looping when a matrix device was available before the libvirt start.
Marc Hartmayer debugged this and circumvented this in libvirt:
https://www.redhat.com/archives/libvir-list/2019-February/msg00837.html

Still libudev expects a subsystem link in the matrix folder when doing the udev_enumerate_scan_devices call.

Having a bus is one way of adding a subsystem link.

Quoted 179 lines
Quoted 24 lines

We restrict the number of allowed devices to a single one.

Doing this we need to suppress the forced link from the matrix device to the vfio_ap driver and we suppress the device_type we do not need anymore.

Since the associated matrix driver is not the vfio_ap driver any more, we have to change the search for the devices on the vfio_ap driver in the function vfio_ap_verify_queue_reserved.

---
  drivers/s390/crypto/vfio_ap_drv.c     | 63 +++++++++++++++++++++++++++++++----
  drivers/s390/crypto/vfio_ap_ops.c     |  4 +--
  drivers/s390/crypto/vfio_ap_private.h |  1 +
  3 files changed, 60 insertions(+), 8 deletions(-)
drivers/s390/crypto/vfio_ap_drv.c +0 -0
index 31c6c84..1fd5fe6 100644

drivers/s390/crypto/vfio_ap_drv.c MODULE_LICENSE("GPL v2"); · line 29

Quoted 8 lines
drivers/s390/crypto/vfio_ap_drv.c +3 -2
@@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");
 
  static struct ap_driver vfio_ap_drv;
 
-static struct device_type vfio_ap_dev_type = {
-	.name = VFIO_AP_DEV_TYPE_NAME,
+struct matrix_driver {
+	struct device_driver drv;
+	int device_count;

This counter basically ensures that at most one device may bind with this driver... you'd still have that device on the bus, though.

Quoted 57 lines
drivers/s390/crypto/vfio_ap_drv.c +39 -0
  };
 
  struct ap_matrix_dev *matrix_dev;
@@ -62,6 +63,41 @@ static void vfio_ap_matrix_dev_release(struct device *dev)
  	kfree(matrix_dev);
  }
 
+static int matrix_bus_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static struct bus_type matrix_bus = {
+	.name = "vfio_ap",
+	.match = &matrix_bus_match,
+};
+
+static int matrix_probe(struct device *dev);
+static int matrix_remove(struct device *dev);
+static struct matrix_driver matrix_driver = {
+	.drv = {
+		.name = "vfio_ap",
+		.bus = &matrix_bus,
+		.probe = matrix_probe,
+		.remove = matrix_remove,
+	},
+};
+
+static int matrix_probe(struct device *dev)
+{
+	if (matrix_driver.device_count)
+		return -EEXIST;
+	matrix_driver.device_count++;
+	return 0;
+}
+
+static int matrix_remove(struct device *dev)
+{
+	matrix_driver.device_count--;
+	return 0;
+}
+
  static int vfio_ap_matrix_dev_create(void)
  {
  	int ret;
@@ -71,6 +107,10 @@ static int vfio_ap_matrix_dev_create(void)
  	if (IS_ERR(root_device))
  		return PTR_ERR(root_device);
 
+	ret = bus_register(&matrix_bus);
+	if (ret)
+		goto bus_register_err;
+
  	matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
  	if (!matrix_dev) {
  		ret = -ENOMEM;

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 134

Quoted 10 lines
drivers/s390/crypto/vfio_ap_drv.c +2 -2
@@ -87,30 +127,41 @@ static int vfio_ap_matrix_dev_create(void)
  	mutex_init(&matrix_dev->lock);
  	INIT_LIST_HEAD(&matrix_dev->mdev_list);
 
-	matrix_dev->device.type = &vfio_ap_dev_type;
  	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
  	matrix_dev->device.parent = root_device;
+	matrix_dev->device.bus = &matrix_bus;
  	matrix_dev->device.release = vfio_ap_matrix_dev_release;
-	matrix_dev->device.driver = &vfio_ap_drv.driver;
+	matrix_dev->vfio_ap_drv = &vfio_ap_drv;

Can't you get that structure through matrix_dev->device.driver instead when you need it in the function below?

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 143

Quoted 9 lines
drivers/s390/crypto/vfio_ap_drv.c +4 -0
  	ret = device_register(&matrix_dev->device);
  	if (ret)
  		goto matrix_reg_err;
 
+	ret = driver_register(&matrix_driver.drv);
+	if (ret)
+		goto matrix_drv_err;
+

As you already have several structures that can be registered exactly once (the root device, the bus, the driver, ...), you can already be sure that there's only one device on the bus, can't you?

Quoted 46 lines
drivers/s390/crypto/vfio_ap_drv.c +9 -2
  	return 0;
 
+matrix_drv_err:
+	device_unregister(&matrix_dev->device);
  matrix_reg_err:
  	put_device(&matrix_dev->device);
  matrix_alloc_err:
+	bus_unregister(&matrix_bus);
+bus_register_err:
  	root_device_unregister(root_device);
-
  	return ret;
  }
 
  static void vfio_ap_matrix_dev_destroy(void)
  {
+	struct device *root_device = matrix_dev->device.parent;
+
+	driver_unregister(&matrix_driver.drv);
  	device_unregister(&matrix_dev->device);
-	root_device_unregister(matrix_dev->device.parent);
+	bus_unregister(&matrix_bus);
+	root_device_unregister(root_device);
  }
 
  static int __init vfio_ap_init(void)
drivers/s390/crypto/vfio_ap_ops.c +2 -2
index 272ef42..900b9cf 100644
@@ -198,8 +198,8 @@ static int vfio_ap_verify_queue_reserved(unsigned long *apid,
  	qres.apqi = apqi;
  	qres.reserved = false;
 
-	ret = driver_for_each_device(matrix_dev->device.driver, NULL, &qres,
-				     vfio_ap_has_queue);
+	ret = driver_for_each_device(&matrix_dev->vfio_ap_drv->driver, NULL,
+				     &qres, vfio_ap_has_queue);
  	if (ret)
  		return ret;
 
drivers/s390/crypto/vfio_ap_private.h +0 -0
index 5675492..76b7f98 100644

drivers/s390/crypto/vfio_ap_private.h struct ap_matrix_dev { · line 46

Quoted 7 lines
drivers/s390/crypto/vfio_ap_private.h +1 -0
@@ -40,6 +40,7 @@ struct ap_matrix_dev {
  	struct ap_config_info info;
  	struct list_head mdev_list;
  	struct mutex lock;
+	struct ap_driver  *vfio_ap_drv;
  };
 
  extern struct ap_matrix_dev *matrix_dev;

This feels like a lot of boilerplate code, just to create a bus that basically doesn't do anything. I'm surprised that libudev can't deal with bus-less devices properly...

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#7 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

In reply to Cornelia Huck
Quoted 10 lines · Cornelia Huck
Quoted 4 lines · On Thu, 14 Feb 2019 14:51:01 +0100 Pierre Morel <[email protected]> wrote:

Libudev relies on having a subsystem link for non-root devices. To avoid libudev (and potentially other userspace tools) choking on the matrix device let us introduce a vfio_ap bus and with that the vfio_ap bus subsytem, and make the matrix device reside within it.

How does libudev choke on this? It feels wrong to introduce a bus that basically does nothing...

Christian answered this in another thread, so I don't answer.

Quoted 4 lines
Quoted 4 lines

We restrict the number of allowed devices to a single one.

...snip...

Quoted 5 lines
Quoted 5 lines

+++ b/drivers/s390/crypto/vfio_ap_drv.c

drivers/s390/crypto/vfio_ap_drv.c +0 -0
@@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");
 
  static struct ap_driver vfio_ap_drv;
 
Quoted 8 lines

drivers/s390/crypto/vfio_ap_drv.c MODULE_LICENSE("GPL v2"); · line 29

Quoted 5 lines
drivers/s390/crypto/vfio_ap_drv.c +3 -2
-static struct device_type vfio_ap_dev_type = {
-	.name = VFIO_AP_DEV_TYPE_NAME,
+struct matrix_driver {
+	struct device_driver drv;
+	int device_count;

This counter basically ensures that at most one device may bind with this driver... you'd still have that device on the bus, though.

yes, this is what is wanted: this driver can only support one device. May be another matrix driver can support one or more other devices.

I should update comment message my be.

Quoted 6 lines
Quoted 6 lines
drivers/s390/crypto/vfio_ap_drv.c +0 -0
  };
 
  struct ap_matrix_dev *matrix_dev;
Quoted 10 lines

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 134

Quoted 7 lines
drivers/s390/crypto/vfio_ap_drv.c +2 -2
-	matrix_dev->device.type = &vfio_ap_dev_type;
  	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
  	matrix_dev->device.parent = root_device;
+	matrix_dev->device.bus = &matrix_bus;
  	matrix_dev->device.release = vfio_ap_matrix_dev_release;
-	matrix_dev->device.driver = &vfio_ap_drv.driver;
+	matrix_dev->vfio_ap_drv = &vfio_ap_drv;

Can't you get that structure through matrix_dev->device.driver instead when you need it in the function below?

Not anymore.
We have two different drivers and devices
matrix_drv <-> matrix_dev
and
vfio_ap_drv <-> ap_devices

The driver behind the matrix_dev->dev->driver is matrix_drv what is needed here is vfio_ap_drv.

Quoted 6 lines
Quoted 6 lines
  
  	ret = device_register(&matrix_dev->device);
  	if (ret)
  		goto matrix_reg_err;
Quoted 8 lines

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 143

Quoted 4 lines
drivers/s390/crypto/vfio_ap_drv.c +4 -0
+	ret = driver_register(&matrix_driver.drv);
+	if (ret)
+		goto matrix_drv_err;
+

As you already have several structures that can be registered exactly once (the root device, the bus, the driver, ...), you can already be sure that there's only one device on the bus, can't you?

hum, no I don't think so, no device can register before this module is loaded, but what does prevent a device to register later from another module?

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#8 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 40 lines · On Thu, 14 Feb 2019 16:47:30 +0100 Pierre Morel <[email protected]> wrote:
Quoted 8 lines · Cornelia Huck
Quoted 5 lines · On Thu, 14 Feb 2019 14:51:01 +0100 Pierre Morel <[email protected]> wrote:

+++ b/drivers/s390/crypto/vfio_ap_drv.c

drivers/s390/crypto/vfio_ap_drv.c +0 -0
@@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");
 
  static struct ap_driver vfio_ap_drv;
 
Quoted 8 lines

drivers/s390/crypto/vfio_ap_drv.c MODULE_LICENSE("GPL v2"); · line 29

Quoted 5 lines
drivers/s390/crypto/vfio_ap_drv.c +3 -2
-static struct device_type vfio_ap_dev_type = {
-	.name = VFIO_AP_DEV_TYPE_NAME,
+struct matrix_driver {
+	struct device_driver drv;
+	int device_count;  

This counter basically ensures that at most one device may bind with this driver... you'd still have that device on the bus, though.

yes, this is what is wanted: this driver can only support one device. May be another matrix driver can support one or more other devices.

I should update comment message my be.

Quoted 6 lines
Quoted 6 lines
drivers/s390/crypto/vfio_ap_drv.c +0 -0
  };
 
  struct ap_matrix_dev *matrix_dev;  
Quoted 10 lines

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 134

Quoted 7 lines
drivers/s390/crypto/vfio_ap_drv.c +2 -2
-	matrix_dev->device.type = &vfio_ap_dev_type;
  	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
  	matrix_dev->device.parent = root_device;
+	matrix_dev->device.bus = &matrix_bus;
  	matrix_dev->device.release = vfio_ap_matrix_dev_release;
-	matrix_dev->device.driver = &vfio_ap_drv.driver;
+	matrix_dev->vfio_ap_drv = &vfio_ap_drv;  

Can't you get that structure through matrix_dev->device.driver instead when you need it in the function below?

Quoted 8 lines

Not anymore.
We have two different drivers and devices
matrix_drv <-> matrix_dev
and
vfio_ap_drv <-> ap_devices

The driver behind the matrix_dev->dev->driver is matrix_drv what is needed here is vfio_ap_drv.

Wait, we had tacked a driver for ap devices unto a matrix device, which is not on the ap bus? Maybe that's what trips libudev?

(And reading further in the current code, it seems we clear that structure _after_ the matrix device had been setup, so how can that even work? Where am I confused?)

Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
  
  
  	ret = device_register(&matrix_dev->device);
  	if (ret)
  		goto matrix_reg_err;
Quoted 8 lines

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_matrix_dev_create(void) · line 143

Quoted 4 lines
drivers/s390/crypto/vfio_ap_drv.c +4 -0
+	ret = driver_register(&matrix_driver.drv);
+	if (ret)
+		goto matrix_drv_err;
+  

As you already have several structures that can be registered exactly once (the root device, the bus, the driver, ...), you can already be sure that there's only one device on the bus, can't you?

Quoted 3 lines

hum, no I don't think so, no device can register before this module is loaded, but what does prevent a device to register later from another module?

Not unless you export the interface, I guess.

#9 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 41 lines · Cornelia Huck
Quoted 38 lines · On Thu, 14 Feb 2019 16:47:30 +0100 Pierre Morel <[email protected]> wrote:
Quoted 8 lines · Cornelia Huck
Quoted 5 lines · On Thu, 14 Feb 2019 14:51:01 +0100 Pierre Morel <[email protected]> wrote:

+++ b/drivers/s390/crypto/vfio_ap_drv.c @@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");

static struct ap_driver vfio_ap_drv;

Quoted 7 lines
Quoted 3 lines

-static struct device_type vfio_ap_dev_type = { - .name =
VFIO_AP_DEV_TYPE_NAME, +struct matrix_driver { + struct
device_driver drv; + int device_count;

This counter basically ensures that at most one device may bind with this driver... you'd still have that device on the bus, though.

yes, this is what is wanted: this driver can only support one device. May be another matrix driver can support one or more other devices.

I should update comment message my be.

Quoted 14 lines
Quoted 11 lines

};

struct ap_matrix_dev *matrix_dev;

drivers/s390/crypto/vfio_ap_drv.c +0 -1
-	matrix_dev->device.type = &vfio_ap_dev_type; 

dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME); matrix_dev->device.parent = root_device; + matrix_dev->device.bus = &matrix_bus; matrix_dev->device.release = vfio_ap_matrix_dev_release; - matrix_dev->device.driver = &vfio_ap_drv.driver; +
matrix_dev->vfio_ap_drv = &vfio_ap_drv;

Can't you get that structure through matrix_dev->device.driver instead when you need it in the function below?

Quoted 8 lines
Quoted 5 lines

Not anymore. We have two different drivers and devices matrix_drv <-> matrix_dev and vfio_ap_drv <-> ap_devices

The driver behind the matrix_dev->dev->driver is matrix_drv what is needed here is vfio_ap_drv.

Wait, we had tacked a driver for ap devices unto a matrix device, which is not on the ap bus?

...yes -(

Quoted 2 lines

Maybe that's what trips libudev? >
(And reading further in the current code, it seems we clear that structure _after_ the matrix device had been setup, so how can that even work? Where am I confused?)

On device_register there were no bus, so the core just do not look for a driver and this field was nor tested nor overwritten.

Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 9 lines

ret = device_register(&matrix_dev->device); if (ret) goto matrix_reg_err;

(quoted diff) +1 -0
+	ret = driver_register(&matrix_driver.drv); +	if (ret) +		goto

matrix_drv_err; +

As you already have several structures that can be registered exactly once (the root device, the bus, the driver, ...), you can already be sure that there's only one device on the bus, can't you?

Quoted 6 lines
Quoted 3 lines

hum, no I don't think so, no device can register before this module is loaded, but what does prevent a device to register later from another module?

Not unless you export the interface, I guess.

:) definitively right
thanks, this will simplify the code in the next version.
I will take the patch away from this series to get the way to stable as Christian requested.

Regards,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
maintainer
#10 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 42 lines · Pierre Morel
Quoted 41 lines · Cornelia Huck
Quoted 38 lines · On Thu, 14 Feb 2019 16:47:30 +0100 Pierre Morel <[email protected]> wrote:
Quoted 8 lines · Cornelia Huck
Quoted 5 lines · On Thu, 14 Feb 2019 14:51:01 +0100 Pierre Morel <[email protected]> wrote:

+++ b/drivers/s390/crypto/vfio_ap_drv.c @@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");

static struct ap_driver vfio_ap_drv;

Quoted 7 lines
Quoted 3 lines

-static struct device_type vfio_ap_dev_type = { -    .name = VFIO_AP_DEV_TYPE_NAME, +struct matrix_driver { +    struct device_driver drv; +    int device_count;

This counter basically ensures that at most one device may bind with this driver... you'd still have that device on the bus, though.

yes, this is what is wanted: this driver can only support one device. May be another matrix driver can support one or more other devices.

I should update comment message my be.

Quoted 14 lines
Quoted 11 lines

};

struct ap_matrix_dev *matrix_dev;

-    matrix_dev->device.type = &vfio_ap_dev_type;
dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME); matrix_dev->device.parent = root_device; + matrix_dev->device.bus = &matrix_bus; matrix_dev->device.release = vfio_ap_matrix_dev_release; - matrix_dev->device.driver = &vfio_ap_drv.driver; +
matrix_dev->vfio_ap_drv = &vfio_ap_drv;

Can't you get that structure through matrix_dev->device.driver instead when you need it in the function below?

Quoted 8 lines
Quoted 8 lines
Quoted 5 lines

Not anymore. We have two different drivers and devices matrix_drv <-> matrix_dev and vfio_ap_drv <-> ap_devices

The driver behind the matrix_dev->dev->driver is matrix_drv what is needed here is vfio_ap_drv.

Wait, we had tacked a driver for ap devices unto a matrix device, which is not on the ap bus?

It's really a bit more complicated than that. Without going into a
lengthy description of the history of AP passthrough support, suffice it
to say that we needed a device to serve as the parent of each mediated
device used to configure a matrix of AP adapter IDs and domain indexes
identifying the devices to which a guest would be granted access. The
AP devices themselves are attached to the AP bus, but the matrix device
is an artificial (virtual?) device whose sole purpose in life is to
serve as an anchor for the mediated devices whose sysfs interfaces are
created and managed by the vfio_ap device driver. The matrix device
itself is created by the vfio_ap device driver - when it is initialized - for that purpose. In hindsight, maybe there was a better way to implement this, but neither this patch nor this discussion belongs in
this series. It distracts from discussion of interrupt support which is
the sole purpose of the patch series.

Quoted 38 lines

...yes -(

Quoted 2 lines

Maybe that's what trips libudev? >
(And reading further in the current code, it seems we clear that structure _after_ the matrix device had been setup, so how can that even work? Where am I confused?)

On device_register there were no bus, so the core just do not look for a driver and this field was nor tested nor overwritten.

Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 10 lines

ret = device_register(&matrix_dev->device); if (ret) goto matrix_reg_err;

+    ret = driver_register(&matrix_driver.drv); +    if (ret) +        goto
matrix_drv_err; +

As you already have several structures that can be registered exactly once (the root device, the bus, the driver, ...), you can already be sure that there's only one device on the bus, can't you?

Quoted 6 lines
Quoted 3 lines

hum, no I don't think so, no device can register before this module is loaded, but what does prevent a device to register later from another module?

Not unless you export the interface, I guess.

:) definitively right
thanks, this will simplify the code in the next version.
I will take the patch away from this series to get the way to stable as Christian requested.

Regards,
Pierre

#11 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 29 lines · On Thu, 14 Feb 2019 13:30:59 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 19 lines · Pierre Morel
Quoted 18 lines · Cornelia Huck
Quoted 15 lines · On Thu, 14 Feb 2019 16:47:30 +0100 Pierre Morel <[email protected]> wrote:
Quoted 13 lines · Cornelia Huck
Quoted 7 lines · On Thu, 14 Feb 2019 14:51:01 +0100 Pierre Morel <[email protected]> wrote:

-    matrix_dev->device.type = &vfio_ap_dev_type; dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME); matrix_dev->device.parent = root_device; + matrix_dev->device.bus = &matrix_bus; matrix_dev->device.release = vfio_ap_matrix_dev_release; -
matrix_dev->device.driver = &vfio_ap_drv.driver; + matrix_dev->vfio_ap_drv = &vfio_ap_drv;

Can't you get that structure through matrix_dev->device.driver instead when you need it in the function below?

Quoted 8 lines
Quoted 8 lines
Quoted 5 lines

Not anymore. We have two different drivers and devices matrix_drv <-> matrix_dev and vfio_ap_drv <-> ap_devices

The driver behind the matrix_dev->dev->driver is matrix_drv what is needed here is vfio_ap_drv.

Wait, we had tacked a driver for ap devices unto a matrix device, which is not on the ap bus?

Quoted 14 lines

It's really a bit more complicated than that. Without going into a lengthy description of the history of AP passthrough support, suffice it to say that we needed a device to serve as the parent of each mediated device used to configure a matrix of AP adapter IDs and domain indexes identifying the devices to which a guest would be granted access. The AP devices themselves are attached to the AP bus, but the matrix device is an artificial (virtual?) device whose sole purpose in life is to serve as an anchor for the mediated devices whose sysfs interfaces are created and managed by the vfio_ap device driver. The matrix device itself is created by the vfio_ap device driver - when it is initialized
- for that purpose. In hindsight, maybe there was a better way to implement this, but neither this patch nor this discussion belongs in this series. It distracts from discussion of interrupt support which is the sole purpose of the patch series.

The we-need-a-parent part is fine; but whatever we're doing with that driver just looks wrong, so that even the new bus that basically does nothing looks better...

Quoted 11 lines
Quoted 11 lines

...yes -(

Quoted 4 lines

Maybe that's what trips libudev? >
(And reading further in the current code, it seems we clear that structure _after_ the matrix device had been setup, so how can that even work? Where am I confused?)

On device_register there were no bus, so the core just do not look for a driver and this field was nor tested nor overwritten.

Hm... so has the callback in driver_for_each_device() in vfio_ap_verify_queue_reserved() ever been invoked at all? It seems this patch fixes more than just libudev issues...

Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 20 lines
Quoted 8 lines
Quoted 8 lines

ret = device_register(&matrix_dev->device); if (ret) goto matrix_reg_err;

Quoted 8 lines
Quoted 3 lines

+    ret = driver_register(&matrix_driver.drv); +    if (ret) +        goto
matrix_drv_err; +

As you already have several structures that can be registered exactly once (the root device, the bus, the driver, ...), you can already be sure that there's only one device on the bus, can't you?

hum, no I don't think so, no device can register before this module is loaded, but what does prevent a device to register later from another module?

Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

Not unless you export the interface, I guess.

:) definitively right
thanks, this will simplify the code in the next version.
I will take the patch away from this series to get the way to stable as Christian requested.

Yeah, makes sense.

maintainer
#12 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 47 lines · Cornelia Huck
Quoted 29 lines · On Thu, 14 Feb 2019 13:30:59 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 19 lines · Pierre Morel
Quoted 18 lines · Cornelia Huck
Quoted 15 lines · On Thu, 14 Feb 2019 16:47:30 +0100 Pierre Morel <[email protected]> wrote:
Quoted 13 lines · Cornelia Huck
Quoted 7 lines · On Thu, 14 Feb 2019 14:51:01 +0100 Pierre Morel <[email protected]> wrote:

-    matrix_dev->device.type = &vfio_ap_dev_type; dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME); matrix_dev->device.parent = root_device; + matrix_dev->device.bus = &matrix_bus; matrix_dev->device.release = vfio_ap_matrix_dev_release; -
matrix_dev->device.driver = &vfio_ap_drv.driver; + matrix_dev->vfio_ap_drv = &vfio_ap_drv;

Can't you get that structure through matrix_dev->device.driver instead when you need it in the function below?

Quoted 8 lines
Quoted 8 lines
Quoted 5 lines

Not anymore. We have two different drivers and devices matrix_drv <-> matrix_dev and vfio_ap_drv <-> ap_devices

The driver behind the matrix_dev->dev->driver is matrix_drv what is needed here is vfio_ap_drv.

Wait, we had tacked a driver for ap devices unto a matrix device, which is not on the ap bus?

Quoted 14 lines

It's really a bit more complicated than that. Without going into a lengthy description of the history of AP passthrough support, suffice it to say that we needed a device to serve as the parent of each mediated device used to configure a matrix of AP adapter IDs and domain indexes identifying the devices to which a guest would be granted access. The AP devices themselves are attached to the AP bus, but the matrix device is an artificial (virtual?) device whose sole purpose in life is to serve as an anchor for the mediated devices whose sysfs interfaces are created and managed by the vfio_ap device driver. The matrix device itself is created by the vfio_ap device driver - when it is initialized
- for that purpose. In hindsight, maybe there was a better way to implement this, but neither this patch nor this discussion belongs in this series. It distracts from discussion of interrupt support which is the sole purpose of the patch series.

Quoted 3 lines

The we-need-a-parent part is fine; but whatever we're doing with that driver just looks wrong, so that even the new bus that basically does nothing looks better...

I believe there might be a much better way to handle this which is why I objected to this patch being delivered with this series, which provides AP interrupt support. Quite simply, this patch has no relationship to interrupt support and should be considered as an item unto itself. To conduct a review within the context of interrupt support distracts focus from the pertinent subject matter.

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

...yes -(

Quoted 4 lines

Maybe that's what trips libudev? >
(And reading further in the current code, it seems we clear that structure _after_ the matrix device had been setup, so how can that even work? Where am I confused?)

Quoted 6 lines
Quoted 2 lines
Quoted 2 lines

On device_register there were no bus, so the core just do not look for a driver and this field was nor tested nor overwritten.

Hm... so has the callback in driver_for_each_device() in vfio_ap_verify_queue_reserved() ever been invoked at all? It seems this patch fixes more than just libudev issues...

It is this patch that rendered the driver_for_each_device() in vfio_ap_verify_queue_reserved() erroneous. That function gets called every time an adapter or domain is assigned to the mdev. This patch introduced the problem with driver_for_each_device().

Quoted 32 lines
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
Quoted 21 lines
Quoted 9 lines
Quoted 9 lines

ret = device_register(&matrix_dev->device); if (ret) goto matrix_reg_err;

Quoted 8 lines
Quoted 3 lines

+    ret = driver_register(&matrix_driver.drv); +    if (ret) +        goto
matrix_drv_err; +

As you already have several structures that can be registered exactly once (the root device, the bus, the driver, ...), you can already be sure that there's only one device on the bus, can't you?

hum, no I don't think so, no device can register before this module is loaded, but what does prevent a device to register later from another module?

Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

Not unless you export the interface, I guess.

:) definitively right
thanks, this will simplify the code in the next version.
I will take the patch away from this series to get the way to stable as Christian requested.

Yeah, makes sense.

#13 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 14 lines · On Fri, 15 Feb 2019 16:59:33 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 13 lines · Cornelia Huck
Quoted 9 lines · On Thu, 14 Feb 2019 13:30:59 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 8 lines · Pierre Morel
Quoted 3 lines · Cornelia Huck

(And reading further in the current code, it seems we clear that structure _after_ the matrix device had been setup, so how can that even work? Where am I confused?)

On device_register there were no bus, so the core just do not look for a driver and this field was nor tested nor overwritten.

Quoted 8 lines
Quoted 3 lines

Hm... so has the callback in driver_for_each_device() in vfio_ap_verify_queue_reserved() ever been invoked at all? It seems this patch fixes more than just libudev issues...

It is this patch that rendered the driver_for_each_device() in vfio_ap_verify_queue_reserved() erroneous. That function gets called every time an adapter or domain is assigned to the mdev. This patch introduced the problem with driver_for_each_device().

So, does this function need to be removed or called from another place, then? (It looks like it was dead code before.)

maintainer
#14 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 21 lines · Cornelia Huck
Quoted 18 lines · On Fri, 15 Feb 2019 16:59:33 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 16 lines · Cornelia Huck
Quoted 9 lines · On Thu, 14 Feb 2019 13:30:59 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 8 lines · Pierre Morel
Quoted 3 lines · Cornelia Huck

(And reading further in the current code, it seems we clear that structure _after_ the matrix device had been setup, so how can that even work? Where am I confused?)

On device_register there were no bus, so the core just do not look for a driver and this field was nor tested nor overwritten.

Hm... so has the callback in driver_for_each_device() in vfio_ap_verify_queue_reserved() ever been invoked at all? It seems this patch fixes more than just libudev issues...

Quoted 7 lines
Quoted 4 lines

It is this patch that rendered the driver_for_each_device() in vfio_ap_verify_queue_reserved() erroneous. That function gets called every time an adapter or domain is assigned to the mdev. This patch introduced the problem with driver_for_each_device().

So, does this function need to be removed or called from another place, then? (It looks like it was dead code before.)

I don't see why you think it's dead code:

assign_adapter_store
==> vfio_ap_mdev_verify_queues_reserved_for_apid

    ==> vfio_ap_verify_queue_reserved
        ==> driver_for_each_device

The only way that the vfio_ap_verify_queue_reserved - the function that calls driver_for_each_device - does not get called is if no bits have yet been set in matrix_mdev->matrix.aqm.

Quoted 1 line
#15 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 32 lines · On Mon, 18 Feb 2019 11:35:45 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 21 lines · Cornelia Huck
Quoted 18 lines · On Fri, 15 Feb 2019 16:59:33 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 16 lines · Cornelia Huck
Quoted 9 lines · On Thu, 14 Feb 2019 13:30:59 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 8 lines · Pierre Morel
Quoted 3 lines · Cornelia Huck

(And reading further in the current code, it seems we clear that structure _after_ the matrix device had been setup, so how can that even work? Where am I confused?)

On device_register there were no bus, so the core just do not look for a driver and this field was nor tested nor overwritten.

Hm... so has the callback in driver_for_each_device() in vfio_ap_verify_queue_reserved() ever been invoked at all? It seems this patch fixes more than just libudev issues...

Quoted 7 lines
Quoted 4 lines

It is this patch that rendered the driver_for_each_device() in vfio_ap_verify_queue_reserved() erroneous. That function gets called every time an adapter or domain is assigned to the mdev. This patch introduced the problem with driver_for_each_device().

So, does this function need to be removed or called from another place, then? (It looks like it was dead code before.)

I don't see why you think it's dead code:

Quoted 8 lines

assign_adapter_store
==> vfio_ap_mdev_verify_queues_reserved_for_apid

     ==> vfio_ap_verify_queue_reserved
         ==> driver_for_each_device  

The only way that the vfio_ap_verify_queue_reserved - the function that calls driver_for_each_device - does not get called is if no bits have yet been set in matrix_mdev->matrix.aqm.

What I don't see is how this can be called if no device has been, in fact, bound to the driver in the driver core...

maintainer
#16 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 40 lines · Cornelia Huck
Quoted 37 lines · On Mon, 18 Feb 2019 11:35:45 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 21 lines · Cornelia Huck
Quoted 18 lines · On Fri, 15 Feb 2019 16:59:33 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 16 lines · Cornelia Huck
Quoted 9 lines · On Thu, 14 Feb 2019 13:30:59 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 8 lines · Pierre Morel
Quoted 3 lines · Cornelia Huck

(And reading further in the current code, it seems we clear that structure _after_ the matrix device had been setup, so how can that even work? Where am I confused?)

On device_register there were no bus, so the core just do not look for a driver and this field was nor tested nor overwritten.

Hm... so has the callback in driver_for_each_device() in vfio_ap_verify_queue_reserved() ever been invoked at all? It seems this patch fixes more than just libudev issues...

Quoted 7 lines
Quoted 4 lines

It is this patch that rendered the driver_for_each_device() in vfio_ap_verify_queue_reserved() erroneous. That function gets called every time an adapter or domain is assigned to the mdev. This patch introduced the problem with driver_for_each_device().

So, does this function need to be removed or called from another place, then? (It looks like it was dead code before.)

I don't see why you think it's dead code:

assign_adapter_store
==> vfio_ap_mdev_verify_queues_reserved_for_apid

      ==> vfio_ap_verify_queue_reserved
          ==> driver_for_each_device
Quoted 6 lines
Quoted 3 lines

The only way that the vfio_ap_verify_queue_reserved - the function that calls driver_for_each_device - does not get called is if no bits have yet been set in matrix_mdev->matrix.aqm.

What I don't see is how this can be called if no device has been, in fact, bound to the driver in the driver core...

Let's start with the fact that one can create an mdev device regardless of whether a queue has been bound to the vfio_ap driver. Once an mdev device is created, one can start assigning adapters, domains and control domains to it. Let's say the admin now attempts to assign an adapter, in which case the assign_adapter_store() function is invoked. After verifying that the APID passed in is a valid adapter number, the vfio_ap_mdev_verify_queues_reserved_for_apid() function is called. This function first checks if any domains have been assigned and if not, calls vfio_ap_verify_queue_reserved(&apid, NULL). It is in this function that the driver_for_each_device() function is called. Since there are no devices bound to the vfio_ap device driver, the callback passed in to the driver_for_each_device() function will never get called, so the vfio_ap_mdev_verify_queues_reserved_for_apid() function will return -EADDRNOTAVAIL. A similar flow will occur if the first assignment is for a domain. The bottom line is, the driver_for_each_device() function is called every time an adapter or domain is assigned.

Quoted 1 line
#17 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 48 lines · On Tue, 19 Feb 2019 17:27:05 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 40 lines · Cornelia Huck
Quoted 37 lines · On Mon, 18 Feb 2019 11:35:45 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 21 lines · Cornelia Huck
Quoted 18 lines · On Fri, 15 Feb 2019 16:59:33 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 16 lines · Cornelia Huck
Quoted 9 lines · On Thu, 14 Feb 2019 13:30:59 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 8 lines · Pierre Morel
Quoted 3 lines · Cornelia Huck

(And reading further in the current code, it seems we clear that structure _after_ the matrix device had been setup, so how can that even work? Where am I confused?)

On device_register there were no bus, so the core just do not look for a driver and this field was nor tested nor overwritten.

Hm... so has the callback in driver_for_each_device() in vfio_ap_verify_queue_reserved() ever been invoked at all? It seems this patch fixes more than just libudev issues...

Quoted 7 lines
Quoted 4 lines

It is this patch that rendered the driver_for_each_device() in vfio_ap_verify_queue_reserved() erroneous. That function gets called every time an adapter or domain is assigned to the mdev. This patch introduced the problem with driver_for_each_device().

So, does this function need to be removed or called from another place, then? (It looks like it was dead code before.)

I don't see why you think it's dead code:

assign_adapter_store
==> vfio_ap_mdev_verify_queues_reserved_for_apid

      ==> vfio_ap_verify_queue_reserved
          ==> driver_for_each_device  
Quoted 6 lines
Quoted 3 lines

The only way that the vfio_ap_verify_queue_reserved - the function that calls driver_for_each_device - does not get called is if no bits have yet been set in matrix_mdev->matrix.aqm.

What I don't see is how this can be called if no device has been, in fact, bound to the driver in the driver core...

Quoted 16 lines

Let's start with the fact that one can create an mdev device regardless of whether a queue has been bound to the vfio_ap driver. Once an mdev device is created, one can start assigning adapters, domains and control domains to it. Let's say the admin now attempts to assign an adapter, in which case the assign_adapter_store() function is invoked. After verifying that the APID passed in is a valid adapter number, the vfio_ap_mdev_verify_queues_reserved_for_apid() function is called. This function first checks if any domains have been assigned and if not, calls vfio_ap_verify_queue_reserved(&apid, NULL). It is in this function that the driver_for_each_device() function is called. Since there are no devices bound to the vfio_ap device driver, the callback passed in to the driver_for_each_device() function will never get called, so the vfio_ap_mdev_verify_queues_reserved_for_apid() function will return -EADDRNOTAVAIL. A similar flow will occur if the first assignment is for a domain. The bottom line is, the driver_for_each_device() function is called every time an adapter or domain is assigned.

Indeed. I just got lost with the various drivers and devices in play here :(

#18 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

In reply to Pierre Morel
Quoted 11 lines · Pierre Morel

Libudev relies on having a subsystem link for non-root devices. To avoid libudev (and potentially other userspace tools) choking on the matrix device let us introduce a vfio_ap bus and with that the vfio_ap bus subsytem, and make the matrix device reside within it.

We restrict the number of allowed devices to a single one.

Doing this we need to suppress the forced link from the matrix device to the vfio_ap driver and we suppress the device_type we do not need anymore.

Quoted 5 lines

Since the associated matrix driver is not the vfio_ap driver any more, we have to change the search for the devices on the vfio_ap driver in the function vfio_ap_verify_queue_reserved.

Didnt you want to a add a reported-by?

Quoted 151 lines

---

 drivers/s390/crypto/vfio_ap_drv.c     | 63 +++++++++++++++++++++++++++++++----
 drivers/s390/crypto/vfio_ap_ops.c     |  4 +--
 drivers/s390/crypto/vfio_ap_private.h |  1 +
 3 files changed, 60 insertions(+), 8 deletions(-)
drivers/s390/crypto/vfio_ap_drv.c +57 -6
index 31c6c84..1fd5fe6 100644
@@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");
 
 static struct ap_driver vfio_ap_drv;
 
-static struct device_type vfio_ap_dev_type = {
-	.name = VFIO_AP_DEV_TYPE_NAME,
+struct matrix_driver {
+	struct device_driver drv;
+	int device_count;
 };
 
 struct ap_matrix_dev *matrix_dev;
@@ -62,6 +63,41 @@ static void vfio_ap_matrix_dev_release(struct device *dev)
 	kfree(matrix_dev);
 }
 
+static int matrix_bus_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static struct bus_type matrix_bus = {
+	.name = "vfio_ap",
+	.match = &matrix_bus_match,
+};
+
+static int matrix_probe(struct device *dev);
+static int matrix_remove(struct device *dev);
+static struct matrix_driver matrix_driver = {
+	.drv = {
+		.name = "vfio_ap",
+		.bus = &matrix_bus,
+		.probe = matrix_probe,
+		.remove = matrix_remove,
+	},
+};
+
+static int matrix_probe(struct device *dev)
+{
+	if (matrix_driver.device_count)
+		return -EEXIST;
+	matrix_driver.device_count++;
+	return 0;
+}
+
+static int matrix_remove(struct device *dev)
+{
+	matrix_driver.device_count--;
+	return 0;
+}
+
 static int vfio_ap_matrix_dev_create(void)
 {
 	int ret;
@@ -71,6 +107,10 @@ static int vfio_ap_matrix_dev_create(void)
 	if (IS_ERR(root_device))
 		return PTR_ERR(root_device);
 
+	ret = bus_register(&matrix_bus);
+	if (ret)
+		goto bus_register_err;
+
 	matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
 	if (!matrix_dev) {
 		ret = -ENOMEM;
@@ -87,30 +127,41 @@ static int vfio_ap_matrix_dev_create(void)
 	mutex_init(&matrix_dev->lock);
 	INIT_LIST_HEAD(&matrix_dev->mdev_list);
 
-	matrix_dev->device.type = &vfio_ap_dev_type;
 	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
 	matrix_dev->device.parent = root_device;
+	matrix_dev->device.bus = &matrix_bus;
 	matrix_dev->device.release = vfio_ap_matrix_dev_release;
-	matrix_dev->device.driver = &vfio_ap_drv.driver;
+	matrix_dev->vfio_ap_drv = &vfio_ap_drv;
 
 	ret = device_register(&matrix_dev->device);
 	if (ret)
 		goto matrix_reg_err;
 
+	ret = driver_register(&matrix_driver.drv);
+	if (ret)
+		goto matrix_drv_err;
+
 	return 0;
 
+matrix_drv_err:
+	device_unregister(&matrix_dev->device);
 matrix_reg_err:
 	put_device(&matrix_dev->device);
 matrix_alloc_err:
+	bus_unregister(&matrix_bus);
+bus_register_err:
 	root_device_unregister(root_device);
-
 	return ret;
 }
 
 static void vfio_ap_matrix_dev_destroy(void)
 {
+	struct device *root_device = matrix_dev->device.parent;
+
+	driver_unregister(&matrix_driver.drv);
 	device_unregister(&matrix_dev->device);
-	root_device_unregister(matrix_dev->device.parent);
+	bus_unregister(&matrix_bus);
+	root_device_unregister(root_device);
 }
 
 static int __init vfio_ap_init(void)
drivers/s390/crypto/vfio_ap_ops.c +2 -2
index 272ef42..900b9cf 100644
@@ -198,8 +198,8 @@ static int vfio_ap_verify_queue_reserved(unsigned long *apid,
 	qres.apqi = apqi;
 	qres.reserved = false;
 
-	ret = driver_for_each_device(matrix_dev->device.driver, NULL, &qres,
-				     vfio_ap_has_queue);
+	ret = driver_for_each_device(&matrix_dev->vfio_ap_drv->driver, NULL,
+				     &qres, vfio_ap_has_queue);
 	if (ret)
 		return ret;
 
drivers/s390/crypto/vfio_ap_private.h +1 -0
index 5675492..76b7f98 100644
@@ -40,6 +40,7 @@ struct ap_matrix_dev {
 	struct ap_config_info info;
 	struct list_head mdev_list;
 	struct mutex lock;
+	struct ap_driver  *vfio_ap_drv;
 };
 
 extern struct ap_matrix_dev *matrix_dev;
#19 lore raw

Re: [PATCH v3 1/9] s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem

Quoted 14 lines · Christian Borntraeger
Quoted 11 lines · Pierre Morel

Libudev relies on having a subsystem link for non-root devices. To avoid libudev (and potentially other userspace tools) choking on the matrix device let us introduce a vfio_ap bus and with that the vfio_ap bus subsytem, and make the matrix device reside within it.

We restrict the number of allowed devices to a single one.

Doing this we need to suppress the forced link from the matrix device to the vfio_ap driver and we suppress the device_type we do not need anymore.

Quoted 7 lines
Quoted 5 lines

Since the associated matrix driver is not the vfio_ap driver any more, we have to change the search for the devices on the vfio_ap driver in the function vfio_ap_verify_queue_reserved.

Didnt you want to a add a reported-by?

Yes, forgot it.

Quoted 151 lines
Quoted 151 lines

---

  drivers/s390/crypto/vfio_ap_drv.c     | 63 +++++++++++++++++++++++++++++++----
  drivers/s390/crypto/vfio_ap_ops.c     |  4 +--
  drivers/s390/crypto/vfio_ap_private.h |  1 +
  3 files changed, 60 insertions(+), 8 deletions(-)
drivers/s390/crypto/vfio_ap_drv.c +57 -6
index 31c6c84..1fd5fe6 100644
@@ -24,8 +24,9 @@ MODULE_LICENSE("GPL v2");
 
  static struct ap_driver vfio_ap_drv;
 
-static struct device_type vfio_ap_dev_type = {
-	.name = VFIO_AP_DEV_TYPE_NAME,
+struct matrix_driver {
+	struct device_driver drv;
+	int device_count;
  };
 
  struct ap_matrix_dev *matrix_dev;
@@ -62,6 +63,41 @@ static void vfio_ap_matrix_dev_release(struct device *dev)
  	kfree(matrix_dev);
  }
 
+static int matrix_bus_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static struct bus_type matrix_bus = {
+	.name = "vfio_ap",
+	.match = &matrix_bus_match,
+};
+
+static int matrix_probe(struct device *dev);
+static int matrix_remove(struct device *dev);
+static struct matrix_driver matrix_driver = {
+	.drv = {
+		.name = "vfio_ap",
+		.bus = &matrix_bus,
+		.probe = matrix_probe,
+		.remove = matrix_remove,
+	},
+};
+
+static int matrix_probe(struct device *dev)
+{
+	if (matrix_driver.device_count)
+		return -EEXIST;
+	matrix_driver.device_count++;
+	return 0;
+}
+
+static int matrix_remove(struct device *dev)
+{
+	matrix_driver.device_count--;
+	return 0;
+}
+
  static int vfio_ap_matrix_dev_create(void)
  {
  	int ret;
@@ -71,6 +107,10 @@ static int vfio_ap_matrix_dev_create(void)
  	if (IS_ERR(root_device))
  		return PTR_ERR(root_device);
 
+	ret = bus_register(&matrix_bus);
+	if (ret)
+		goto bus_register_err;
+
  	matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
  	if (!matrix_dev) {
  		ret = -ENOMEM;
@@ -87,30 +127,41 @@ static int vfio_ap_matrix_dev_create(void)
  	mutex_init(&matrix_dev->lock);
  	INIT_LIST_HEAD(&matrix_dev->mdev_list);
 
-	matrix_dev->device.type = &vfio_ap_dev_type;
  	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
  	matrix_dev->device.parent = root_device;
+	matrix_dev->device.bus = &matrix_bus;
  	matrix_dev->device.release = vfio_ap_matrix_dev_release;
-	matrix_dev->device.driver = &vfio_ap_drv.driver;
+	matrix_dev->vfio_ap_drv = &vfio_ap_drv;
 
  	ret = device_register(&matrix_dev->device);
  	if (ret)
  		goto matrix_reg_err;
 
+	ret = driver_register(&matrix_driver.drv);
+	if (ret)
+		goto matrix_drv_err;
+
  	return 0;
 
+matrix_drv_err:
+	device_unregister(&matrix_dev->device);
  matrix_reg_err:
  	put_device(&matrix_dev->device);
  matrix_alloc_err:
+	bus_unregister(&matrix_bus);
+bus_register_err:
  	root_device_unregister(root_device);
-
  	return ret;
  }
 
  static void vfio_ap_matrix_dev_destroy(void)
  {
+	struct device *root_device = matrix_dev->device.parent;
+
+	driver_unregister(&matrix_driver.drv);
  	device_unregister(&matrix_dev->device);
-	root_device_unregister(matrix_dev->device.parent);
+	bus_unregister(&matrix_bus);
+	root_device_unregister(root_device);
  }
 
  static int __init vfio_ap_init(void)
drivers/s390/crypto/vfio_ap_ops.c +2 -2
index 272ef42..900b9cf 100644
@@ -198,8 +198,8 @@ static int vfio_ap_verify_queue_reserved(unsigned long *apid,
  	qres.apqi = apqi;
  	qres.reserved = false;
 
-	ret = driver_for_each_device(matrix_dev->device.driver, NULL, &qres,
-				     vfio_ap_has_queue);
+	ret = driver_for_each_device(&matrix_dev->vfio_ap_drv->driver, NULL,
+				     &qres, vfio_ap_has_queue);
  	if (ret)
  		return ret;
 
drivers/s390/crypto/vfio_ap_private.h +1 -0
index 5675492..76b7f98 100644
@@ -40,6 +40,7 @@ struct ap_matrix_dev {
  	struct ap_config_info info;
  	struct list_head mdev_list;
  	struct mutex lock;
+	struct ap_driver  *vfio_ap_drv;
  };
 
  extern struct ap_matrix_dev *matrix_dev;
Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#20 lore raw

PATCH v3 2/9 s390: ap: kvm: setting a hook for PQAP instructions

In reply to Pierre Morel

This patch adds interception code for the PQAP instructions, and a callback inside the KVM arch structure for s390.

If a VFIO-AP drivers needs to intercept PQAP/AQIC or PQAP/TAPQ instructions, the driver will initialize the callback inside the kvm_arch structure to be called when the interception of a PQAP instruction occurs.

If the callback is not initialized, the code still returns -EOPNOTSUPP to let userland handle the instruction as it used to.

---
 arch/s390/include/asm/kvm_host.h |  1 +
 arch/s390/kvm/priv.c             | 50 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+)
arch/s390/include/asm/kvm_host.h +1 -0
index c5f5156..49cc8b0 100644
@@ -719,6 +719,7 @@ struct kvm_s390_cpu_model {
 
 struct kvm_s390_crypto {
 	struct kvm_s390_crypto_cb *crycb;
+	int (*pqap_hook)(struct kvm_vcpu *vcpu);
 	__u32 crycbd;
 	__u8 aes_kw;
 	__u8 dea_kw;
arch/s390/kvm/priv.c +50 -0

68 lines not on this page · raw message

Signature · 1 line
2.7.4
#21 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

Quoted 4 lines · On Thu, 14 Feb 2019 14:51:02 +0100 Pierre Morel <[email protected]> wrote:

This patch adds interception code for the PQAP instructions, and a callback inside the KVM arch structure for s390.

If a VFIO-AP drivers needs to intercept PQAP/AQIC or PQAP/TAPQ

s/drivers/driver/

Quoted 39 lines

instructions, the driver will initialize the callback inside the kvm_arch structure to be called when the interception of a PQAP instruction occurs.

If the callback is not initialized, the code still returns -EOPNOTSUPP to let userland handle the instruction as it used to.

---
 arch/s390/include/asm/kvm_host.h |  1 +
 arch/s390/kvm/priv.c             | 50 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+)
arch/s390/include/asm/kvm_host.h +1 -0
index c5f5156..49cc8b0 100644
@@ -719,6 +719,7 @@ struct kvm_s390_cpu_model {
 
 struct kvm_s390_crypto {
 	struct kvm_s390_crypto_cb *crycb;
+	int (*pqap_hook)(struct kvm_vcpu *vcpu);
 	__u32 crycbd;
 	__u8 aes_kw;
 	__u8 dea_kw;
arch/s390/kvm/priv.c +1 -0
index 8679bd7..72fdc21 100644
@@ -27,6 +27,7 @@
 #include <asm/io.h>
 #include <asm/ptrace.h>
 #include <asm/sclp.h>
+#include <asm/ap.h>
 #include "gaccess.h"
 #include "kvm-s390.h"
 #include "trace.h"

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 598

Quoted 6 lines
arch/s390/kvm/priv.c +3 -0
@@ -592,6 +593,53 @@ static int handle_io_inst(struct kvm_vcpu *vcpu)
 	}
 }
 
+/*
+ * handle_pqap: Handling pqap interception
+ * @vcpu: the vcpu having issue the pqap instruction

s/issue/issued/

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 600

Quoted 2 lines
arch/s390/kvm/priv.c +2 -0
+ *
+ * This callback only handles PQAP/AQIC instruction and

Here you only talk about PQAP/AQIC, what about PQAP/TAPQ mentioned in the patch description?

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 606

Quoted 6 lines
arch/s390/kvm/priv.c +6 -0
+ * calls a dedicated callback for this instruction if
+ * a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * Do not change the behavior if, return -EOPNOTSUPP if:
+ * - the hook is not used do not change the behavior.

The hook is not used? Or not set? (I don't think you need to repeat "do not change the behavior".)

Quoted 24 lines
arch/s390/kvm/priv.c +24 -0
+ * - AP instructions are not available or not available to the guest
+ * - the instruction is not PQAP with function code indicating
+ *   AQIC do not change the previous behavior.
+ *
+ * For PQAP/AQIC instruction, verify privilege and specifications
+ *
+ * return the value returned by the callback.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+	uint8_t fc;
+
+	/* Verify that the hook callback is registered */
+	if (!vcpu->kvm->arch.crypto.pqap_hook)
+		return -EOPNOTSUPP;
+	/* Verify that the AP instruction are available */
+	if (!ap_instructions_available())
+		return -EOPNOTSUPP;
+	/* Verify that the guest is allowed to use AP instructions */
+	if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+		return -EOPNOTSUPP;
+	/* Verify that the function code is AQIC */
+	fc = vcpu->run->s.regs.gprs[0] >> 24;
+	if (fc != 0x03)

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 640

Quoted 10 lines
arch/s390/kvm/priv.c +10 -0
+		return -EOPNOTSUPP;
+
+	/* PQAP instructions are allowed for guest kernel only */
+	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+	/* AQIC instruction is allowed only if facility 65 is available */
+	if (!test_kvm_facility(vcpu->kvm, 65))
+		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+	/* All right, call the callback */
+	return vcpu->kvm->arch.crypto.pqap_hook(vcpu);

Can that callback also return -EOPNOTSUPP to order to drop to user space?

Quoted 14 lines
arch/s390/kvm/priv.c +4 -0
+}
+
 static int handle_stfl(struct kvm_vcpu *vcpu)
 {
 	int rc;
@@ -878,6 +926,8 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
 		return handle_sthyi(vcpu);
 	case 0x7d:
 		return handle_stsi(vcpu);
+	case 0xaf:
+		return handle_pqap(vcpu);
 	case 0xb1:
 		return handle_stfl(vcpu);
 	case 0xb2:
#22 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

Quoted 9 lines · Cornelia Huck
Quoted 4 lines · On Thu, 14 Feb 2019 14:51:02 +0100 Pierre Morel <[email protected]> wrote:

This patch adds interception code for the PQAP instructions, and a callback inside the KVM arch structure for s390.

If a VFIO-AP drivers needs to intercept PQAP/AQIC or PQAP/TAPQ

s/drivers/driver/

thanks. OK

Quoted 1 line

...

Quoted 11 lines

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 598

Quoted 9 lines
  #include "kvm-s390.h"
  #include "trace.h"
arch/s390/kvm/priv.c +3 -0
@@ -592,6 +593,53 @@ static int handle_io_inst(struct kvm_vcpu *vcpu)
  	}
  }
 
+/*
+ * handle_pqap: Handling pqap interception
+ * @vcpu: the vcpu having issue the pqap instruction

s/issue/issued/

OK. thanks.

Quoted 6 lines

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 600

Quoted 3 lines
arch/s390/kvm/priv.c +2 -0
+ *
+ * This callback only handles PQAP/AQIC instruction and

Here you only talk about PQAP/AQIC, what about PQAP/TAPQ mentioned in the patch description?

I can add "for now" or "in this patch" or suppress the reference to PAPQ/TAPQ

Quoted 9 lines

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 606

Quoted 7 lines
arch/s390/kvm/priv.c +6 -0
+ * calls a dedicated callback for this instruction if
+ * a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * Do not change the behavior if, return -EOPNOTSUPP if:
+ * - the hook is not used do not change the behavior.

The hook is not used? Or not set?

I think "is not set" is better.

Quoted 2 lines

(I don't think you need to repeat "do
not change the behavior".)

OK

Quoted 30 lines
Quoted 30 lines
arch/s390/kvm/priv.c +29 -0
+ * - AP instructions are not available or not available to the guest
+ * - the instruction is not PQAP with function code indicating
+ *   AQIC do not change the previous behavior.
+ *
+ * For PQAP/AQIC instruction, verify privilege and specifications
+ *
+ * return the value returned by the callback.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+	uint8_t fc;
+
+	/* Verify that the hook callback is registered */
+	if (!vcpu->kvm->arch.crypto.pqap_hook)
+		return -EOPNOTSUPP;
+	/* Verify that the AP instruction are available */
+	if (!ap_instructions_available())
+		return -EOPNOTSUPP;
+	/* Verify that the guest is allowed to use AP instructions */
+	if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+		return -EOPNOTSUPP;
+	/* Verify that the function code is AQIC */
+	fc = vcpu->run->s.regs.gprs[0] >> 24;
+	if (fc != 0x03)
+		return -EOPNOTSUPP;
+
+	/* PQAP instructions are allowed for guest kernel only */
+	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
Quoted 8 lines

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 640

Quoted 5 lines
arch/s390/kvm/priv.c +5 -0
+	/* AQIC instruction is allowed only if facility 65 is available */
+	if (!test_kvm_facility(vcpu->kvm, 65))
+		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+	/* All right, call the callback */
+	return vcpu->kvm->arch.crypto.pqap_hook(vcpu);

Can that callback also return -EOPNOTSUPP to order to drop to user space?

Yes.
Why not?

Quoted 16 lines
Quoted 15 lines
arch/s390/kvm/priv.c +4 -0
+}
+
  static int handle_stfl(struct kvm_vcpu *vcpu)
  {
  	int rc;
@@ -878,6 +926,8 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
  		return handle_sthyi(vcpu);
  	case 0x7d:
  		return handle_stsi(vcpu);
+	case 0xaf:
+		return handle_pqap(vcpu);
  	case 0xb1:
  		return handle_stfl(vcpu);
  	case 0xb2:
Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#23 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

Quoted 14 lines · On Thu, 14 Feb 2019 17:45:06 +0100 Pierre Morel <[email protected]> wrote:
Quoted 9 lines · Cornelia Huck
Quoted 4 lines · On Thu, 14 Feb 2019 14:51:02 +0100 Pierre Morel <[email protected]> wrote:

This patch adds interception code for the PQAP instructions, and a callback inside the KVM arch structure for s390.

If a VFIO-AP drivers needs to intercept PQAP/AQIC or PQAP/TAPQ

s/drivers/driver/

thanks. OK

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

+ *
+ * This callback only handles PQAP/AQIC instruction and

Here you only talk about PQAP/AQIC, what about PQAP/TAPQ mentioned in the patch description?

I can add "for now" or "in this patch" or suppress the reference to PAPQ/TAPQ

I'd just add a note to the patch description that this patch only handles PQAP/AQCI and that handling PQAP/TAPQ is something for a follow-on patch.

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines

+ * calls a dedicated callback for this instruction if
+ * a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * Do not change the behavior if, return -EOPNOTSUPP if:
+ * - the hook is not used do not change the behavior.

Quoted 3 lines
Quoted 1 line

The hook is not used? Or not set?

I think "is not set" is better.

Ok.

Quoted 45 lines
Quoted 3 lines

(I don't think you need to repeat "do
not change the behavior".)

OK

Quoted 30 lines
Quoted 30 lines

+ * - AP instructions are not available or not available to the guest
+ * - the instruction is not PQAP with function code indicating
+ * AQIC do not change the previous behavior.
+ *
+ * For PQAP/AQIC instruction, verify privilege and specifications
+ *
+ * return the value returned by the callback.
+ */

arch/s390/kvm/priv.c +21 -0
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+	uint8_t fc;
+
+	/* Verify that the hook callback is registered */
+	if (!vcpu->kvm->arch.crypto.pqap_hook)
+		return -EOPNOTSUPP;
+	/* Verify that the AP instruction are available */
+	if (!ap_instructions_available())
+		return -EOPNOTSUPP;
+	/* Verify that the guest is allowed to use AP instructions */
+	if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+		return -EOPNOTSUPP;
+	/* Verify that the function code is AQIC */
+	fc = vcpu->run->s.regs.gprs[0] >> 24;
+	if (fc != 0x03)
+		return -EOPNOTSUPP;
+
+	/* PQAP instructions are allowed for guest kernel only */
+	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
Quoted 8 lines

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 640

Quoted 5 lines
arch/s390/kvm/priv.c +5 -0
+	/* AQIC instruction is allowed only if facility 65 is available */
+	if (!test_kvm_facility(vcpu->kvm, 65))
+		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+	/* All right, call the callback */
+	return vcpu->kvm->arch.crypto.pqap_hook(vcpu);  

Can that callback also return -EOPNOTSUPP to order to drop to user space?

Quoted 2 lines

Yes.
Why not?

Maybe also mention that in the function description?

#24 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

Quoted 23 lines · Cornelia Huck
Quoted 20 lines · On Thu, 14 Feb 2019 17:45:06 +0100 Pierre Morel <[email protected]> wrote:
Quoted 9 lines · Cornelia Huck
Quoted 4 lines · On Thu, 14 Feb 2019 14:51:02 +0100 Pierre Morel <[email protected]> wrote:

This patch adds interception code for the PQAP instructions, and a callback inside the KVM arch structure for s390.

If a VFIO-AP drivers needs to intercept PQAP/AQIC or PQAP/TAPQ

s/drivers/driver/

thanks. OK

Quoted 5 lines
Quoted 2 lines

+ *
+ * This callback only handles PQAP/AQIC instruction and

Here you only talk about PQAP/AQIC, what about PQAP/TAPQ mentioned in the patch description?

Quoted 6 lines
Quoted 2 lines

I can add "for now" or "in this patch" or suppress the reference to PAPQ/TAPQ

I'd just add a note to the patch description that this patch only handles PQAP/AQCI and that handling PQAP/TAPQ is something for a follow-on patch.

OK, I will clear this.
Thanks

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

...snip...

Quoted 12 lines
Quoted 12 lines
Quoted 11 lines

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 640

Quoted 8 lines
arch/s390/kvm/priv.c +8 -0
+	/* PQAP instructions are allowed for guest kernel only */
+	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+	/* AQIC instruction is allowed only if facility 65 is available */
+	if (!test_kvm_facility(vcpu->kvm, 65))
+		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+	/* All right, call the callback */
+	return vcpu->kvm->arch.crypto.pqap_hook(vcpu);

Can that callback also return -EOPNOTSUPP to order to drop to user space?

Quoted 5 lines
Quoted 2 lines

Yes.
Why not?

Maybe also mention that in the function description?

Will do thanks.

Regards,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
maintainer
#25 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

In reply to Pierre Morel
Quoted 72 lines · Pierre Morel

This patch adds interception code for the PQAP instructions, and a callback inside the KVM arch structure for s390.

If a VFIO-AP drivers needs to intercept PQAP/AQIC or PQAP/TAPQ instructions, the driver will initialize the callback inside the kvm_arch structure to be called when the interception of a PQAP instruction occurs.

If the callback is not initialized, the code still returns -EOPNOTSUPP to let userland handle the instruction as it used to.

---
  arch/s390/include/asm/kvm_host.h |  1 +
  arch/s390/kvm/priv.c             | 50 ++++++++++++++++++++++++++++++++++++++++
  2 files changed, 51 insertions(+)
arch/s390/include/asm/kvm_host.h +1 -0
index c5f5156..49cc8b0 100644
@@ -719,6 +719,7 @@ struct kvm_s390_cpu_model {
 
  struct kvm_s390_crypto {
  	struct kvm_s390_crypto_cb *crycb;
+	int (*pqap_hook)(struct kvm_vcpu *vcpu);
  	__u32 crycbd;
  	__u8 aes_kw;
  	__u8 dea_kw;
arch/s390/kvm/priv.c +27 -0
index 8679bd7..72fdc21 100644
@@ -27,6 +27,7 @@
  #include <asm/io.h>
  #include <asm/ptrace.h>
  #include <asm/sclp.h>
+#include <asm/ap.h>
  #include "gaccess.h"
  #include "kvm-s390.h"
  #include "trace.h"
@@ -592,6 +593,53 @@ static int handle_io_inst(struct kvm_vcpu *vcpu)
  	}
  }
 
+/*
+ * handle_pqap: Handling pqap interception
+ * @vcpu: the vcpu having issue the pqap instruction
+ *
+ * This callback only handles PQAP/AQIC instruction and
+ * calls a dedicated callback for this instruction if
+ * a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * Do not change the behavior if, return -EOPNOTSUPP if:
+ * - the hook is not used do not change the behavior.
+ * - AP instructions are not available or not available to the guest
+ * - the instruction is not PQAP with function code indicating
+ *   AQIC do not change the previous behavior.
+ *
+ * For PQAP/AQIC instruction, verify privilege and specifications
+ *
+ * return the value returned by the callback.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+	uint8_t fc;
+
+	/* Verify that the hook callback is registered */
+	if (!vcpu->kvm->arch.crypto.pqap_hook)
+		return -EOPNOTSUPP;

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 631

Quoted 10 lines
arch/s390/kvm/priv.c +10 -0
+	/* Verify that the AP instruction are available */
+	if (!ap_instructions_available())
+		return -EOPNOTSUPP;
+	/* Verify that the guest is allowed to use AP instructions */
+	if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+		return -EOPNOTSUPP;
+	/* Verify that the function code is AQIC */
+	fc = vcpu->run->s.regs.gprs[0] >> 24;
+	if (fc != 0x03)
+		return -EOPNOTSUPP;

This does not belong here. Function code 3 is one of 7 function codes that can be sent with the PQAP instruction. This belongs in the PQAP hook code.

Quoted 24 lines
arch/s390/kvm/priv.c +13 -0
+
+	/* PQAP instructions are allowed for guest kernel only */
+	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+	/* AQIC instruction is allowed only if facility 65 is available */
+	if (!test_kvm_facility(vcpu->kvm, 65))
+		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+	/* All right, call the callback */
+	return vcpu->kvm->arch.crypto.pqap_hook(vcpu);
+}
+
  static int handle_stfl(struct kvm_vcpu *vcpu)
  {
  	int rc;
@@ -878,6 +926,8 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
  		return handle_sthyi(vcpu);
  	case 0x7d:
  		return handle_stsi(vcpu);
+	case 0xaf:
+		return handle_pqap(vcpu);
  	case 0xb1:
  		return handle_stfl(vcpu);
  	case 0xb2:
#26 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

Quoted 78 lines · Tony Krowiak
Quoted 77 lines · Pierre Morel

This patch adds interception code for the PQAP instructions, and a callback inside the KVM arch structure for s390.

If a VFIO-AP drivers needs to intercept PQAP/AQIC or PQAP/TAPQ instructions, the driver will initialize the callback inside the kvm_arch structure to be called when the interception of a PQAP instruction occurs.

If the callback is not initialized, the code still returns -EOPNOTSUPP to let userland handle the instruction as it used to.

---
  arch/s390/include/asm/kvm_host.h |  1 +
  arch/s390/kvm/priv.c             | 50
++++++++++++++++++++++++++++++++++++++++

  2 files changed, 51 insertions(+)
arch/s390/include/asm/kvm_host.h +1 -0
index c5f5156..49cc8b0 100644
@@ -719,6 +719,7 @@ struct kvm_s390_cpu_model {
   struct kvm_s390_crypto {
       struct kvm_s390_crypto_cb *crycb;
+    int (*pqap_hook)(struct kvm_vcpu *vcpu);
       __u32 crycbd;
       __u8 aes_kw;
       __u8 dea_kw;
arch/s390/kvm/priv.c +33 -0
index 8679bd7..72fdc21 100644
@@ -27,6 +27,7 @@
   #include <asm/io.h>
   #include <asm/ptrace.h>
   #include <asm/sclp.h>
+#include <asm/ap.h>
   #include "gaccess.h"
   #include "kvm-s390.h"
   #include "trace.h"
@@ -592,6 +593,53 @@ static int handle_io_inst(struct kvm_vcpu *vcpu)
       }
   }
+/*
+ * handle_pqap: Handling pqap interception
+ * @vcpu: the vcpu having issue the pqap instruction
+ *
+ * This callback only handles PQAP/AQIC instruction and
+ * calls a dedicated callback for this instruction if
+ * a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * Do not change the behavior if, return -EOPNOTSUPP if:
+ * - the hook is not used do not change the behavior.
+ * - AP instructions are not available or not available to the guest
+ * - the instruction is not PQAP with function code indicating
+ *   AQIC do not change the previous behavior.
+ *
+ * For PQAP/AQIC instruction, verify privilege and specifications
+ *
+ * return the value returned by the callback.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+    uint8_t fc;
+
+    /* Verify that the hook callback is registered */
+    if (!vcpu->kvm->arch.crypto.pqap_hook)
+        return -EOPNOTSUPP;
+    /* Verify that the AP instruction are available */
+    if (!ap_instructions_available())
+        return -EOPNOTSUPP;
+    /* Verify that the guest is allowed to use AP instructions */
+    if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+        return -EOPNOTSUPP;
Quoted 8 lines

arch/s390/kvm/priv.c static int handle_io_inst(struct kvm_vcpu *vcpu) · line 631

Quoted 4 lines
arch/s390/kvm/priv.c +4 -0
+    /* Verify that the function code is AQIC */
+    fc = vcpu->run->s.regs.gprs[0] >> 24;
+    if (fc != 0x03)
+        return -EOPNOTSUPP;

This does not belong here. Function code 3 is one of 7 function codes that can be sent with the PQAP instruction. This belongs in the PQAP hook code.

On one hand, effectively I would prefer to put the code in the VFIO driver code.
On the other hand, doing this would lead to export the code for test_kvm_facility() and kvm_s390_inject_program_int() from the kvm-s390.h

I choose not to export these functions from the KVM code.

Would like opinion from KVM maintainers?

Quoted 26 lines
Quoted 25 lines
arch/s390/kvm/priv.c +11 -0
+
+    /* PQAP instructions are allowed for guest kernel only */
+    if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+        return kvm_s390_inject_program_intkvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+    /* AQIC instruction is allowed only if facility 65 is available */
+    if (!test_kvm_facility(vcpu->kvm, 65))
+        return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+    /* All right, call the callback */
+    return vcpu->kvm->arch.crypto.pqap_hook(vcpu);
+}
+
   static int handle_stfl(struct kvm_vcpu *vcpu)
   {
       int rc;
@@ -878,6 +926,8 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
           return handle_sthyi(vcpu);

      case 0x7d:
          return handle_stsi(vcpu);
+    case 0xaf:
+        return handle_pqap(vcpu);
      case 0xb1:
          return handle_stfl(vcpu);
      case 0xb2:

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#27 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

Quoted 44 lines · On Mon, 18 Feb 2019 19:29:10 +0100 Pierre Morel <[email protected]> wrote:
Quoted 34 lines · Tony Krowiak
Quoted 32 lines · Pierre Morel
arch/s390/kvm/priv.c +32 -0
+/*
+ * handle_pqap: Handling pqap interception
+ * @vcpu: the vcpu having issue the pqap instruction
+ *
+ * This callback only handles PQAP/AQIC instruction and
+ * calls a dedicated callback for this instruction if
+ * a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * Do not change the behavior if, return -EOPNOTSUPP if:
+ * - the hook is not used do not change the behavior.
+ * - AP instructions are not available or not available to the guest
+ * - the instruction is not PQAP with function code indicating
+ *   AQIC do not change the previous behavior.
+ *
+ * For PQAP/AQIC instruction, verify privilege and specifications
+ *
+ * return the value returned by the callback.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+    uint8_t fc;
+
+    /* Verify that the hook callback is registered */
+    if (!vcpu->kvm->arch.crypto.pqap_hook)
+        return -EOPNOTSUPP;
+    /* Verify that the AP instruction are available */
+    if (!ap_instructions_available())
+        return -EOPNOTSUPP;
+    /* Verify that the guest is allowed to use AP instructions */
+    if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+        return -EOPNOTSUPP;
Quoted 8 lines
Quoted 4 lines

+    /* Verify that the function code is AQIC */
+    fc = vcpu->run->s.regs.gprs[0] >> 24;
+    if (fc != 0x03)
+        return -EOPNOTSUPP;

This does not belong here. Function code 3 is one of 7 function codes that can be sent with the PQAP instruction. This belongs in the PQAP hook code.

Quoted 8 lines

On one hand, effectively I would prefer to put the code in the VFIO driver code.
On the other hand, doing this would lead to export the code for test_kvm_facility() and kvm_s390_inject_program_int() from the kvm-s390.h

I choose not to export these functions from the KVM code.

Would like opinion from KVM maintainers?

Looking at this (and without access to the specification...), I think the check for problem state makes sense in here (if this applies to all PQAP functions equally, which seems likely). The check for the facility makes more sense in the handler. You can probably still inject the specification exception here if you use a clever return code.

Another option: Provide a way to register a callback per function code; this allows you to still do the check here and extend it later for other function codes (which will probably be indicated by another facility).

Quoted 29 lines
Quoted 27 lines
Quoted 26 lines
arch/s390/kvm/priv.c +11 -0
+
+    /* PQAP instructions are allowed for guest kernel only */
+    if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+        return kvm_s390_inject_program_intkvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+    /* AQIC instruction is allowed only if facility 65 is available */
+    if (!test_kvm_facility(vcpu->kvm, 65))
+        return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+    /* All right, call the callback */
+    return vcpu->kvm->arch.crypto.pqap_hook(vcpu);
+}
+

  static int handle_stfl(struct kvm_vcpu *vcpu)
  {
      int rc;

arch/s390/kvm/priv.c +0 -0
@@ -878,6 +926,8 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
           return handle_sthyi(vcpu);

      case 0x7d:
          return handle_stsi(vcpu);
+    case 0xaf:
+        return handle_pqap(vcpu);
      case 0xb1:
          return handle_stfl(vcpu);
      case 0xb2:

#28 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

Quoted 54 lines · Cornelia Huck
Quoted 51 lines · On Mon, 18 Feb 2019 19:29:10 +0100 Pierre Morel <[email protected]> wrote:
Quoted 34 lines · Tony Krowiak
Quoted 32 lines · Pierre Morel
arch/s390/kvm/priv.c +32 -0
+/*
+ * handle_pqap: Handling pqap interception
+ * @vcpu: the vcpu having issue the pqap instruction
+ *
+ * This callback only handles PQAP/AQIC instruction and
+ * calls a dedicated callback for this instruction if
+ * a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * Do not change the behavior if, return -EOPNOTSUPP if:
+ * - the hook is not used do not change the behavior.
+ * - AP instructions are not available or not available to the guest
+ * - the instruction is not PQAP with function code indicating
+ *   AQIC do not change the previous behavior.
+ *
+ * For PQAP/AQIC instruction, verify privilege and specifications
+ *
+ * return the value returned by the callback.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+    uint8_t fc;
+
+    /* Verify that the hook callback is registered */
+    if (!vcpu->kvm->arch.crypto.pqap_hook)
+        return -EOPNOTSUPP;
+    /* Verify that the AP instruction are available */
+    if (!ap_instructions_available())
+        return -EOPNOTSUPP;
+    /* Verify that the guest is allowed to use AP instructions */
+    if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+        return -EOPNOTSUPP;
Quoted 8 lines
Quoted 4 lines

+    /* Verify that the function code is AQIC */
+    fc = vcpu->run->s.regs.gprs[0] >> 24;
+    if (fc != 0x03)
+        return -EOPNOTSUPP;

This does not belong here. Function code 3 is one of 7 function codes that can be sent with the PQAP instruction. This belongs in the PQAP hook code.

On one hand, effectively I would prefer to put the code in the VFIO driver code.
On the other hand, doing this would lead to export the code for test_kvm_facility() and kvm_s390_inject_program_int() from the kvm-s390.h

I choose not to export these functions from the KVM code.

Quoted 8 lines
Quoted 1 line

Would like opinion from KVM maintainers?

Looking at this (and without access to the specification...), I think the check for problem state makes sense in here (if this applies to all PQAP functions equally, which seems likely). The check for the facility makes more sense in the handler. You can probably still inject the specification exception here if you use a clever return code.

If there is no objection on exporting the KVM functions... I can do this.

Quoted 4 lines

Another option: Provide a way to register a callback per function code; this allows you to still do the check here and extend it later for other function codes (which will probably be indicated by another facility).

I like this option even better.

Regards,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
maintainer
#29 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

Quoted 57 lines · Pierre Morel
Quoted 56 lines · Cornelia Huck
Quoted 52 lines · On Mon, 18 Feb 2019 19:29:10 +0100 Pierre Morel <[email protected]> wrote:
Quoted 34 lines · Tony Krowiak
Quoted 32 lines · Pierre Morel
arch/s390/kvm/priv.c +32 -0
+/*
+ * handle_pqap: Handling pqap interception
+ * @vcpu: the vcpu having issue the pqap instruction
+ *
+ * This callback only handles PQAP/AQIC instruction and
+ * calls a dedicated callback for this instruction if
+ * a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * Do not change the behavior if, return -EOPNOTSUPP if:
+ * - the hook is not used do not change the behavior.
+ * - AP instructions are not available or not available to the guest
+ * - the instruction is not PQAP with function code indicating
+ *   AQIC do not change the previous behavior.
+ *
+ * For PQAP/AQIC instruction, verify privilege and specifications
+ *
+ * return the value returned by the callback.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+    uint8_t fc;
+
+    /* Verify that the hook callback is registered */
+    if (!vcpu->kvm->arch.crypto.pqap_hook)
+        return -EOPNOTSUPP;
+    /* Verify that the AP instruction are available */
+    if (!ap_instructions_available())
+        return -EOPNOTSUPP;
+    /* Verify that the guest is allowed to use AP instructions */
+    if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+        return -EOPNOTSUPP;
Quoted 8 lines
Quoted 4 lines

+    /* Verify that the function code is AQIC */
+    fc = vcpu->run->s.regs.gprs[0] >> 24;
+    if (fc != 0x03)
+        return -EOPNOTSUPP;

This does not belong here. Function code 3 is one of 7 function codes that can be sent with the PQAP instruction. This belongs in the PQAP hook code.

On one hand, effectively I would prefer to put the code in the VFIO driver code.
On the other hand, doing this would lead to export the code for test_kvm_facility() and kvm_s390_inject_program_int() from the kvm-s390.h

I choose not to export these functions from the KVM code.

Would like opinion from KVM maintainers?

Quoted 8 lines
Quoted 6 lines

Looking at this (and without access to the specification...), I think the check for problem state makes sense in here (if this applies to all PQAP functions equally, which seems likely). The check for the facility makes more sense in the handler. You can probably still inject the specification exception here if you use a clever return code.

If there is no objection on exporting the KVM functions... I can do this.

I do not understand why you would have to export KVM functions to place the check for FC 0x03 in the pqap hook? What am I missing here? Maybe you misunderstood my comment? The following is the only code I suggested you move:

+ fc = vcpu->run->s.regs.gprs[0] >> 24;
+ if (fc != 0x03)
+ return -EOPNOTSUPP;

What does that have to do with test_kvm_facility() and kvm_s390_inject_program_int()? Please explain.

Quoted 12 lines
Quoted 5 lines

Another option: Provide a way to register a callback per function code; this allows you to still do the check here and extend it later for other function codes (which will probably be indicated by another facility).

I like this option even better.

Regards,
Pierre

#30 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

Quoted 65 lines · Tony Krowiak
Quoted 64 lines · Pierre Morel
Quoted 62 lines · Cornelia Huck
Quoted 44 lines · On Mon, 18 Feb 2019 19:29:10 +0100 Pierre Morel <[email protected]> wrote:
Quoted 34 lines · Tony Krowiak
Quoted 32 lines · Pierre Morel
arch/s390/kvm/priv.c +32 -0
+/*
+ * handle_pqap: Handling pqap interception
+ * @vcpu: the vcpu having issue the pqap instruction
+ *
+ * This callback only handles PQAP/AQIC instruction and
+ * calls a dedicated callback for this instruction if
+ * a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * Do not change the behavior if, return -EOPNOTSUPP if:
+ * - the hook is not used do not change the behavior.
+ * - AP instructions are not available or not available to the guest
+ * - the instruction is not PQAP with function code indicating
+ *   AQIC do not change the previous behavior.
+ *
+ * For PQAP/AQIC instruction, verify privilege and specifications
+ *
+ * return the value returned by the callback.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+    uint8_t fc;
+
+    /* Verify that the hook callback is registered */
+    if (!vcpu->kvm->arch.crypto.pqap_hook)
+        return -EOPNOTSUPP;
+    /* Verify that the AP instruction are available */
+    if (!ap_instructions_available())
+        return -EOPNOTSUPP;
+    /* Verify that the guest is allowed to use AP instructions */
+    if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+        return -EOPNOTSUPP;
Quoted 8 lines
Quoted 4 lines

+    /* Verify that the function code is AQIC */
+    fc = vcpu->run->s.regs.gprs[0] >> 24;
+    if (fc != 0x03)
+        return -EOPNOTSUPP;

This does not belong here. Function code 3 is one of 7 function codes that can be sent with the PQAP instruction. This belongs in the PQAP hook code.

Quoted 8 lines

On one hand, effectively I would prefer to put the code in the VFIO driver code.
On the other hand, doing this would lead to export the code for test_kvm_facility() and kvm_s390_inject_program_int() from the kvm-s390.h

I choose not to export these functions from the KVM code.

Would like opinion from KVM maintainers?

Looking at this (and without access to the specification...), I think the check for problem state makes sense in here (if this applies to all PQAP functions equally, which seems likely). The check for the facility makes more sense in the handler. You can probably still inject the specification exception here if you use a clever return code.

Quoted 5 lines
Quoted 1 line

If there is no objection on exporting the KVM functions... I can do this.

I do not understand why you would have to export KVM functions to place the check for FC 0x03 in the pqap hook? What am I missing here? Maybe you misunderstood my comment?

No I did not but in between I discovered an error in the handling of the interception of PQAP/AQIC.

QEMU and KVM can both accept PQAP/AQIC even if the vfio_ap driver is not loaded.
However now that the guest officially get the PQAP/AQIC instruction we need to handle the specification and operation exceptions inside KVM _before_ testing and even calling the driver hook.

I will make the changes in the next iteration.

Regards,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
maintainer
#31 lore raw

Re: [PATCH v3 2/9] s390: ap: kvm: setting a hook for PQAP instructions

In reply to Pierre Morel
Quoted 57 lines · Pierre Morel
Quoted 56 lines · Cornelia Huck
Quoted 52 lines · On Mon, 18 Feb 2019 19:29:10 +0100 Pierre Morel <[email protected]> wrote:
Quoted 34 lines · Tony Krowiak
Quoted 32 lines · Pierre Morel
arch/s390/kvm/priv.c +32 -0
+/*
+ * handle_pqap: Handling pqap interception
+ * @vcpu: the vcpu having issue the pqap instruction
+ *
+ * This callback only handles PQAP/AQIC instruction and
+ * calls a dedicated callback for this instruction if
+ * a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * Do not change the behavior if, return -EOPNOTSUPP if:
+ * - the hook is not used do not change the behavior.
+ * - AP instructions are not available or not available to the guest
+ * - the instruction is not PQAP with function code indicating
+ *   AQIC do not change the previous behavior.
+ *
+ * For PQAP/AQIC instruction, verify privilege and specifications
+ *
+ * return the value returned by the callback.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+    uint8_t fc;
+
+    /* Verify that the hook callback is registered */
+    if (!vcpu->kvm->arch.crypto.pqap_hook)
+        return -EOPNOTSUPP;
+    /* Verify that the AP instruction are available */
+    if (!ap_instructions_available())
+        return -EOPNOTSUPP;
+    /* Verify that the guest is allowed to use AP instructions */
+    if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+        return -EOPNOTSUPP;
Quoted 8 lines
Quoted 4 lines

+    /* Verify that the function code is AQIC */
+    fc = vcpu->run->s.regs.gprs[0] >> 24;
+    if (fc != 0x03)
+        return -EOPNOTSUPP;

This does not belong here. Function code 3 is one of 7 function codes that can be sent with the PQAP instruction. This belongs in the PQAP hook code.

On one hand, effectively I would prefer to put the code in the VFIO driver code.
On the other hand, doing this would lead to export the code for test_kvm_facility() and kvm_s390_inject_program_int() from the kvm-s390.h

I choose not to export these functions from the KVM code.

Would like opinion from KVM maintainers?

Quoted 8 lines
Quoted 6 lines

Looking at this (and without access to the specification...), I think the check for problem state makes sense in here (if this applies to all PQAP functions equally, which seems likely). The check for the facility makes more sense in the handler. You can probably still inject the specification exception here if you use a clever return code.

If there is no objection on exporting the KVM functions... I can do this.

I think I understand where you are coming from. In looking back at the original patch, I see there are checks using the test_kvm_facility and kvm_s390_inject_program_int functions placed after your check for fc != 0x03. You clearly misunderstood what I was asking you to do. I was suggesting that ONLY the check for 'fc != 0x03' be done in the hook. I was NOT suggesting the instructions following the check for fc != 0x03 be done in the hook, so there is no need to export any KVM functions.

Quoted 12 lines
Quoted 5 lines

Another option: Provide a way to register a callback per function code; this allows you to still do the check here and extend it later for other function codes (which will probably be indicated by another facility).

I like this option even better.

Regards,
Pierre

#32 lore raw

PATCH v3 3/9 s390: ap: new vfio_ap_queue structure

In reply to Pierre Morel

The AP interruptions are assigned on a queue basis and we need some information neloging to the queue to handle interuptions.

We add a new structure vfio_ap_queue, to hold per
queue information useful to handle interruptions.

- apqn: AP queue number (defined here)
- isc : Interrupt subclass (defined later)
- nib : notification information byte (defined later)

The vfio_ap_queue structure is allocated when the vfio_ap_driver is probed and added as driver data to the ap_queue device. It is free on remove.

The structure is linked to the matrix_dev host device.

---
 drivers/s390/crypto/vfio_ap_drv.c     | 23 ++++++++++++++++++++++-
 drivers/s390/crypto/vfio_ap_private.h |  3 +++
 2 files changed, 25 insertions(+), 1 deletion(-)
drivers/s390/crypto/vfio_ap_drv.c +22 -1
index 1fd5fe6..03153e6 100644
@@ -46,14 +46,35 @@ static struct ap_device_id ap_queue_ids[] = {
 
 MODULE_DEVICE_TABLE(vfio_ap, ap_queue_ids);
 
+/**
+ * vfio_ap_queue_dev_probe:
+ *
+ * Allocate a vfio_ap_queue structure and associate it
+ * with the device as driver_data.
+ */
 static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
 {
+	struct vfio_ap_queue *q;
+
+	q = kzalloc(sizeof(*q), GFP_KERNEL);
+	if (!q)
+		return -ENOMEM;
+	dev_set_drvdata(&apdev->device, q);
+	q->apqn = to_ap_queue(&apdev->device)->qid;
 	return 0;
 }
 
+/**
+ * vfio_ap_queue_dev_remove:
+ *
+ * Free the associated vfio_ap_queue structure
+ */
 static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
 {
-	/* Nothing to do yet */
+	struct vfio_ap_queue *q;
+
+	q = dev_get_drvdata(&apdev->device);
+	kfree(q);
 }
 
 static void vfio_ap_matrix_dev_release(struct device *dev)
drivers/s390/crypto/vfio_ap_private.h +3 -0
index 76b7f98..8836f01 100644
@@ -86,4 +86,7 @@ struct ap_matrix_mdev {
 extern int vfio_ap_mdev_register(void);
 extern void vfio_ap_mdev_unregister(void);
 
+struct vfio_ap_queue {
+	int	apqn;
+};
 #endif /* _VFIO_AP_PRIVATE_H_ */
Signature · 1 line
2.7.4
#33 lore raw

Re: [PATCH v3 3/9] s390: ap: new vfio_ap_queue structure

Quoted 2 lines · On Thu, 14 Feb 2019 14:51:03 +0100 Pierre Morel <[email protected]> wrote:

The AP interruptions are assigned on a queue basis and we need some information neloging to the queue

s/neloging/belonging/

Quoted 1 line

to handle interuptions.

s/interuptions/interruptions/

Quoted 7 lines

We add a new structure vfio_ap_queue, to hold per
queue information useful to handle interruptions.

- apqn: AP queue number (defined here)
- isc : Interrupt subclass (defined later)
- nib : notification information byte (defined later)

So, you basically simply want quick access to these? Makes sense.

Quoted 4 lines

The vfio_ap_queue structure is allocated when the vfio_ap_driver is probed and added as driver data to the ap_queue device. It is free on remove.

s/free/freed/

Quoted 2 lines

The structure is linked to the matrix_dev host device.

Hm, I don't quite follow?

Quoted 7 lines
---
 drivers/s390/crypto/vfio_ap_drv.c     | 23 ++++++++++++++++++++++-
 drivers/s390/crypto/vfio_ap_private.h |  3 +++
 2 files changed, 25 insertions(+), 1 deletion(-)

Patch looks reasonable; might make sense to squash it with later patches (still need to read).

#34 lore raw

Re: [PATCH v3 3/9] s390: ap: new vfio_ap_queue structure

Quoted 27 lines · Cornelia Huck
Quoted 2 lines · On Thu, 14 Feb 2019 14:51:03 +0100 Pierre Morel <[email protected]> wrote:

The AP interruptions are assigned on a queue basis and we need some information neloging to the queue

s/neloging/belonging/

Quoted 1 line

to handle interuptions.

s/interuptions/interruptions/

Quoted 7 lines

We add a new structure vfio_ap_queue, to hold per
queue information useful to handle interruptions.

- apqn: AP queue number (defined here)
- isc : Interrupt subclass (defined later)
- nib : notification information byte (defined later)

So, you basically simply want quick access to these? Makes sense.

Quoted 4 lines

The vfio_ap_queue structure is allocated when the vfio_ap_driver is probed and added as driver data to the ap_queue device. It is free on remove.

Quoted 6 lines

s/free/freed/

Quoted 2 lines

The structure is linked to the matrix_dev host device.

Hm, I don't quite follow?

Sorry, do not try to, this has been left from a previous internal version. I will suppress this

Quoted 12 lines
Quoted 8 lines
---
  drivers/s390/crypto/vfio_ap_drv.c     | 23 ++++++++++++++++++++++-
  drivers/s390/crypto/vfio_ap_private.h |  3 +++
  2 files changed, 25 insertions(+), 1 deletion(-)

Patch looks reasonable; might make sense to squash it with later patches (still need to read).

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#35 lore raw

PATCH v3 4/9 s390: ap: tools to find a queue with a specific APQN

In reply to Pierre Morel

We need to find the queue with a specific APQN during the handling of the interception of the PQAP/AQIC instruction.

To handle the AP associated device reference count we keep track of it in the vfio_ap_queue until we put the device.

---
 drivers/s390/crypto/vfio_ap_ops.c     | 54 +++++++++++++++++++++++++++++++++++
 drivers/s390/crypto/vfio_ap_private.h |  1 +
 2 files changed, 55 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +54 -0
index 900b9cf..2a52c9b 100644
@@ -24,6 +24,60 @@
 #define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough"
 #define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
 
+/**
+ * vfio_ap_check_apqn: check if a ap_queue is of a given APQN
+ *
+ * Returns 1 if we have a match.
+ * Otherwise returns 0.
+ */
+static int vfio_ap_check_apqn(struct device *dev, void *data)
+{
+	struct vfio_ap_queue *q = dev_get_drvdata(dev);
+
+	return (q->apqn == *(int *)data);
+}
+
+/**
+ * vfio_ap_get_queue: Retrieve a queue with a specific APQN
+ * @apqn: The queue APQN
+ *
+ * Retrieve a queue with a specific APQN from the list of the
+ * devices associated to the vfio_ap_driver.
+ *
+ * The vfio_ap_queue has been already associated with the device
+ * during the probe.
+ * Store the associated device for reference counting
+ *
+ * Returns the pointer to the associated vfio_ap_queue
+ */
+static  __attribute__((unused))
+	struct vfio_ap_queue *vfio_ap_get_queue(int apqn)
+{
+	struct device *dev;
+	struct vfio_ap_queue *q;
+
+	dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL, &apqn,
+				 vfio_ap_check_apqn);
+	if (!dev)
+		return NULL;
+	q = dev_get_drvdata(dev);
+	q->dev = dev;
+	return q;
+}
+
+/**
+ * vfio_ap_put_queue: lower device reference count for a queue
+ * @q: The queue
+ *
+ * put the associated device
+ *
+ */
+static  __attribute__((unused)) void vfio_ap_put_queue(struct vfio_ap_queue *q)
+{
+	put_device(q->dev);
+	q->dev = NULL;
+}
+
 static void vfio_ap_matrix_init(struct ap_config_info *info,
 				struct ap_matrix *matrix)
 {
drivers/s390/crypto/vfio_ap_private.h +1 -0
index 8836f01..081f0d7 100644
@@ -87,6 +87,7 @@ extern int vfio_ap_mdev_register(void);
 extern void vfio_ap_mdev_unregister(void);
 
 struct vfio_ap_queue {
+	struct device *dev;
 	int	apqn;
 };
 #endif /* _VFIO_AP_PRIVATE_H_ */
Signature · 1 line
2.7.4
#36 lore raw

Re: [PATCH v3 4/9] s390: ap: tools to find a queue with a specific APQN

Quoted 5 lines · On Thu, 14 Feb 2019 14:51:04 +0100 Pierre Morel <[email protected]> wrote:

We need to find the queue with a specific APQN during the handling of the interception of the PQAP/AQIC instruction.

To handle the AP associated device reference count we keep track of it in the vfio_ap_queue until we put the device.

So, the relationship is
(struct ap_device)--(driver_data)-->(struct vfio_ap_queue)--(pointer)-->(struct ap_device) ? IOW, a backlink?

If so, can't you already set that up during probe?

Or am I confused by the various similar devices again? Maybe a diagram would help...

Quoted 32 lines
---
 drivers/s390/crypto/vfio_ap_ops.c     | 54 +++++++++++++++++++++++++++++++++++
 drivers/s390/crypto/vfio_ap_private.h |  1 +
 2 files changed, 55 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +17 -0
index 900b9cf..2a52c9b 100644
@@ -24,6 +24,60 @@
 #define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough"
 #define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
 
+/**
+ * vfio_ap_check_apqn: check if a ap_queue is of a given APQN
+ *
+ * Returns 1 if we have a match.
+ * Otherwise returns 0.
+ */
+static int vfio_ap_check_apqn(struct device *dev, void *data)
+{
+	struct vfio_ap_queue *q = dev_get_drvdata(dev);
+
+	return (q->apqn == *(int *)data);
+}
+
+/**
+ * vfio_ap_get_queue: Retrieve a queue with a specific APQN
+ * @apqn: The queue APQN
+ *

drivers/s390/crypto/vfio_ap_ops.c line 53

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+ * Retrieve a queue with a specific APQN from the list of the
+ * devices associated to the vfio_ap_driver.
+ *
+ * The vfio_ap_queue has been already associated with the device
+ * during the probe.
+ * Store the associated device for reference counting
+ *
+ * Returns the pointer to the associated vfio_ap_queue
+ */
+static  __attribute__((unused))

Eww. Can you get rid of that by reordering or squashing patches?

Quoted 42 lines
drivers/s390/crypto/vfio_ap_ops.c +27 -0
+	struct vfio_ap_queue *vfio_ap_get_queue(int apqn)
+{
+	struct device *dev;
+	struct vfio_ap_queue *q;
+
+	dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL, &apqn,
+				 vfio_ap_check_apqn);
+	if (!dev)
+		return NULL;
+	q = dev_get_drvdata(dev);
+	q->dev = dev;
+	return q;
+}
+
+/**
+ * vfio_ap_put_queue: lower device reference count for a queue
+ * @q: The queue
+ *
+ * put the associated device
+ *
+ */
+static  __attribute__((unused)) void vfio_ap_put_queue(struct vfio_ap_queue *q)
+{
+	put_device(q->dev);
+	q->dev = NULL;
+}
+
 static void vfio_ap_matrix_init(struct ap_config_info *info,
 				struct ap_matrix *matrix)
 {
drivers/s390/crypto/vfio_ap_private.h +1 -0
index 8836f01..081f0d7 100644
@@ -87,6 +87,7 @@ extern int vfio_ap_mdev_register(void);
 extern void vfio_ap_mdev_unregister(void);
 
 struct vfio_ap_queue {
+	struct device *dev;
 	int	apqn;
 };
 #endif /* _VFIO_AP_PRIVATE_H_ */
#37 lore raw

Re: [PATCH v3 4/9] s390: ap: tools to find a queue with a specific APQN

Quoted 6 lines · Cornelia Huck
Quoted 3 lines · On Thu, 14 Feb 2019 14:51:04 +0100 Pierre Morel <[email protected]> wrote:

We need to find the queue with a specific APQN during the handling of the interception of the PQAP/AQIC instruction.

Quoted 8 lines
Quoted 2 lines

To handle the AP associated device reference count we keep track of it in the vfio_ap_queue until we put the device.

So, the relationship is
(struct ap_device)--(driver_data)-->(struct vfio_ap_queue)--(pointer)-->(struct ap_device) ? IOW, a backlink?

If so, can't you already set that up during probe?

Will do.

Quoted 3 lines

Or am I confused by the various similar devices again? Maybe a diagram would help...

No you are right.

Quoted 37 lines
Quoted 37 lines
---
  drivers/s390/crypto/vfio_ap_ops.c     | 54 +++++++++++++++++++++++++++++++++++
  drivers/s390/crypto/vfio_ap_private.h |  1 +
  2 files changed, 55 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +21 -0
index 900b9cf..2a52c9b 100644
@@ -24,6 +24,60 @@
  #define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough"
  #define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
 
+/**
+ * vfio_ap_check_apqn: check if a ap_queue is of a given APQN
+ *
+ * Returns 1 if we have a match.
+ * Otherwise returns 0.
+ */
+static int vfio_ap_check_apqn(struct device *dev, void *data)
+{
+	struct vfio_ap_queue *q = dev_get_drvdata(dev);
+
+	return (q->apqn == *(int *)data);
+}
+
+/**
+ * vfio_ap_get_queue: Retrieve a queue with a specific APQN
+ * @apqn: The queue APQN
+ *
+ * Retrieve a queue with a specific APQN from the list of the
+ * devices associated to the vfio_ap_driver.
+ *
+ * The vfio_ap_queue has been already associated with the device
Quoted 8 lines

drivers/s390/crypto/vfio_ap_ops.c line 53

Quoted 6 lines
drivers/s390/crypto/vfio_ap_ops.c +6 -0
+ * during the probe.
+ * Store the associated device for reference counting
+ *
+ * Returns the pointer to the associated vfio_ap_queue
+ */
+static  __attribute__((unused))

Eww. Can you get rid of that by reordering or squashing patches?

I did this to avoid posting a very big patch.
I will of course squash 4 and 5 with patch 6, when the two patches 4 and 5 are reviewed.

If you think it brings more clarity to squash all for the next iteration I will do.

Regards,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#38 lore raw

Re: [PATCH v3 4/9] s390: ap: tools to find a queue with a specific APQN

Quoted 16 lines · On Fri, 15 Feb 2019 11:10:43 +0100 Pierre Morel <[email protected]> wrote:
Quoted 6 lines · Cornelia Huck
Quoted 3 lines · On Thu, 14 Feb 2019 14:51:04 +0100 Pierre Morel <[email protected]> wrote:

We need to find the queue with a specific APQN during the handling of the interception of the PQAP/AQIC instruction.

Quoted 8 lines
Quoted 2 lines

To handle the AP associated device reference count we keep track of it in the vfio_ap_queue until we put the device.

So, the relationship is
(struct ap_device)--(driver_data)-->(struct vfio_ap_queue)--(pointer)-->(struct ap_device) ? IOW, a backlink?

If so, can't you already set that up during probe?

Quoted 7 lines

Will do.

Quoted 3 lines

Or am I confused by the various similar devices again? Maybe a diagram would help...

No you are right.

Good, I was fearing that I was more confused than normal for Fridays ;)

Quoted 48 lines
Quoted 39 lines
Quoted 39 lines
---
  drivers/s390/crypto/vfio_ap_ops.c     | 54 +++++++++++++++++++++++++++++++++++
  drivers/s390/crypto/vfio_ap_private.h |  1 +
  2 files changed, 55 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +21 -0
index 900b9cf..2a52c9b 100644
@@ -24,6 +24,60 @@
  #define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough"
  #define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
 
+/**
+ * vfio_ap_check_apqn: check if a ap_queue is of a given APQN
+ *
+ * Returns 1 if we have a match.
+ * Otherwise returns 0.
+ */
+static int vfio_ap_check_apqn(struct device *dev, void *data)
+{
+	struct vfio_ap_queue *q = dev_get_drvdata(dev);
+
+	return (q->apqn == *(int *)data);
+}
+
+/**
+ * vfio_ap_get_queue: Retrieve a queue with a specific APQN
+ * @apqn: The queue APQN
+ *
+ * Retrieve a queue with a specific APQN from the list of the
+ * devices associated to the vfio_ap_driver.
+ *
+ * The vfio_ap_queue has been already associated with the device
Quoted 8 lines

drivers/s390/crypto/vfio_ap_ops.c line 53

Quoted 6 lines
drivers/s390/crypto/vfio_ap_ops.c +6 -0
+ * during the probe.
+ * Store the associated device for reference counting
+ *
+ * Returns the pointer to the associated vfio_ap_queue
+ */
+static  __attribute__((unused))  

Eww. Can you get rid of that by reordering or squashing patches?

Quoted 6 lines

I did this to avoid posting a very big patch.
I will of course squash 4 and 5 with patch 6, when the two patches 4 and 5 are reviewed.

If you think it brings more clarity to squash all for the next iteration I will do.

Let's just see what the patches look like in the end. If a squashed patch is not too unwieldy, I'd prefer that over those unused annotations, though.

Hoping for review from others as well ;)

maintainer
#39 lore raw

Re: [PATCH v3 4/9] s390: ap: tools to find a queue with a specific APQN

In reply to Pierre Morel
Quoted 38 lines · Pierre Morel

We need to find the queue with a specific APQN during the handling of the interception of the PQAP/AQIC instruction.

To handle the AP associated device reference count we keep track of it in the vfio_ap_queue until we put the device.

---
  drivers/s390/crypto/vfio_ap_ops.c     | 54 +++++++++++++++++++++++++++++++++++
  drivers/s390/crypto/vfio_ap_private.h |  1 +
  2 files changed, 55 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +18 -0
index 900b9cf..2a52c9b 100644
@@ -24,6 +24,60 @@
  #define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough"
  #define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
 
+/**
+ * vfio_ap_check_apqn: check if a ap_queue is of a given APQN
+ *
+ * Returns 1 if we have a match.
+ * Otherwise returns 0.
+ */
+static int vfio_ap_check_apqn(struct device *dev, void *data)
+{
+	struct vfio_ap_queue *q = dev_get_drvdata(dev);
+
+	return (q->apqn == *(int *)data);
+}
+
+/**
+ * vfio_ap_get_queue: Retrieve a queue with a specific APQN
+ * @apqn: The queue APQN
+ *
+ * Retrieve a queue with a specific APQN from the list of the

drivers/s390/crypto/vfio_ap_ops.c line 54

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+ * devices associated to the vfio_ap_driver.
+ *
+ * The vfio_ap_queue has been already associated with the device
+ * during the probe.
+ * Store the associated device for reference counting
+ *
+ * Returns the pointer to the associated vfio_ap_queue
+ */
+static  __attribute__((unused))
+	struct vfio_ap_queue *vfio_ap_get_queue(int apqn)

I think you should change this signature for the reasons I stated below:

struct device *vfio_ap_get_queue_dev(int apqn)

drivers/s390/crypto/vfio_ap_ops.c line 64

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+{
+	struct device *dev;
+	struct vfio_ap_queue *q;
+
+	dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL, &apqn,
+				 vfio_ap_check_apqn);
+	if (!dev)
+		return NULL;
+	q = dev_get_drvdata(dev);
+	q->dev = dev;

Why store the device with the vfio_ap_queue object? Why not just return the device. The caller can get the vfio_ap_queue from the device's driver data. It seems the only reason for the 'dev' field is to temporarily hold a ref to the device so it can be put later. Why not just put the device.

Quoted 5 lines
drivers/s390/crypto/vfio_ap_ops.c +5 -0
+	return q;
+}
+
+/**
+ * vfio_ap_put_queue: lower device reference count for a queue

drivers/s390/crypto/vfio_ap_ops.c line 79

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+ * @q: The queue
+ *
+ * put the associated device
+ *
+ */
+static  __attribute__((unused)) void vfio_ap_put_queue(struct vfio_ap_queue *q)
+{
+	put_device(q->dev);
+	q->dev = NULL;
+}

I would get rid of this function. If you take my suggestion above, you can just call the put_device() directly. There will be no need for this superfluous 'dev' field.

drivers/s390/crypto/vfio_ap_private.h extern int vfio_ap_mdev_register(void); · line 90

Quoted 13 lines
drivers/s390/crypto/vfio_ap_ops.c +1 -0
+
  static void vfio_ap_matrix_init(struct ap_config_info *info,
  				struct ap_matrix *matrix)
  {
drivers/s390/crypto/vfio_ap_private.h +1 -0
index 8836f01..081f0d7 100644
@@ -87,6 +87,7 @@ extern int vfio_ap_mdev_register(void);
  extern void vfio_ap_mdev_unregister(void);
 
  struct vfio_ap_queue {
+	struct device *dev;

No need for this as per my comments above.

Quoted 4 lines
drivers/s390/crypto/vfio_ap_private.h +0 -0
  	int	apqn;
  };
  #endif /* _VFIO_AP_PRIVATE_H_ */
#40 lore raw

Re: [PATCH v3 4/9] s390: ap: tools to find a queue with a specific APQN

Quoted 34 lines · On Fri, 15 Feb 2019 17:13:21 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 17 lines · Pierre Morel

We need to find the queue with a specific APQN during the handling of the interception of the PQAP/AQIC instruction.

To handle the AP associated device reference count we keep track of it in the vfio_ap_queue until we put the device.

---
  drivers/s390/crypto/vfio_ap_ops.c     | 54 +++++++++++++++++++++++++++++++++++
  drivers/s390/crypto/vfio_ap_private.h |  1 +
  2 files changed, 55 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +5 -0
+/**
+ * vfio_ap_get_queue: Retrieve a queue with a specific APQN
+ * @apqn: The queue APQN
+ *
+ * Retrieve a queue with a specific APQN from the list of the

drivers/s390/crypto/vfio_ap_ops.c line 54

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+ * devices associated to the vfio_ap_driver.
+ *
+ * The vfio_ap_queue has been already associated with the device
+ * during the probe.
+ * Store the associated device for reference counting
+ *
+ * Returns the pointer to the associated vfio_ap_queue
+ */
+static  __attribute__((unused))
+	struct vfio_ap_queue *vfio_ap_get_queue(int apqn)  

I think you should change this signature for the reasons I stated below:

struct device *vfio_ap_get_queue_dev(int apqn)

Quoted 16 lines

drivers/s390/crypto/vfio_ap_ops.c line 64

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+{
+	struct device *dev;
+	struct vfio_ap_queue *q;
+
+	dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL, &apqn,
+				 vfio_ap_check_apqn);
+	if (!dev)
+		return NULL;
+	q = dev_get_drvdata(dev);
+	q->dev = dev;  

Why store the device with the vfio_ap_queue object? Why not just return the device. The caller can get the vfio_ap_queue from the device's driver data. It seems the only reason for the 'dev' field is to temporarily hold a ref to the device so it can be put later. Why not just put the device.

Having looked at the remainder of the patches, I tend to agree that we don't really need the backlink; we walk the driver's list of devices in any case IIUC.

We *might* want a mechanism to grab the queue quickly (i.e. without walking the list) if there's anything performance sensitive in there; but from the patch descriptions, I don't think anything is done in a hot path, so it should be fine.

#41 lore raw

Re: [PATCH v3 4/9] s390: ap: tools to find a queue with a specific APQN

Quoted 54 lines · Cornelia Huck
Quoted 34 lines · On Fri, 15 Feb 2019 17:13:21 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 17 lines · Pierre Morel

We need to find the queue with a specific APQN during the handling of the interception of the PQAP/AQIC instruction.

To handle the AP associated device reference count we keep track of it in the vfio_ap_queue until we put the device.

---
   drivers/s390/crypto/vfio_ap_ops.c     | 54 +++++++++++++++++++++++++++++++++++
   drivers/s390/crypto/vfio_ap_private.h |  1 +
   2 files changed, 55 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +5 -0
+/**
+ * vfio_ap_get_queue: Retrieve a queue with a specific APQN
+ * @apqn: The queue APQN
+ *
+ * Retrieve a queue with a specific APQN from the list of the

drivers/s390/crypto/vfio_ap_ops.c line 54

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+ * devices associated to the vfio_ap_driver.
+ *
+ * The vfio_ap_queue has been already associated with the device
+ * during the probe.
+ * Store the associated device for reference counting
+ *
+ * Returns the pointer to the associated vfio_ap_queue
+ */
+static  __attribute__((unused))
+	struct vfio_ap_queue *vfio_ap_get_queue(int apqn)

I think you should change this signature for the reasons I stated below:

struct device *vfio_ap_get_queue_dev(int apqn)

Quoted 16 lines

drivers/s390/crypto/vfio_ap_ops.c line 64

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+{
+	struct device *dev;
+	struct vfio_ap_queue *q;
+
+	dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL, &apqn,
+				 vfio_ap_check_apqn);
+	if (!dev)
+		return NULL;
+	q = dev_get_drvdata(dev);
+	q->dev = dev;

Why store the device with the vfio_ap_queue object? Why not just return the device. The caller can get the vfio_ap_queue from the device's driver data. It seems the only reason for the 'dev' field is to temporarily hold a ref to the device so it can be put later. Why not just put the device.

Quoted 9 lines

Having looked at the remainder of the patches, I tend to agree that we don't really need the backlink; we walk the driver's list of devices in any case IIUC.

We *might* want a mechanism to grab the queue quickly (i.e. without walking the list) if there's anything performance sensitive in there; but from the patch descriptions, I don't think anything is done in a hot path, so it should be fine.

OK you are right, I ll drop it

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
maintainer
#42 lore raw

Re: [PATCH v3 4/9] s390: ap: tools to find a queue with a specific APQN

In reply to Cornelia Huck
Quoted 37 lines · Cornelia Huck
Quoted 34 lines · On Fri, 15 Feb 2019 17:13:21 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 17 lines · Pierre Morel

We need to find the queue with a specific APQN during the handling of the interception of the PQAP/AQIC instruction.

To handle the AP associated device reference count we keep track of it in the vfio_ap_queue until we put the device.

---
   drivers/s390/crypto/vfio_ap_ops.c     | 54 +++++++++++++++++++++++++++++++++++
   drivers/s390/crypto/vfio_ap_private.h |  1 +
   2 files changed, 55 insertions(+)
drivers/s390/crypto/vfio_ap_ops.c +5 -0
+/**
+ * vfio_ap_get_queue: Retrieve a queue with a specific APQN
+ * @apqn: The queue APQN
+ *
+ * Retrieve a queue with a specific APQN from the list of the

drivers/s390/crypto/vfio_ap_ops.c line 54

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+ * devices associated to the vfio_ap_driver.
+ *
+ * The vfio_ap_queue has been already associated with the device
+ * during the probe.
+ * Store the associated device for reference counting
+ *
+ * Returns the pointer to the associated vfio_ap_queue
+ */
+static  __attribute__((unused))
+	struct vfio_ap_queue *vfio_ap_get_queue(int apqn)

I think you should change this signature for the reasons I stated below:

struct device *vfio_ap_get_queue_dev(int apqn)

Quoted 16 lines
Quoted 8 lines
Quoted 8 lines
drivers/s390/crypto/vfio_ap_ops.c +8 -0
+{
+	struct device *dev;
+	struct vfio_ap_queue *q;
+
+	dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL, &apqn,
+				 vfio_ap_check_apqn);
+	if (!dev)
+		return NULL;
Quoted 8 lines

drivers/s390/crypto/vfio_ap_ops.c line 64

Quoted 2 lines
drivers/s390/crypto/vfio_ap_ops.c +2 -0
+	q = dev_get_drvdata(dev);
+	q->dev = dev;

Why store the device with the vfio_ap_queue object? Why not just return the device. The caller can get the vfio_ap_queue from the device's driver data. It seems the only reason for the 'dev' field is to temporarily hold a ref to the device so it can be put later. Why not just put the device.

After thinking about this further, I question whether we even need this function if it is going to return 'struct device *'. In that case, why not just call driver_find_device() when the device is needed? If you want to keep the function, then the function needs only one statement:

	return driver_find_device(...).
Quoted 10 lines

Having looked at the remainder of the patches, I tend to agree that we don't really need the backlink; we walk the driver's list of devices in any case IIUC.

We *might* want a mechanism to grab the queue quickly (i.e. without walking the list) if there's anything performance sensitive in there; but from the patch descriptions, I don't think anything is done in a hot path, so it should be fine.

#43 lore raw

PATCH v3 5/9 s390: ap: tools to associate a queue to a matrix

In reply to Pierre Morel

We need tools to associate a queue and a matrix to be able later to find the matrix associated with the queue for which we got the APQN in the register 1 during a PQAP/AQIC instruction interception.

---
 drivers/s390/crypto/vfio_ap_ops.c     | 66 +++++++++++++++++++++++++++++++++--
 drivers/s390/crypto/vfio_ap_private.h |  1 +
 2 files changed, 64 insertions(+), 3 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +63 -3
index 2a52c9b..1851b24 100644
@@ -50,8 +50,7 @@ static int vfio_ap_check_apqn(struct device *dev, void *data)
  *
  * Returns the pointer to the associated vfio_ap_queue
  */
-static  __attribute__((unused))
-	struct vfio_ap_queue *vfio_ap_get_queue(int apqn)
+static struct vfio_ap_queue *vfio_ap_get_queue(int apqn)
 {
 	struct device *dev;
 	struct vfio_ap_queue *q;
@@ -72,7 +71,7 @@ static  __attribute__((unused))
  * put the associated device
  *
  */
-static  __attribute__((unused)) void vfio_ap_put_queue(struct vfio_ap_queue *q)
+static void vfio_ap_put_queue(struct vfio_ap_queue *q)
 {
 	put_device(q->dev);
 	q->dev = NULL;
@@ -867,6 +866,67 @@ static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi,
 	return -EBUSY;
 }
 
+/**
+ * vfio_ap_dissociate_queues: Dissociate a matrix mediated device to a queue
+ *
+ * Go through all bits in the AQM and APM and dissociate the queue
+ * from the matrix device.
+ *
+ * No return value we are throwing the mediated device anyway.
+ */
+static void vfio_ap_dissociate_queues(struct ap_matrix_mdev *matrix_mdev)
+{
+	unsigned long apid, apqi;
+	struct vfio_ap_queue *q;
+
+	for_each_set_bit_inv(apid, matrix_mdev->matrix.apm,
+			     matrix_mdev->matrix.apm_max + 1) {
+		for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm,
+				     matrix_mdev->matrix.aqm_max + 1) {
+			q = vfio_ap_get_queue(AP_MKQID(apid, apqi));
+			if (q) {
+				vfio_ap_mdev_reset_queue(apid, apqi, 1);
+				q->matrix = NULL;
+				vfio_ap_put_queue(q);
+			} else
+				pr_err("%s: no queue for %02lx.%04lx\n",
+				       __func__, apid, apqi);
+		}
+	}
+}
+
+/**
+ * vfio_ap_associate_queues: Associate a matrix mediated device to a queue
+ *
+ * Go through all bits in the AQM and APM and calculate the APQN, and find
+ * the matching queue to associate with the matrix device.
+ *
+ * In the case a queue could not be found return -ENODEV.
+ * Otherwise return 0.
+ */
+static __attribute__((unused))
+	int vfio_ap_associate_queues(struct ap_matrix_mdev *matrix_mdev)
+{
+	unsigned long apid, apqi;
+	struct vfio_ap_queue *q;
+
+	for_each_set_bit_inv(apid, matrix_mdev->matrix.apm,
+			     matrix_mdev->matrix.apm_max + 1) {
+		for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm,
+				     matrix_mdev->matrix.aqm_max + 1) {
+			q = vfio_ap_get_queue(AP_MKQID(apid, apqi));
+			if (!q)
+				goto error;
+			q->matrix = matrix_mdev;
+			vfio_ap_put_queue(q);
+		}
+	}
+	return 0;
+error:
+	pr_err("%s: no queue for %02lx.%04lx\n", __func__, apid, apqi);
+	vfio_ap_dissociate_queues(matrix_mdev);
+	return -ENODEV;
+}
 static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev)
 {
 	int ret;
drivers/s390/crypto/vfio_ap_private.h +1 -0
index 081f0d7..10bc8b5 100644
@@ -89,5 +89,6 @@ extern void vfio_ap_mdev_unregister(void);
 struct vfio_ap_queue {
 	struct device *dev;
 	int	apqn;
+	struct ap_matrix_mdev *matrix;
 };
 #endif /* _VFIO_AP_PRIVATE_H_ */
Signature · 1 line
2.7.4
maintainer
#44 lore raw

Re: [PATCH v3 5/9] s390: ap: tools to associate a queue to a matrix

Quoted 16 lines · Pierre Morel

We need tools to associate a queue and a matrix to be able later to find the matrix associated with the queue for which we got the APQN in the register 1 during a PQAP/AQIC instruction interception.

---
  drivers/s390/crypto/vfio_ap_ops.c     | 66 +++++++++++++++++++++++++++++++++--
  drivers/s390/crypto/vfio_ap_private.h |  1 +
  2 files changed, 64 insertions(+), 3 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +0 -0
index 2a52c9b..1851b24 100644

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_check_apqn(struct device *dev, void *data) · line 54

Quoted 5 lines
drivers/s390/crypto/vfio_ap_ops.c +0 -2
@@ -50,8 +50,7 @@ static int vfio_ap_check_apqn(struct device *dev, void *data)
   *
   * Returns the pointer to the associated vfio_ap_queue
   */
-static  __attribute__((unused))
-	struct vfio_ap_queue *vfio_ap_get_queue(int apqn)

I don't like this, it indicates to me that this and the previous patch should have been squashed together. I realize your intent was to make the patches smaller, but I don't think this makes it any easier to review them. In fact, it makes it harder IMHO, because you have to flip back and forth between patches to fully comprehend the usage.

drivers/s390/crypto/vfio_ap_ops.c static __attribute__((unused)) · line 75

Quoted 9 lines
drivers/s390/crypto/vfio_ap_ops.c +1 -1
+static struct vfio_ap_queue *vfio_ap_get_queue(int apqn)
  {
  	struct device *dev;
  	struct vfio_ap_queue *q;
@@ -72,7 +71,7 @@ static  __attribute__((unused))
   * put the associated device
   *
   */
-static  __attribute__((unused)) void vfio_ap_put_queue(struct vfio_ap_queue *q)

Ditto for this.

Quoted 9 lines
drivers/s390/crypto/vfio_ap_ops.c +2 -0
+static void vfio_ap_put_queue(struct vfio_ap_queue *q)
  {
  	put_device(q->dev);
  	q->dev = NULL;
@@ -867,6 +866,67 @@ static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi,
  	return -EBUSY;
  }
 
+/**

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 879

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+ * vfio_ap_dissociate_queues: Dissociate a matrix mediated device to a queue
+ *
+ * Go through all bits in the AQM and APM and dissociate the queue
+ * from the matrix device.
+ *
+ * No return value we are throwing the mediated device anyway.
+ */
+static void vfio_ap_dissociate_queues(struct ap_matrix_mdev *matrix_mdev)
+{
+	unsigned long apid, apqi;

The changes I recommend here are based on the comments in my response to patch 4.

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 880

Quoted 1 line
drivers/s390/crypto/vfio_ap_ops.c +1 -0
+	struct vfio_ap_queue *q;

Add this:

	struct device *qdev;

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 886

Quoted 6 lines
drivers/s390/crypto/vfio_ap_ops.c +6 -0
+
+	for_each_set_bit_inv(apid, matrix_mdev->matrix.apm,
+			     matrix_mdev->matrix.apm_max + 1) {
+		for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm,
+				     matrix_mdev->matrix.aqm_max + 1) {
+			q = vfio_ap_get_queue(AP_MKQID(apid, apqi));

Replace with:

	qdev = vfio_ap_get_queue_dev(AP_MKQID(apid, apqi);

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 887

Quoted 1 line
drivers/s390/crypto/vfio_ap_ops.c +1 -0
+			if (q) {

Replace with:

	if (qdev) {

Add this:

	q = dev_get_drvdata(qdev);

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 890

Quoted 3 lines
drivers/s390/crypto/vfio_ap_ops.c +3 -0
+				vfio_ap_mdev_reset_queue(apid, apqi, 1);
+				q->matrix = NULL;
+				vfio_ap_put_queue(q);

Replace with:
put_device(qdev)

Quoted 7 lines
drivers/s390/crypto/vfio_ap_ops.c +7 -0
+			} else
+				pr_err("%s: no queue for %02lx.%04lx\n",
+				       __func__, apid, apqi);
+		}
+	}
+}
+

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 907

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+/**
+ * vfio_ap_associate_queues: Associate a matrix mediated device to a queue
+ *
+ * Go through all bits in the AQM and APM and calculate the APQN, and find
+ * the matching queue to associate with the matrix device.
+ *
+ * In the case a queue could not be found return -ENODEV.
+ * Otherwise return 0.
+ */
+static __attribute__((unused))

This indicates this patch should be squashed with the patch that introduces this function. Why have a patch that introduces a function that is not used and put and artificially specify an attribute just to keep the compiler from issuing a warning?

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 909

Quoted 2 lines
drivers/s390/crypto/vfio_ap_ops.c +2 -0
+	int vfio_ap_associate_queues(struct ap_matrix_mdev *matrix_mdev)
+{

The same as above, the changes I recommend here are based on the comments in my response to patch 4.

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 911

Quoted 2 lines
drivers/s390/crypto/vfio_ap_ops.c +2 -0
+	unsigned long apid, apqi;
+	struct vfio_ap_queue *q;

Add:

	struct device *qdev;

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 886

Quoted 6 lines
drivers/s390/crypto/vfio_ap_ops.c +6 -0
+
+	for_each_set_bit_inv(apid, matrix_mdev->matrix.apm,
+			     matrix_mdev->matrix.apm_max + 1) {
+		for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm,
+				     matrix_mdev->matrix.aqm_max + 1) {
+			q = vfio_ap_get_queue(AP_MKQID(apid, apqi));

Replace with:

	qdev = vfio_ap_get_queue_dev(AP_MKQID(apid, apqi));

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 918

Quoted 1 line
drivers/s390/crypto/vfio_ap_ops.c +1 -0
+			if (!q)

Replace with:

	if (!qdev)

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 919

Quoted 1 line
drivers/s390/crypto/vfio_ap_ops.c +1 -0
+				goto error;

Add:

	q = dev_get_drvdata(qdev);

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 921

Quoted 2 lines
drivers/s390/crypto/vfio_ap_ops.c +2 -0
+			q->matrix = matrix_mdev;
+			vfio_ap_put_queue(q);

Replace with:

	put_device(qdev);
Quoted 16 lines
drivers/s390/crypto/vfio_ap_ops.c +8 -0
+		}
+	}
+	return 0;
+error:
+	pr_err("%s: no queue for %02lx.%04lx\n", __func__, apid, apqi);
+	vfio_ap_dissociate_queues(matrix_mdev);
+	return -ENODEV;
+}
  static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev)
  {
  	int ret;
drivers/s390/crypto/vfio_ap_private.h +0 -0
index 081f0d7..10bc8b5 100644

drivers/s390/crypto/vfio_ap_private.h extern void vfio_ap_mdev_unregister(void); · line 92

Quoted 4 lines
drivers/s390/crypto/vfio_ap_private.h +1 -0
@@ -89,5 +89,6 @@ extern void vfio_ap_mdev_unregister(void);
  struct vfio_ap_queue {
  	struct device *dev;
  	int	apqn;
+	struct ap_matrix_mdev *matrix;

Can you rename this variable matrix_mdev?
* That is how struct ap_matrix_mdev vars are named everywhere else
* It prevents confusing it with naming of vars for struct ap_matrix.

Quoted 3 lines
drivers/s390/crypto/vfio_ap_private.h +0 -0
  };
  #endif /* _VFIO_AP_PRIVATE_H_ */
#45 lore raw

Re: [PATCH v3 5/9] s390: ap: tools to associate a queue to a matrix

Quoted 117 lines · Tony Krowiak
Quoted 17 lines · Pierre Morel

We need tools to associate a queue and a matrix to be able later to find the matrix associated with the queue for which we got the APQN in the register 1 during a PQAP/AQIC instruction interception.

---
  drivers/s390/crypto/vfio_ap_ops.c     | 66
+++++++++++++++++++++++++++++++++--
  drivers/s390/crypto/vfio_ap_private.h |  1 +

  2 files changed, 64 insertions(+), 3 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +0 -0
index 2a52c9b..1851b24 100644

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_check_apqn(struct device *dev, · line 55

Quoted 6 lines
drivers/s390/crypto/vfio_ap_ops.c +0 -2
@@ -50,8 +50,7 @@ static int vfio_ap_check_apqn(struct device *dev, 
 void *data)
    *
    * Returns the pointer to the associated vfio_ap_queue
    */
-static  __attribute__((unused))
-    struct vfio_ap_queue *vfio_ap_get_queue(int apqn)

I don't like this, it indicates to me that this and the previous patch should have been squashed together. I realize your intent was to make the patches smaller, but I don't think this makes it any easier to review them. In fact, it makes it harder IMHO, because you have to flip back and forth between patches to fully comprehend the usage.

drivers/s390/crypto/vfio_ap_ops.c static  __attribute__((unused)) · line 74

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +1 -0
+static struct vfio_ap_queue *vfio_ap_get_queue(int apqn)
   {
       struct device *dev;

      struct vfio_ap_queue *q;

drivers/s390/crypto/vfio_ap_ops.c +0 -1
@@ -72,7 +71,7 @@ static  __attribute__((unused))
    * put the associated device
    *
    */
-static  __attribute__((unused)) void vfio_ap_put_queue(struct 
 vfio_ap_queue *q)

Ditto for this.

Quoted 13 lines
drivers/s390/crypto/vfio_ap_ops.c +1 -0
+static void vfio_ap_put_queue(struct vfio_ap_queue *q)
   {
       put_device(q->dev);

      q->dev = NULL;

drivers/s390/crypto/vfio_ap_ops.c +2 -0
@@ -867,6 +866,67 @@ static int vfio_ap_mdev_reset_queue(unsigned int 
 apid, unsigned int apqi,
       return -EBUSY;
   }
+/**
+ * vfio_ap_dissociate_queues: Dissociate a matrix mediated device to 

a queue
+ *
+ * Go through all bits in the AQM and APM and dissociate the queue

Quoted 8 lines

+ * from the matrix device.
+ *
+ * No return value we are throwing the mediated device anyway.
+ */
+static void vfio_ap_dissociate_queues(struct ap_matrix_mdev *matrix_mdev)
+{
+    unsigned long apid, apqi;

The changes I recommend here are based on the comments in my response to patch 4.

Quoted 1 line

+    struct vfio_ap_queue *q;

Add this:

    struct device *qdev;

Quoted 6 lines

+
+    for_each_set_bit_inv(apid, matrix_mdev->matrix.apm, +                 matrix_mdev->matrix.apm_max + 1) { +        for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm, +                     matrix_mdev->matrix.aqm_max + 1) { +            q = vfio_ap_get_queue(AP_MKQID(apid, apqi));

Replace with:
    qdev = vfio_ap_get_queue_dev(AP_MKQID(apid, apqi);

Quoted 1 line

+            if (q) {

Replace with:
    if (qdev) {

Add this:
    q = dev_get_drvdata(qdev);

Quoted 3 lines

+                vfio_ap_mdev_reset_queue(apid, apqi, 1); +                q->matrix = NULL;
+                vfio_ap_put_queue(q);

Replace with:
    put_device(qdev)

Quoted 16 lines

+            } else
+                pr_err("%s: no queue for %02lx.%04lx\n", +                       __func__, apid, apqi);
+        }
+    }

drivers/s390/crypto/vfio_ap_ops.c +4 -0
+}
+
+/**
+ * vfio_ap_associate_queues: Associate a matrix mediated device to a 

queue
+ *
+ * Go through all bits in the AQM and APM and calculate the APQN, and find
+ * the matching queue to associate with the matrix device.
+ *
+ * In the case a queue could not be found return -ENODEV.

Quoted 8 lines
Quoted 3 lines

+ * Otherwise return 0.
+ */
+static __attribute__((unused))

This indicates this patch should be squashed with the patch that introduces this function. Why have a patch that introduces a function that is not used and put and artificially specify an attribute just to keep the compiler from issuing a warning?

Seems to be a majority for this so... will do.

Quoted 7 lines
Quoted 3 lines

+    int vfio_ap_associate_queues(struct ap_matrix_mdev *matrix_mdev) +{

The same as above, the changes I recommend here are based on the comments in my response to patch 4.

... will do

Quoted 12 lines
Quoted 12 lines

+    pr_err("%s: no queue for %02lx.%04lx\n", __func__, apid, apqi); +    vfio_ap_dissociate_queues(matrix_mdev);
+    return -ENODEV;
+}
  static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev) {
      int ret;

drivers/s390/crypto/vfio_ap_private.h +0 -0
index 081f0d7..10bc8b5 100644
@@ -89,5 +89,6 @@ extern void vfio_ap_mdev_unregister(void);
Quoted 8 lines

drivers/s390/crypto/vfio_ap_private.h extern void vfio_ap_mdev_unregister(void); · line 92

Quoted 4 lines
drivers/s390/crypto/vfio_ap_private.h +1 -0
   struct vfio_ap_queue {
       struct device *dev;
       int    apqn;
+    struct ap_matrix_mdev *matrix;

Can you rename this variable matrix_mdev?
* That is how struct ap_matrix_mdev vars are named everywhere else
* It prevents confusing it with naming of vars for struct ap_matrix.

Sorry, I did this but it seems to have been forgotten in a rebase. Will do.

Quoted 5 lines
Quoted 4 lines
drivers/s390/crypto/vfio_ap_private.h +0 -0
   };
   #endif /* _VFIO_AP_PRIVATE_H_ */
Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#46 lore raw

PATCH v3 6/9 vfio: ap: register IOMMU VFIO notifier

In reply to Pierre Morel

To be able to use the VFIO interface to facilitate the mediated device memory pining/unpining we need to register a notifier for IOMMU.

---
 drivers/s390/crypto/vfio_ap_ops.c     | 64 +++++++++++++++++++++++++++++++----
 drivers/s390/crypto/vfio_ap_private.h |  2 ++
 2 files changed, 60 insertions(+), 6 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +58 -6
index 1851b24..6eddc2c 100644
@@ -781,6 +781,36 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = {
 };
 
 /**
+ * vfio_ap_mdev_iommu_notifier: IOMMU notifier callback
+ *
+ * @nb: The notifier block
+ * @action: Action to be taken (VFIO_IOMMU_NOTIFY_DMA_UNMAP)
+ * @data: the specific unmap structure for vfio_iommu_type1
+ *
+ * Unpins the guest IOVA. (The NIB guest address we pinned before).
+ * Return NOTIFY_OK after unpining on a UNMAP request.
+ * otherwise, returns NOTIFY_DONE .
+ */
+static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
+				       unsigned long action, void *data)
+{
+	struct ap_matrix_mdev *matrix_mdev;
+
+	matrix_mdev = container_of(nb, struct ap_matrix_mdev, iommu_notifier);
+
+	if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
+		struct vfio_iommu_type1_dma_unmap *unmap = data;
+		unsigned long g_pfn = unmap->iova >> PAGE_SHIFT;
+
+		vfio_unpin_pages(mdev_dev(matrix_mdev->mdev), &g_pfn, 1);
+		return NOTIFY_OK;
+	}
+
+	return NOTIFY_DONE;
+}
+
+
+/**
  * vfio_ap_mdev_set_kvm
  *
  * @matrix_mdev: a mediated matrix device
@@ -904,8 +934,7 @@ static void vfio_ap_dissociate_queues(struct ap_matrix_mdev *matrix_mdev)
  * In the case a queue could not be found return -ENODEV.
  * Otherwise return 0.
  */
-static __attribute__((unused))
-	int vfio_ap_associate_queues(struct ap_matrix_mdev *matrix_mdev)
+static int vfio_ap_associate_queues(struct ap_matrix_mdev *matrix_mdev)
 {
 	unsigned long apid, apqi;
 	struct vfio_ap_queue *q;
@@ -967,12 +996,32 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
 
 	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
 				     &events, &matrix_mdev->group_notifier);
-	if (ret) {
-		module_put(THIS_MODULE);
-		return ret;
-	}
+	if (ret)
+		goto err_group;
+
+	matrix_mdev->iommu_notifier.notifier_call = vfio_ap_mdev_iommu_notifier;
+	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
+
+	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+				     &events, &matrix_mdev->iommu_notifier);
+	if (ret)
+		goto err_iommu;
+
+	ret = vfio_ap_associate_queues(matrix_mdev);
+	if (ret)
+		goto err_associate;
 
 	return 0;
+
+err_associate:
+	vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+				 &matrix_mdev->iommu_notifier);
+err_iommu:
+	vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
+				 &matrix_mdev->group_notifier);
+err_group:
+	module_put(THIS_MODULE);
+	return ret;
 }
 
 static void vfio_ap_mdev_release(struct mdev_device *mdev)
@@ -985,6 +1034,9 @@ static void vfio_ap_mdev_release(struct mdev_device *mdev)
 	vfio_ap_mdev_reset_queues(mdev);
 	vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
 				 &matrix_mdev->group_notifier);
+	vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+				 &matrix_mdev->iommu_notifier);
+	vfio_ap_dissociate_queues(matrix_mdev);
 	matrix_mdev->kvm = NULL;
 	module_put(THIS_MODULE);
 }
drivers/s390/crypto/vfio_ap_private.h +2 -0
index 10bc8b5..2781720 100644
@@ -80,7 +80,9 @@ struct ap_matrix_mdev {
 	struct list_head node;
 	struct ap_matrix matrix;
 	struct notifier_block group_notifier;
+	struct notifier_block iommu_notifier;
 	struct kvm *kvm;
+	struct mdev_device *mdev;
 };
 
 extern int vfio_ap_mdev_register(void);
Signature · 1 line
2.7.4
maintainer
#47 lore raw

Re: [PATCH v3 6/9] vfio: ap: register IOMMU VFIO notifier

Quoted 52 lines · Pierre Morel

To be able to use the VFIO interface to facilitate the mediated device memory pining/unpining we need to register a notifier for IOMMU.

---
  drivers/s390/crypto/vfio_ap_ops.c     | 64 +++++++++++++++++++++++++++++++----
  drivers/s390/crypto/vfio_ap_private.h |  2 ++
  2 files changed, 60 insertions(+), 6 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +30 -0
index 1851b24..6eddc2c 100644
@@ -781,6 +781,36 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = {
  };
 
  /**
+ * vfio_ap_mdev_iommu_notifier: IOMMU notifier callback
+ *
+ * @nb: The notifier block
+ * @action: Action to be taken (VFIO_IOMMU_NOTIFY_DMA_UNMAP)
+ * @data: the specific unmap structure for vfio_iommu_type1
+ *
+ * Unpins the guest IOVA. (The NIB guest address we pinned before).
+ * Return NOTIFY_OK after unpining on a UNMAP request.
+ * otherwise, returns NOTIFY_DONE .
+ */
+static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
+				       unsigned long action, void *data)
+{
+	struct ap_matrix_mdev *matrix_mdev;
+
+	matrix_mdev = container_of(nb, struct ap_matrix_mdev, iommu_notifier);
+
+	if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
+		struct vfio_iommu_type1_dma_unmap *unmap = data;
+		unsigned long g_pfn = unmap->iova >> PAGE_SHIFT;
+
+		vfio_unpin_pages(mdev_dev(matrix_mdev->mdev), &g_pfn, 1);
+		return NOTIFY_OK;
+	}
+
+	return NOTIFY_DONE;
+}
+
+
+/**
   * vfio_ap_mdev_set_kvm
   *
   * @matrix_mdev: a mediated matrix device

drivers/s390/crypto/vfio_ap_ops.c static void vfio_ap_dissociate_queues(struct ap_matrix_mdev *matrix_mdev) · line 937

Quoted 6 lines
drivers/s390/crypto/vfio_ap_ops.c +1 -2
@@ -904,8 +934,7 @@ static void vfio_ap_dissociate_queues(struct ap_matrix_mdev *matrix_mdev)
   * In the case a queue could not be found return -ENODEV.
   * Otherwise return 0.
   */
-static __attribute__((unused))
-	int vfio_ap_associate_queues(struct ap_matrix_mdev *matrix_mdev)
+static int vfio_ap_associate_queues(struct ap_matrix_mdev *matrix_mdev)

Maybe this function should be introduced in this patch instead?

Quoted 15 lines
drivers/s390/crypto/vfio_ap_ops.c +4 -4
  {
  	unsigned long apid, apqi;
  	struct vfio_ap_queue *q;
@@ -967,12 +996,32 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
 
  	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
  				     &events, &matrix_mdev->group_notifier);
-	if (ret) {
-		module_put(THIS_MODULE);
-		return ret;
-	}
+	if (ret)
+		goto err_group;
+
+	matrix_mdev->iommu_notifier.notifier_call = vfio_ap_mdev_iommu_notifier;

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_open(struct mdev_device *mdev) · line 1012

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
+
+	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+				     &events, &matrix_mdev->iommu_notifier);
+	if (ret)
+		goto err_iommu;
+
+	ret = vfio_ap_associate_queues(matrix_mdev);
+	if (ret)
+		goto err_associate;

I think the matrix_mdev should be associated with queues when an assignment of an adapter or domain is made to the mdev device via its sysfs interfaces. I say this because assigning an adapter or domain to
an mdev device effectively grants ownership of any additional AP queues added to the mdev device's AP matrix as a result of the assignment. It only makes sense to assign ownership to the vfio_ap_queue objects
representing the queues at that time. If an adapter or domain is
dynamically assigned while a guest is using the affected queues, then
the associations will have to be made at that time and this code will
likely go bye bye.

Quoted 16 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
  	return 0;
+
+err_associate:
+	vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+				 &matrix_mdev->iommu_notifier);
+err_iommu:
+	vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
+				 &matrix_mdev->group_notifier);
+err_group:
+	module_put(THIS_MODULE);
+	return ret;
  }
 
  static void vfio_ap_mdev_release(struct mdev_device *mdev)

drivers/s390/crypto/vfio_ap_ops.c static void vfio_ap_mdev_release(struct mdev_device *mdev) · line 1039

Quoted 6 lines
drivers/s390/crypto/vfio_ap_ops.c +3 -0
@@ -985,6 +1034,9 @@ static void vfio_ap_mdev_release(struct mdev_device *mdev)
  	vfio_ap_mdev_reset_queues(mdev);
  	vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
  				 &matrix_mdev->group_notifier);
+	vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+				 &matrix_mdev->iommu_notifier);
+	vfio_ap_dissociate_queues(matrix_mdev);

I think the matrix_mdev should be dissociated from queues when an
adapter or domain is unassigned from the mdev device via its
sysfs interfaces. I say this because unassigning an adapter or domain from an mdev device effectively takes away ownership of any AP queues removed from the mdev device's AP matrix as a result of the
unassignment. It only makes sense to remove ownership from the
vfio_ap_queue objects representing the queues at that time. This will
become necessary for the forthcoming dynamic configuration patches.
If an adapter or domain is dynamically unassigned while a guest is
using the affected queues, then the dissociation will have to be made
at that time and this code will likely go bye bye.

Quoted 18 lines
drivers/s390/crypto/vfio_ap_ops.c +0 -0
  	matrix_mdev->kvm = NULL;
  	module_put(THIS_MODULE);
  }
drivers/s390/crypto/vfio_ap_private.h +2 -0
index 10bc8b5..2781720 100644
@@ -80,7 +80,9 @@ struct ap_matrix_mdev {
  	struct list_head node;
  	struct ap_matrix matrix;
  	struct notifier_block group_notifier;
+	struct notifier_block iommu_notifier;
  	struct kvm *kvm;
+	struct mdev_device *mdev;
  };
 
  extern int vfio_ap_mdev_register(void);
maintainer
#48 lore raw

Re: [PATCH v3 6/9] vfio: ap: register IOMMU VFIO notifier

Quoted 11 lines · On Fri, 15 Feb 2019 17:55:35 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 10 lines · Pierre Morel

To be able to use the VFIO interface to facilitate the mediated device memory pining/unpining we need to register a notifier for IOMMU.

---
  drivers/s390/crypto/vfio_ap_ops.c     | 64 +++++++++++++++++++++++++++++++----
  drivers/s390/crypto/vfio_ap_private.h |  2 ++
  2 files changed, 60 insertions(+), 6 deletions(-)
Quoted 4 lines

drivers/s390/crypto/vfio_ap_ops.c

Quoted 4 lines
drivers/s390/crypto/vfio_ap_ops.c +0 -0
index 1851b24..6eddc2c 100644

[..]
struct vfio_ap_queue *q;

Quoted 25 lines
Quoted 12 lines
drivers/s390/crypto/vfio_ap_ops.c +4 -4
@@ -967,12 +996,32 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
 
  	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
  				     &events, &matrix_mdev->group_notifier);
-	if (ret) {
-		module_put(THIS_MODULE);
-		return ret;
-	}
+	if (ret)
+		goto err_group;
+
+	matrix_mdev->iommu_notifier.notifier_call = vfio_ap_mdev_iommu_notifier;

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_open(struct mdev_device *mdev) · line 1012

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
+
+	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+				     &events, &matrix_mdev->iommu_notifier);
+	if (ret)
+		goto err_iommu;
+
+	ret = vfio_ap_associate_queues(matrix_mdev);
+	if (ret)
+		goto err_associate;

I think the matrix_mdev should be associated with queues when an assignment of an adapter or domain is made to the mdev device via its

Quoted 9 lines

sysfs interfaces. I say this because assigning an adapter or domain to an mdev device effectively grants ownership of any additional AP queues added to the mdev device's AP matrix as a result of the assignment. It only makes sense to assign ownership to the vfio_ap_queue objects representing the queues at that time. If an adapter or domain is dynamically assigned while a guest is using the affected queues, then the associations will have to be made at that time and this code will likely go bye bye.

Actually, we need the stuff in vfio_ap_queues only if the guest is offered to decides to use AP adaper interrupts. I would prefer to have it around only when needed: as long as we have the nib pinned for any given queue. Is there a reason why not to do so?

Regards,
Halil

[..]

#49 lore raw

Re: [PATCH v3 6/9] vfio: ap: register IOMMU VFIO notifier

Quoted 62 lines · Halil Pasic
Quoted 11 lines · On Fri, 15 Feb 2019 17:55:35 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 10 lines · Pierre Morel

To be able to use the VFIO interface to facilitate the mediated device memory pining/unpining we need to register a notifier for IOMMU.

---
   drivers/s390/crypto/vfio_ap_ops.c     | 64 +++++++++++++++++++++++++++++++----
   drivers/s390/crypto/vfio_ap_private.h |  2 ++
   2 files changed, 60 insertions(+), 6 deletions(-)
Quoted 4 lines

drivers/s390/crypto/vfio_ap_ops.c

Quoted 4 lines
drivers/s390/crypto/vfio_ap_ops.c +0 -0
index 1851b24..6eddc2c 100644

[..]
struct vfio_ap_queue *q;

Quoted 25 lines
Quoted 12 lines
drivers/s390/crypto/vfio_ap_ops.c +4 -4
@@ -967,12 +996,32 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
 
   	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
   				     &events, &matrix_mdev->group_notifier);
-	if (ret) {
-		module_put(THIS_MODULE);
-		return ret;
-	}
+	if (ret)
+		goto err_group;
+
+	matrix_mdev->iommu_notifier.notifier_call = vfio_ap_mdev_iommu_notifier;

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_open(struct mdev_device *mdev) · line 1012

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
+
+	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+				     &events, &matrix_mdev->iommu_notifier);
+	if (ret)
+		goto err_iommu;
+
+	ret = vfio_ap_associate_queues(matrix_mdev);
+	if (ret)
+		goto err_associate;

I think the matrix_mdev should be associated with queues when an assignment of an adapter or domain is made to the mdev device via its

Quoted 9 lines

sysfs interfaces. I say this because assigning an adapter or domain to an mdev device effectively grants ownership of any additional AP queues added to the mdev device's AP matrix as a result of the assignment. It only makes sense to assign ownership to the vfio_ap_queue objects representing the queues at that time. If an adapter or domain is dynamically assigned while a guest is using the affected queues, then the associations will have to be made at that time and this code will likely go bye bye.

Actually, we need the stuff in vfio_ap_queues only if the guest is offered to decides to use AP adaper interrupts. I would prefer to have it around only when needed: as long as we have the nib pinned for any given queue. Is there a reason why not to do so?

Quoted 5 lines

Regards,
Halil

[..]

Since I will rework the vfio_ap_queue life cycle, I will study this.
But I find the creation / deletion in probe/remove and the link/unlimk to the matrix device in assign/un_assign as suggested by Tony more logical.

Regards,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
maintainer
#50 lore raw

Re: [PATCH v3 6/9] vfio: ap: register IOMMU VFIO notifier

In reply to Halil Pasic
Quoted 57 lines · Halil Pasic
Quoted 11 lines · On Fri, 15 Feb 2019 17:55:35 -0500 Tony Krowiak <[email protected]> wrote:
Quoted 10 lines · Pierre Morel

To be able to use the VFIO interface to facilitate the mediated device memory pining/unpining we need to register a notifier for IOMMU.

---
   drivers/s390/crypto/vfio_ap_ops.c     | 64 +++++++++++++++++++++++++++++++----
   drivers/s390/crypto/vfio_ap_private.h |  2 ++
   2 files changed, 60 insertions(+), 6 deletions(-)
Quoted 4 lines

drivers/s390/crypto/vfio_ap_ops.c

Quoted 4 lines
drivers/s390/crypto/vfio_ap_ops.c +0 -0
index 1851b24..6eddc2c 100644

[..]
struct vfio_ap_queue *q;

Quoted 25 lines
Quoted 12 lines
drivers/s390/crypto/vfio_ap_ops.c +4 -4
@@ -967,12 +996,32 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
 
   	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
   				     &events, &matrix_mdev->group_notifier);
-	if (ret) {
-		module_put(THIS_MODULE);
-		return ret;
-	}
+	if (ret)
+		goto err_group;
+
+	matrix_mdev->iommu_notifier.notifier_call = vfio_ap_mdev_iommu_notifier;

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_open(struct mdev_device *mdev) · line 1012

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
+
+	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+				     &events, &matrix_mdev->iommu_notifier);
+	if (ret)
+		goto err_iommu;
+
+	ret = vfio_ap_associate_queues(matrix_mdev);
+	if (ret)
+		goto err_associate;

I think the matrix_mdev should be associated with queues when an assignment of an adapter or domain is made to the mdev device via its

Quoted 9 lines

sysfs interfaces. I say this because assigning an adapter or domain to an mdev device effectively grants ownership of any additional AP queues added to the mdev device's AP matrix as a result of the assignment. It only makes sense to assign ownership to the vfio_ap_queue objects representing the queues at that time. If an adapter or domain is dynamically assigned while a guest is using the affected queues, then the associations will have to be made at that time and this code will likely go bye bye.

Quoted 4 lines

Actually, we need the stuff in vfio_ap_queues only if the guest is offered to decides to use AP adaper interrupts. I would prefer to have it around only when needed: as long as we have the nib pinned for any given queue. Is there a reason why not to do so?

Even if we keep the vfio_ap_queue around for the life of a guest, association/dissociation will have to be done when an adapter or domain is dynamically assigned.

Quoted 6 lines

Regards,
Halil

[..]

#51 lore raw

Re: [PATCH v3 6/9] vfio: ap: register IOMMU VFIO notifier

In reply to Tony Krowiak
Quoted 125 lines · Tony Krowiak
Quoted 54 lines · Pierre Morel

To be able to use the VFIO interface to facilitate the mediated device memory pining/unpining we need to register a notifier for IOMMU.

---
  drivers/s390/crypto/vfio_ap_ops.c     | 64
+++++++++++++++++++++++++++++++----
  drivers/s390/crypto/vfio_ap_private.h |  2 ++

  2 files changed, 60 insertions(+), 6 deletions(-)
drivers/s390/crypto/vfio_ap_ops.c +30 -0
index 1851b24..6eddc2c 100644
@@ -781,6 +781,36 @@ static const struct attribute_group 
 *vfio_ap_mdev_attr_groups[] = {
   };
   /**
+ * vfio_ap_mdev_iommu_notifier: IOMMU notifier callback
+ *
+ * @nb: The notifier block
+ * @action: Action to be taken (VFIO_IOMMU_NOTIFY_DMA_UNMAP)
+ * @data: the specific unmap structure for vfio_iommu_type1
+ *
+ * Unpins the guest IOVA. (The NIB guest address we pinned before).
+ * Return NOTIFY_OK after unpining on a UNMAP request.
+ * otherwise, returns NOTIFY_DONE .
+ */
+static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
+                       unsigned long action, void *data)
+{
+    struct ap_matrix_mdev *matrix_mdev;
+
+    matrix_mdev = container_of(nb, struct ap_matrix_mdev, 
 iommu_notifier);
+
+    if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
+        struct vfio_iommu_type1_dma_unmap *unmap = data;
+        unsigned long g_pfn = unmap->iova >> PAGE_SHIFT;
+
+        vfio_unpin_pages(mdev_dev(matrix_mdev->mdev), &g_pfn, 1);
+        return NOTIFY_OK;
+    }
+
+    return NOTIFY_DONE;
+}
+
+
+/**
    * vfio_ap_mdev_set_kvm
    *

   * @matrix_mdev: a mediated matrix device

drivers/s390/crypto/vfio_ap_ops.c static void vfio_ap_dissociate_queues(struct · line 938

Quoted 7 lines
drivers/s390/crypto/vfio_ap_ops.c +1 -2
@@ -904,8 +934,7 @@ static void vfio_ap_dissociate_queues(struct 
 ap_matrix_mdev *matrix_mdev)
    * In the case a queue could not be found return -ENODEV.
    * Otherwise return 0.
    */
-static __attribute__((unused))
-    int vfio_ap_associate_queues(struct ap_matrix_mdev *matrix_mdev)
+static int vfio_ap_associate_queues(struct ap_matrix_mdev *matrix_mdev)

Maybe this function should be introduced in this patch instead?

Quoted 16 lines
drivers/s390/crypto/vfio_ap_ops.c +0 -0
   {
       unsigned long apid, apqi;

      struct vfio_ap_queue *q;

drivers/s390/crypto/vfio_ap_ops.c +4 -4
@@ -967,12 +996,32 @@ static int vfio_ap_mdev_open(struct mdev_device 
 *mdev)
       ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
                        &events, &matrix_mdev->group_notifier);
-    if (ret) {
-        module_put(THIS_MODULE);
-        return ret;
-    }
+    if (ret)
+        goto err_group;
+
+    matrix_mdev->iommu_notifier.notifier_call = 
 vfio_ap_mdev_iommu_notifier;

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_open(struct mdev_device · line 1013

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+    events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
+
+    ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+                     &events, &matrix_mdev->iommu_notifier);
+    if (ret)
+        goto err_iommu;
+
+    ret = vfio_ap_associate_queues(matrix_mdev);
+    if (ret)
+        goto err_associate;

I think the matrix_mdev should be associated with queues when an assignment of an adapter or domain is made to the mdev device via its sysfs interfaces. I say this because assigning an adapter or domain to
an mdev device effectively grants ownership of any additional AP queues added to the mdev device's AP matrix as a result of the assignment. It only makes sense to assign ownership to the vfio_ap_queue objects
representing the queues at that time. If an adapter or domain is
dynamically assigned while a guest is using the affected queues, then
the associations will have to be made at that time and this code will
likely go bye bye.

Quoted 14 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
       return 0;
+
+err_associate:
+    vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+                 &matrix_mdev->iommu_notifier);
+err_iommu:
+    vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
+                 &matrix_mdev->group_notifier);
+err_group:
+    module_put(THIS_MODULE);
+    return ret;
   }
   static void vfio_ap_mdev_release(struct mdev_device *mdev)

drivers/s390/crypto/vfio_ap_ops.c static void vfio_ap_mdev_release(struct · line 1040

Quoted 7 lines
drivers/s390/crypto/vfio_ap_ops.c +3 -0
@@ -985,6 +1034,9 @@ static void vfio_ap_mdev_release(struct 
 mdev_device *mdev)
       vfio_ap_mdev_reset_queues(mdev);
       vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
                    &matrix_mdev->group_notifier);
+    vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
+                 &matrix_mdev->iommu_notifier);
+    vfio_ap_dissociate_queues(matrix_mdev);

I think the matrix_mdev should be dissociated from queues when an adapter or domain is unassigned from the mdev device via its

Quoted 8 lines

sysfs interfaces. I say this because unassigning an adapter or domain from an mdev device effectively takes away ownership of any AP queues removed from the mdev device's AP matrix as a result of the
unassignment. It only makes sense to remove ownership from the
vfio_ap_queue objects representing the queues at that time. This will
become necessary for the forthcoming dynamic configuration patches.
If an adapter or domain is dynamically unassigned while a guest is
using the affected queues, then the dissociation will have to be made
at that time and this code will likely go bye bye.

Effectively,having a link from the vfio_ap_queue to the mediated device will simplify the sanity checking during assignment.

I will go this way.

Regards,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#52 lore raw

PATCH v3 7/9 s390: ap: implement PAPQ AQIC interception in kernel

In reply to Pierre Morel

We register the AP PQAP instruction hook during the open of the mediated device. And unregister it on release.

In the AP PQAP instruction hook, if we receive a demand to enable IRQs,
- we retrieve the vfio_ap_queue based on the APQN we receive in REG1,
- we retrieve the page of the guest address, (NIB), from register REG2
- we the mediated device to use the VFIO pinning infratrsucture to pin the page of the guest address,
- we retrieve the pointer to KVM to register the guest ISC and retrieve the host ISC
- finaly we activate GISA

If we receive a demand to disable IRQs,
- we deactivate GISA
- unregister from the GIB
- unping the NIB

---
 drivers/s390/crypto/ap_bus.h          |   1 +
 drivers/s390/crypto/vfio_ap_ops.c     | 191 +++++++++++++++++++++++++++++++++-
 drivers/s390/crypto/vfio_ap_private.h |   2 +
 3 files changed, 191 insertions(+), 3 deletions(-)
drivers/s390/crypto/ap_bus.h +1 -0
index bfc66e4..323f2aa 100644
@@ -43,6 +43,7 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
 #define AP_RESPONSE_BUSY		0x05
 #define AP_RESPONSE_INVALID_ADDRESS	0x06
 #define AP_RESPONSE_OTHERWISE_CHANGED	0x07
+#define AP_RESPONSE_INVALID_GISA	0x08
 #define AP_RESPONSE_Q_FULL		0x10
 #define AP_RESPONSE_NO_PENDING_REPLY	0x10
 #define AP_RESPONSE_INDEX_TOO_BIG	0x11
drivers/s390/crypto/vfio_ap_ops.c +188 -3

248 lines not on this page · raw message

drivers/s390/crypto/vfio_ap_private.h +2 -0
index 2781720..16c99e9 100644
@@ -92,5 +92,7 @@ struct vfio_ap_queue {
 	struct device *dev;
 	int	apqn;
 	struct ap_matrix_mdev *matrix;
+	unsigned long nib;
+	unsigned char isc;
 };
 #endif /* _VFIO_AP_PRIVATE_H_ */
Signature · 1 line
2.7.4
maintainer
#53 lore raw

Re: [PATCH v3 7/9] s390: ap: implement PAPQ AQIC interception in kernel

Quoted 177 lines · Pierre Morel

We register the AP PQAP instruction hook during the open of the mediated device. And unregister it on release.

In the AP PQAP instruction hook, if we receive a demand to enable IRQs,
- we retrieve the vfio_ap_queue based on the APQN we receive in REG1,
- we retrieve the page of the guest address, (NIB), from register REG2
- we the mediated device to use the VFIO pinning infratrsucture to pin the page of the guest address,
- we retrieve the pointer to KVM to register the guest ISC and retrieve the host ISC
- finaly we activate GISA

If we receive a demand to disable IRQs,
- we deactivate GISA
- unregister from the GIB
- unping the NIB

---
  drivers/s390/crypto/ap_bus.h          |   1 +
  drivers/s390/crypto/vfio_ap_ops.c     | 191 +++++++++++++++++++++++++++++++++-
  drivers/s390/crypto/vfio_ap_private.h |   2 +
  3 files changed, 191 insertions(+), 3 deletions(-)
drivers/s390/crypto/ap_bus.h +1 -0
index bfc66e4..323f2aa 100644
@@ -43,6 +43,7 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
  #define AP_RESPONSE_BUSY		0x05
  #define AP_RESPONSE_INVALID_ADDRESS	0x06
  #define AP_RESPONSE_OTHERWISE_CHANGED	0x07
+#define AP_RESPONSE_INVALID_GISA	0x08
  #define AP_RESPONSE_Q_FULL		0x10
  #define AP_RESPONSE_NO_PENDING_REPLY	0x10
  #define AP_RESPONSE_INDEX_TOO_BIG	0x11
drivers/s390/crypto/vfio_ap_ops.c +116 -0
index 6eddc2c..5664cf3 100644
@@ -77,6 +77,28 @@ static void vfio_ap_put_queue(struct vfio_ap_queue *q)
  	q->dev = NULL;
  }
 
+/**
+ * vfio_ap_free_irq:
+ * @q: The vfio_ap_queue
+ *
+ * Unpin the guest NIB
+ * Unregister the ISC from the GIB alert
+ * Clear the vfio_ap_queue intern fields
+ */
+static void vfio_ap_free_irq(struct vfio_ap_queue *q)
+{
+	unsigned long pfn = q->nib >> PAGE_SHIFT;
+
+	if (!q)
+		return;
+	if (q->nib)
+		vfio_unpin_pages(mdev_dev(q->matrix->mdev), &pfn, 1);
+	if (q->isc)
+		kvm_s390_gisc_unregister(q->matrix->kvm, q->isc);
+	q->nib = 0;
+	q->isc = 0;
+}
+
  static void vfio_ap_matrix_init(struct ap_config_info *info,
  				struct ap_matrix *matrix)
  {
@@ -98,6 +120,7 @@ static int vfio_ap_mdev_create(struct kobject *kobj, struct mdev_device *mdev)
  		return -ENOMEM;
  	}
 
+	matrix_mdev->mdev = mdev;
  	vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix);
  	mdev_set_drvdata(mdev, matrix_mdev);
  	mutex_lock(&matrix_dev->lock);
@@ -781,6 +804,156 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = {
  };
 
  /**
+ * vfio_ap_clrirq: Disable Interruption for a APQN
+ *
+ * @dev: the device associated with the ap_queue
+ * @q:   the vfio_ap_queue holding AQIC parameters
+ *
+ * Issue the host side PQAP/AQIC
+ * On success: unpin the NIB saved in *q and unregister from GIB
+ * interface
+ *
+ * Return the ap_queue_status returned by the ap_aqic()
+ */
+static struct ap_queue_status vfio_ap_clrirq(struct vfio_ap_queue *q)
+{
+	struct ap_qirq_ctrl aqic_gisa = {};
+	struct ap_queue_status status;
+
+	status = ap_aqic(q->apqn, aqic_gisa, NULL);
+	if (!status.response_code)
+		vfio_ap_free_irq(q);
+
+	return status;
+}
+
+/**
+ * vfio_ap_setirq: Enable Interruption for a APQN
+ *
+ * @dev: the device associated with the ap_queue
+ * @q:   the vfio_ap_queue holding AQIC parameters
+ *
+ * Pin the NIB saved in *q
+ * Register the guest ISC to GIB interface and retrieve the
+ * host ISC to issue the host side PQAP/AQIC
+ *
+ * Response.status may be set to following Response Code in case of error:
+ * - AP_RESPONSE_INVALID_ADDRESS: vfio_pin_pages failed
+ * - AP_RESPONSE_OTHERWISE_CHANGED: Hypervizor GISA internal error
+ *
+ * Otherwise return the ap_queue_status returned by the ap_aqic()
+ */
+static struct ap_queue_status vfio_ap_setirq(struct vfio_ap_queue *q)
+{
+	struct ap_qirq_ctrl aqic_gisa = {};
+	struct ap_queue_status status = {};
+	struct kvm_s390_gisa *gisa;
+	struct kvm *kvm;
+	unsigned long g_pfn, h_nib, h_pfn;
+	int ret;
+
+	kvm = q->matrix->kvm;
+	gisa = kvm->arch.gisa_int.origin;
+
+	g_pfn = q->nib >> PAGE_SHIFT;
+	ret = vfio_pin_pages(mdev_dev(q->matrix->mdev), &g_pfn, 1,
+			     IOMMU_READ | IOMMU_WRITE, &h_pfn);
+	switch (ret) {
+	case 1:
+		break;
+	case -EINVAL:
+	case -E2BIG:
+		status.response_code = AP_RESPONSE_INVALID_ADDRESS;
+		/* Fallthrough */
+	default:
+		return status;
+	}
+
+	h_nib = (h_pfn << PAGE_SHIFT) | (q->nib & ~PAGE_MASK);
+	aqic_gisa.gisc = q->isc;
+	aqic_gisa.isc = kvm_s390_gisc_register(kvm, q->isc);
+	aqic_gisa.ir = 1;
+	aqic_gisa.gisa = gisa->next_alert >> 4;
+
+	status = ap_aqic(q->apqn, aqic_gisa, (void *)h_nib);
+	if (status.response_code == AP_RESPONSE_INVALID_GISA) {
+		status.response_code = AP_RESPONSE_OTHERWISE_CHANGED;
+		pr_warn("vfio_ap: apqn %02x.%04x: AP_RESPONSE_INVALID_GISA\n",
+			(q->apqn >> 8) & 0xff, q->apqn & 0xff);
+	}
+
+	if (status.response_code)
+		vfio_ap_free_irq(q);
+
+	return status;
+}
+
+/**
+ * handle_pqap: PQAP instruction callback
+ *
+ * @vcpu: The vcpu on which we received the PQAP instruction
+ *
+ * Get the general register contents to initialize internal variables.
+ * REG[0]: APQN
+ * REG[1]: IR and ISC
+ * REG[2]: NIB

drivers/s390/crypto/vfio_ap_ops.c static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { · line 909

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+ *
+ * Response.status may be set to following Response Code:
+ * - AP_RESPONSE_Q_NOT_AVAIL: if the queue is not available
+ * - AP_RESPONSE_DECONFIGURED: if the queue is not configured
+ * - AP_RESPONSE_NORMAL (0) : in case of successs
+ *   Check vfio_ap_setirq() and vfio_ap_clrirq() for other possible RC.
+ *
+ * Return 0 if we could handle the request inside KVM.
+ * otherwise, returns -EOPNOTSUPP to let QEMU handle the fault.
+ */

This function be nothing more than a switch statement for the function code sent with the PQAP instruction. Each case should be a call to a appropriate PQAP function handler. This will make it much easier to add additional handlers for the 6 other PQAP functions if necessary at some time down the road.

drivers/s390/crypto/vfio_ap_ops.c static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { · line 911

Quoted 2 lines
drivers/s390/crypto/vfio_ap_ops.c +2 -0
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{	int ret.
	uint8_t fc;

	fc = vcpu->run->s.regs.gprs[0] >> 24;
	switch(fc) {
	case 0x03:
		ret = handle_pqap_aqic(vcpu);
	default:
		ret = -EOPNOTSUPP;
	}

	return ret;
}

static int handle_pqap_aqic(struct kvm_vcpu *vcpu) {

drivers/s390/crypto/vfio_ap_ops.c static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { · line 913

Quoted 2 lines
drivers/s390/crypto/vfio_ap_ops.c +2 -0
+	uint64_t status;
+	uint16_t apqn;
	struct device *qdev;

drivers/s390/crypto/vfio_ap_ops.c static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { · line 923

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+	struct vfio_ap_queue *q;
+	struct ap_queue_status qstatus = {};
+	struct ap_matrix_mdev *matrix_mdev;
+
+	/* If we do not use the AIV facility just go to userland */
+	if (!(vcpu->arch.sie_block->eca & ECA_AIV))
+		return -EOPNOTSUPP;
+
+	apqn = vcpu->run->s.regs.gprs[0] & 0xffff;
+	q = vfio_ap_get_queue(apqn);

Replace with:

	qdev = vfio_ap_get_queue_dev(apqn);

drivers/s390/crypto/vfio_ap_ops.c static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { · line 924

Quoted 1 line
drivers/s390/crypto/vfio_ap_ops.c +1 -0
+	if (!q) {

Replace with:

	if (!qdev)

drivers/s390/crypto/vfio_ap_ops.c static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { · line 929

Quoted 5 lines
drivers/s390/crypto/vfio_ap_ops.c +5 -0
+		qstatus.response_code = AP_RESPONSE_Q_NOT_AVAIL;
+		goto out;
+	}
+
+	/* Check if the queue is associated with a guest matrix */

Add this:

	q = dev_get_drvdata(qdev);
Quoted 14 lines
drivers/s390/crypto/vfio_ap_ops.c +13 -0
+	matrix_mdev = q->matrix;
+	if (!matrix_mdev || !matrix_mdev->kvm) {
+		qstatus.response_code = AP_RESPONSE_DECONFIGURED
 
+		goto out;
+	}
+
+	status = vcpu->run->s.regs.gprs[1];
+
+	/* If IR bit(16) is set we enable the interrupt */
+	if ((status >> (63 - 16)) & 0x01) {
+		q->isc = status & 0x07;
+		q->nib = vcpu->run->s.regs.gprs[2];
+		qstatus = vfio_ap_setirq(q);

drivers/s390/crypto/vfio_ap_ops.c static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { · line 952

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+		if (qstatus.response_code) {
+			q->nib = 0;
+			q->isc = 0;
+		}
+	} else
+		qstatus = vfio_ap_clrirq(q);
+
+out:
+	memcpy(&vcpu->run->s.regs.gprs[1], &qstatus, sizeof(qstatus));
+	vfio_ap_put_queue(q);

Replace with:

	put_device(qdev);

Can we just do a put_device(qdev) right after we get it since we only need it to get the drvdata, or do we need to wait until the other work is done?

Quoted 83 lines
drivers/s390/crypto/vfio_ap_ops.c +4 -0
+	return 0;
+}
+
+ /*
   * vfio_ap_mdev_iommu_notifier: IOMMU notifier callback
   *

* @nb: The notifier block

drivers/s390/crypto/vfio_ap_ops.c +15 -3
@@ -802,7 +975,9 @@ static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
  		struct vfio_iommu_type1_dma_unmap *unmap = data;
  		unsigned long g_pfn = unmap->iova >> PAGE_SHIFT;
 
-		vfio_unpin_pages(mdev_dev(matrix_mdev->mdev), &g_pfn, 1);
+		if (matrix_mdev->mdev)
+			vfio_unpin_pages(mdev_dev(matrix_mdev->mdev),
+					 &g_pfn, 1);
  		return NOTIFY_OK;
  	}
 
@@ -877,11 +1052,15 @@ static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi,
  				    unsigned int retry)
  {
  	struct ap_queue_status status;
+	struct vfio_ap_queue *q;
+
+	q = vfio_ap_get_queue(AP_MKQID(apid, apqi));
 
  	do {
  		status = ap_zapq(AP_MKQID(apid, apqi));
  		switch (status.response_code) {
  		case AP_RESPONSE_NORMAL:
+			vfio_ap_free_irq(q);
  			return 0;
  		case AP_RESPONSE_RESET_IN_PROGRESS:
  		case AP_RESPONSE_BUSY:
@@ -999,6 +1178,11 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
  	if (ret)
  		goto err_group;
 
+	if (!matrix_mdev->kvm) {
+		ret = -ENODEV;
+		goto err_iommu;
+	}
+
  	matrix_mdev->iommu_notifier.notifier_call = vfio_ap_mdev_iommu_notifier;
  	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
 
@@ -1011,6 +1195,7 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
  	if (ret)
  		goto err_associate;
 
+	matrix_mdev->kvm->arch.crypto.pqap_hook = handle_pqap;
  	return 0;
 
  err_associate:
@@ -1031,12 +1216,12 @@ static void vfio_ap_mdev_release(struct mdev_device *mdev)
  	if (matrix_mdev->kvm)
  		kvm_arch_crypto_clear_masks(matrix_mdev->kvm);
 
-	vfio_ap_mdev_reset_queues(mdev);
+	matrix_mdev->kvm->arch.crypto.pqap_hook = NULL;
+	vfio_ap_dissociate_queues(matrix_mdev);
  	vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
  				 &matrix_mdev->group_notifier);
  	vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
  				 &matrix_mdev->iommu_notifier);
-	vfio_ap_dissociate_queues(matrix_mdev);
  	matrix_mdev->kvm = NULL;
  	module_put(THIS_MODULE);
  }
drivers/s390/crypto/vfio_ap_private.h +2 -0
index 2781720..16c99e9 100644
@@ -92,5 +92,7 @@ struct vfio_ap_queue {
  	struct device *dev;
  	int	apqn;
  	struct ap_matrix_mdev *matrix;
+	unsigned long nib;
+	unsigned char isc;
 
  };
  #endif /* _VFIO_AP_PRIVATE_H_ */
#54 lore raw

Re: [PATCH v3 7/9] s390: ap: implement PAPQ AQIC interception in kernel

Quoted 188 lines · Tony Krowiak
Quoted 187 lines · Pierre Morel

We register the AP PQAP instruction hook during the open of the mediated device. And unregister it on release.

In the AP PQAP instruction hook, if we receive a demand to enable IRQs,
- we retrieve the vfio_ap_queue based on the APQN we receive in REG1,
- we retrieve the page of the guest address, (NIB), from register REG2
- we the mediated device to use the VFIO pinning infratrsucture to pin the page of the guest address,
- we retrieve the pointer to KVM to register the guest ISC and retrieve the host ISC
- finaly we activate GISA

If we receive a demand to disable IRQs,
- we deactivate GISA
- unregister from the GIB
- unping the NIB

---
  drivers/s390/crypto/ap_bus.h          |   1 +
  drivers/s390/crypto/vfio_ap_ops.c     | 191
+++++++++++++++++++++++++++++++++-
  drivers/s390/crypto/vfio_ap_private.h |   2 +

  3 files changed, 191 insertions(+), 3 deletions(-)
drivers/s390/crypto/ap_bus.h +1 -0
index bfc66e4..323f2aa 100644
@@ -43,6 +43,7 @@ static inline int ap_test_bit(unsigned int *ptr, 
 unsigned int nr)
   #define AP_RESPONSE_BUSY        0x05
   #define AP_RESPONSE_INVALID_ADDRESS    0x06
   #define AP_RESPONSE_OTHERWISE_CHANGED    0x07
+#define AP_RESPONSE_INVALID_GISA    0x08
   #define AP_RESPONSE_Q_FULL        0x10
   #define AP_RESPONSE_NO_PENDING_REPLY    0x10

  #define AP_RESPONSE_INDEX_TOO_BIG    0x11

drivers/s390/crypto/vfio_ap_ops.c +57 -0
index 6eddc2c..5664cf3 100644
@@ -77,6 +77,28 @@ static void vfio_ap_put_queue(struct vfio_ap_queue *q)
       q->dev = NULL;
   }
+/**
+ * vfio_ap_free_irq:
+ * @q: The vfio_ap_queue
+ *
+ * Unpin the guest NIB
+ * Unregister the ISC from the GIB alert
+ * Clear the vfio_ap_queue intern fields
+ */
+static void vfio_ap_free_irq(struct vfio_ap_queue *q)
+{
+    unsigned long pfn = q->nib >> PAGE_SHIFT;
+
+    if (!q)
+        return;
+    if (q->nib)
+        vfio_unpin_pages(mdev_dev(q->matrix->mdev), &pfn, 1);
+    if (q->isc)
+        kvm_s390_gisc_unregister(q->matrix->kvm, q->isc);
+    q->nib = 0;
+    q->isc = 0;
+}
+
   static void vfio_ap_matrix_init(struct ap_config_info *info,
                   struct ap_matrix *matrix)
   {
@@ -98,6 +120,7 @@ static int vfio_ap_mdev_create(struct kobject 
 *kobj, struct mdev_device *mdev)
           return -ENOMEM;
       }
+    matrix_mdev->mdev = mdev;
       vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix);
       mdev_set_drvdata(mdev, matrix_mdev);
       mutex_lock(&matrix_dev->lock);
@@ -781,6 +804,156 @@ static const struct attribute_group 
 *vfio_ap_mdev_attr_groups[] = {
   };
   /**
+ * vfio_ap_clrirq: Disable Interruption for a APQN
+ *
+ * @dev: the device associated with the ap_queue
+ * @q:   the vfio_ap_queue holding AQIC parameters
+ *
+ * Issue the host side PQAP/AQIC
+ * On success: unpin the NIB saved in *q and unregister from GIB
+ * interface
+ *
+ * Return the ap_queue_status returned by the ap_aqic()
+ */
+static struct ap_queue_status vfio_ap_clrirq(struct vfio_ap_queue *q)
+{
+    struct ap_qirq_ctrl aqic_gisa = {};
+    struct ap_queue_status status;
+
+    status = ap_aqic(q->apqn, aqic_gisa, NULL);
+    if (!status.response_code)
+        vfio_ap_free_irq(q);
+
+    return status;
+}
+
+/**
+ * vfio_ap_setirq: Enable Interruption for a APQN
+ *
+ * @dev: the device associated with the ap_queue
+ * @q:   the vfio_ap_queue holding AQIC parameters
+ *
+ * Pin the NIB saved in *q
+ * Register the guest ISC to GIB interface and retrieve the
+ * host ISC to issue the host side PQAP/AQIC
+ *
+ * Response.status may be set to following Response Code in case of 

error:
+ * - AP_RESPONSE_INVALID_ADDRESS: vfio_pin_pages failed
+ * - AP_RESPONSE_OTHERWISE_CHANGED: Hypervizor GISA internal error
+ *
+ * Otherwise return the ap_queue_status returned by the ap_aqic()
+ */

drivers/s390/crypto/vfio_ap_ops.c +62 -0
+static struct ap_queue_status vfio_ap_setirq(struct vfio_ap_queue *q)
+{
+    struct ap_qirq_ctrl aqic_gisa = {};
+    struct ap_queue_status status = {};
+    struct kvm_s390_gisa *gisa;
+    struct kvm *kvm;
+    unsigned long g_pfn, h_nib, h_pfn;
+    int ret;
+
+    kvm = q->matrix->kvm;
+    gisa = kvm->arch.gisa_int.origin;
+
+    g_pfn = q->nib >> PAGE_SHIFT;
+    ret = vfio_pin_pages(mdev_dev(q->matrix->mdev), &g_pfn, 1,
+                 IOMMU_READ | IOMMU_WRITE, &h_pfn);
+    switch (ret) {
+    case 1:
+        break;
+    case -EINVAL:
+    case -E2BIG:
+        status.response_code = AP_RESPONSE_INVALID_ADDRESS;
+        /* Fallthrough */
+    default:
+        return status;
+    }
+
+    h_nib = (h_pfn << PAGE_SHIFT) | (q->nib & ~PAGE_MASK);
+    aqic_gisa.gisc = q->isc;
+    aqic_gisa.isc = kvm_s390_gisc_register(kvm, q->isc);
+    aqic_gisa.ir = 1;
+    aqic_gisa.gisa = gisa->next_alert >> 4;
+
+    status = ap_aqic(q->apqn, aqic_gisa, (void *)h_nib);
+    if (status.response_code == AP_RESPONSE_INVALID_GISA) {
+        status.response_code = AP_RESPONSE_OTHERWISE_CHANGED;
+        pr_warn("vfio_ap: apqn %02x.%04x: AP_RESPONSE_INVALID_GISA\n",
+            (q->apqn >> 8) & 0xff, q->apqn & 0xff);
+    }
+
+    if (status.response_code)
+        vfio_ap_free_irq(q);
+
+    return status;
+}
+
+/**
+ * handle_pqap: PQAP instruction callback
+ *
+ * @vcpu: The vcpu on which we received the PQAP instruction
+ *
+ * Get the general register contents to initialize internal variables.
+ * REG[0]: APQN
+ * REG[1]: IR and ISC
+ * REG[2]: NIB
+ *
+ * Response.status may be set to following Response Code:
+ * - AP_RESPONSE_Q_NOT_AVAIL: if the queue is not available
+ * - AP_RESPONSE_DECONFIGURED: if the queue is not configured
+ * - AP_RESPONSE_NORMAL (0) : in case of successs
+ *   Check vfio_ap_setirq() and vfio_ap_clrirq() for other possible RC.
+ *
+ * Return 0 if we could handle the request inside KVM.
Quoted 8 lines
Quoted 2 lines

+ * otherwise, returns -EOPNOTSUPP to let QEMU handle the fault.
+ */

This function be nothing more than a switch statement for the function code sent with the PQAP instruction. Each case should be a call to a appropriate PQAP function handler. This will make it much easier to add additional handlers for the 6 other PQAP functions if necessary at some time down the road.

AFAIK there are only two PQAP functions we can intercept.

I will give attention to this function.
I will wait to this on the answers from KVM maintainers to know which KVM functions I can use here.

Quoted 20 lines

drivers/s390/crypto/vfio_ap_ops.c

Quoted 3 lines
drivers/s390/crypto/vfio_ap_ops.c +2 -0
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{    int ret.

    uint8_t fc;

    fc = vcpu->run->s.regs.gprs[0] >> 24;
    switch(fc) {
    case 0x03:
        ret = handle_pqap_aqic(vcpu);
    default:
        ret = -EOPNOTSUPP;
    }

    return ret;
}

static int handle_pqap_aqic(struct kvm_vcpu *vcpu) {

Quoted 2 lines

+    uint64_t status;
+    uint16_t apqn;

    struct device *qdev;

Quoted 13 lines

drivers/s390/crypto/vfio_ap_ops.c static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { · line 923

Quoted 10 lines

+    struct vfio_ap_queue *q;
+    struct ap_queue_status qstatus = {};
+    struct ap_matrix_mdev *matrix_mdev;

drivers/s390/crypto/vfio_ap_ops.c +7 -0
+
+    /* If we do not use the AIV facility just go to userland */
+    if (!(vcpu->arch.sie_block->eca & ECA_AIV))
+        return -EOPNOTSUPP;
+
+    apqn = vcpu->run->s.regs.gprs[0] & 0xffff;
+    q = vfio_ap_get_queue(apqn);

Replace with:
    qdev = vfio_ap_get_queue_dev(apqn);

You asked to revisit the life cycle of the vfio_ap_queues in another thread. I will do it.

Thanks
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
maintainer
#55 lore raw

Re: [PATCH v3 7/9] s390: ap: implement PAPQ AQIC interception in kernel

In reply to Pierre Morel
Quoted 22 lines · On Thu, 14 Feb 2019 14:51:07 +0100 Pierre Morel <[email protected]> wrote:

We register the AP PQAP instruction hook during the open of the mediated device. And unregister it on release.

In the AP PQAP instruction hook, if we receive a demand to enable IRQs,
- we retrieve the vfio_ap_queue based on the APQN we receive in REG1,
- we retrieve the page of the guest address, (NIB), from register REG2
- we the mediated device to use the VFIO pinning infratrsucture to pin the page of the guest address,
- we retrieve the pointer to KVM to register the guest ISC and retrieve the host ISC
- finaly we activate GISA

If we receive a demand to disable IRQs,
- we deactivate GISA
- unregister from the GIB
- unping the NIB

---

[..]

Quoted 22 lines
drivers/s390/crypto/vfio_ap_ops.c +22 -0
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+	uint64_t status;
+	uint16_t apqn;
+	struct vfio_ap_queue *q;
+	struct ap_queue_status qstatus = {};
+	struct ap_matrix_mdev *matrix_mdev;
+
+	/* If we do not use the AIV facility just go to userland */
+	if (!(vcpu->arch.sie_block->eca & ECA_AIV))
+		return -EOPNOTSUPP;
+
+	apqn = vcpu->run->s.regs.gprs[0] & 0xffff;
+	q = vfio_ap_get_queue(apqn);
+	if (!q) {
+		qstatus.response_code = AP_RESPONSE_Q_NOT_AVAIL;
+		goto out;
+	}
+
+	/* Check if the queue is associated with a guest matrix */
+	matrix_mdev = q->matrix;
+	if (!matrix_mdev || !matrix_mdev->kvm) {

drivers/s390/crypto/vfio_ap_ops.c static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { · line 941

Quoted 10 lines
drivers/s390/crypto/vfio_ap_ops.c +10 -0
+		qstatus.response_code = AP_RESPONSE_DECONFIGURED;
+		goto out;
+	}
+
+	status = vcpu->run->s.regs.gprs[1];
+
+	/* If IR bit(16) is set we enable the interrupt */
+	if ((status >> (63 - 16)) & 0x01) {
+		q->isc = status & 0x07;
+		q->nib = vcpu->run->s.regs.gprs[2];

Careful! You may already have q->nib set (may or may not be a 0x07 scenario). You should unpin the old nib if set interruption controls works out, if we get 0x07 response then you unpin the new one.

Quoted 13 lines
drivers/s390/crypto/vfio_ap_ops.c +13 -0
+		qstatus = vfio_ap_setirq(q);
+		if (qstatus.response_code) {
+			q->nib = 0;
+			q->isc = 0;
+		}
+	} else
+		qstatus = vfio_ap_clrirq(q);
+
+out:
+	memcpy(&vcpu->run->s.regs.gprs[1], &qstatus, sizeof(qstatus));
+	vfio_ap_put_queue(q);
+	return 0;
+}

[..]

drivers/s390/crypto/vfio_ap_ops.c static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 1062

Quoted 13 lines
drivers/s390/crypto/vfio_ap_ops.c +3 -0
@@ -877,11 +1052,15 @@ static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi,
 				    unsigned int retry)
 {
 	struct ap_queue_status status;
+	struct vfio_ap_queue *q;
+
+	q = vfio_ap_get_queue(AP_MKQID(apid, apqi));
 
 	do {
 		status = ap_zapq(AP_MKQID(apid, apqi));
 		switch (status.response_code) {
 		case AP_RESPONSE_NORMAL:

You could do the get queue here

Review static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, · line 1063

Quoted 1 line
(quoted diff) +1 -0
+			vfio_ap_free_irq(q);

And the put here.

Regards,
Halil

Quoted 15 lines
drivers/s390/crypto/vfio_ap_ops.c +5 -0
 			return 0;
 		case AP_RESPONSE_RESET_IN_PROGRESS:
 		case AP_RESPONSE_BUSY:
@@ -999,6 +1178,11 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
 	if (ret)
 		goto err_group;
 
+	if (!matrix_mdev->kvm) {
+		ret = -ENODEV;
+		goto err_iommu;
+	}
+
 	matrix_mdev->iommu_notifier.notifier_call = vfio_ap_mdev_iommu_notifier;
 	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
 

[..]

#56 lore raw

Re: [PATCH v3 7/9] s390: ap: implement PAPQ AQIC interception in kernel

Quoted 56 lines · Halil Pasic
Quoted 22 lines · On Thu, 14 Feb 2019 14:51:07 +0100 Pierre Morel <[email protected]> wrote:

We register the AP PQAP instruction hook during the open of the mediated device. And unregister it on release.

In the AP PQAP instruction hook, if we receive a demand to enable IRQs,
- we retrieve the vfio_ap_queue based on the APQN we receive in REG1,
- we retrieve the page of the guest address, (NIB), from register REG2
- we the mediated device to use the VFIO pinning infratrsucture to pin the page of the guest address,
- we retrieve the pointer to KVM to register the guest ISC and retrieve the host ISC
- finaly we activate GISA

If we receive a demand to disable IRQs,
- we deactivate GISA
- unregister from the GIB
- unping the NIB

---

[..]

Quoted 28 lines
drivers/s390/crypto/vfio_ap_ops.c +28 -0
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+	uint64_t status;
+	uint16_t apqn;
+	struct vfio_ap_queue *q;
+	struct ap_queue_status qstatus = {};
+	struct ap_matrix_mdev *matrix_mdev;
+
+	/* If we do not use the AIV facility just go to userland */
+	if (!(vcpu->arch.sie_block->eca & ECA_AIV))
+		return -EOPNOTSUPP;
+
+	apqn = vcpu->run->s.regs.gprs[0] & 0xffff;
+	q = vfio_ap_get_queue(apqn);
+	if (!q) {
+		qstatus.response_code = AP_RESPONSE_Q_NOT_AVAIL;
+		goto out;
+	}
+
+	/* Check if the queue is associated with a guest matrix */
+	matrix_mdev = q->matrix;
+	if (!matrix_mdev || !matrix_mdev->kvm) {
+		qstatus.response_code = AP_RESPONSE_DECONFIGURED;
+		goto out;
+	}
+
+	status = vcpu->run->s.regs.gprs[1];
+
Quoted 8 lines

drivers/s390/crypto/vfio_ap_ops.c static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { · line 941

Quoted 4 lines
drivers/s390/crypto/vfio_ap_ops.c +4 -0
+	/* If IR bit(16) is set we enable the interrupt */
+	if ((status >> (63 - 16)) & 0x01) {
+		q->isc = status & 0x07;
+		q->nib = vcpu->run->s.regs.gprs[2];

Careful! You may already have q->nib set (may or may not be a 0x07 scenario). You should unpin the old nib if set interruption controls works out, if we get 0x07 response then you unpin the new one.

You are right. We already had this discussion and the corrected patch. It seems I misunderstood what we wanted to do by sending this patch series out.

I will make this right.

regards,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#57 lore raw

PATCH v3 8/9 s390: ap: Cleanup on removing the AP device

In reply to Pierre Morel

When the device is remove, we must make sure to
clear the interruption and reset the AP device.

We also need to clear the CRYCB of the guest.

---
 drivers/s390/crypto/vfio_ap_drv.c     | 92 +++++++++++++++++++++++++++++++++++
 drivers/s390/crypto/vfio_ap_ops.c     |  2 +-
 drivers/s390/crypto/vfio_ap_private.h |  2 +
 3 files changed, 95 insertions(+), 1 deletion(-)
drivers/s390/crypto/vfio_ap_drv.c +92 -0
index 03153e6..50428be 100644
@@ -5,6 +5,7 @@
  * Copyright IBM Corp. 2018
  *
  * Author(s): Tony Krowiak <[email protected]>
+ *	      Pierre Morel <[email protected]>
  */
 
 #include <linux/module.h>
@@ -12,6 +13,8 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <asm/facility.h>
+#include <linux/bitops.h>
+#include <linux/kvm_host.h>
 #include "vfio_ap_private.h"
 
 #define VFIO_AP_ROOT_NAME "vfio_ap"
@@ -64,6 +67,88 @@ static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
 	return 0;
 }
 
+/*
+ * vfio_ap_drain_queue
+ * @q: the queue to drain
+ *
+ * This function waits until the queue is empty.
+ */
+static void vfio_ap_drain_queue(struct vfio_ap_queue *q)
+{
+	struct ap_queue_status status;
+	int retry = 20;
+
+	status = ap_tapq(q->apqn, NULL);
+	while (!status.queue_empty && retry--)  {
+		msleep(200);
+		status = ap_tapq(q->apqn, NULL);
+	}
+	if (retry <= 0) {
+		pr_warn("%s: queue not empty after zapq on apqn 0x%04x\n",
+			__func__, q->apqn);
+	}
+}
+
+/*
+ * vfio_ap_zapq
+ * @q: The queue to zerro
+ *
+ * It is best effort, no return value is done, however on success
+ * we will drain the queue before getting the queue back to the
+ * AP bus.
+ */
+static void vfio_ap_zapq(struct vfio_ap_queue *q)
+{
+	struct ap_queue_status status;
+	int retry = 20;
+
+	do {
+		status = ap_zapq(q->apqn);
+		switch (status.response_code) {
+		case AP_RESPONSE_RESET_IN_PROGRESS:
+		case AP_RESPONSE_BUSY:
+			msleep(20);
+			break;
+		default:
+			pr_warn("%s: zapq error %02x on apqn 0x%04x\n",
+				__func__, status.response_code, q->apqn);
+			return;
+		case AP_RESPONSE_NORMAL:
+			vfio_ap_drain_queue(q);
+			return;
+		}
+	} while (retry--);
+	pr_warn("%s: zapq retry count exceeded code %02x on apqn 0x%04x\n",
+		__func__, status.response_code, q->apqn);
+}
+
+/**
+ * vfio_ap_update_crycb
+ * @q: A pointer to the queue being removed
+ *
+ * We clear the APID of the queue, making this queue unusable for the guest.
+ * After this function we can reset the queue without to fear a race with
+ * the guest to access the queue again.
+ * We do not fear race with the host as we still get the device.
+ */
+static void vfio_ap_update_crycb(struct vfio_ap_queue *q)
+{
+	struct ap_matrix_mdev *matrix_mdev = q->matrix;
+
+	if (!matrix_mdev)
+		return;
+
+	clear_bit_inv(AP_QID_CARD(q->apqn), matrix_mdev->matrix.apm);
+
+	if (!matrix_mdev->kvm)
+		return;
+
+	kvm_arch_crypto_set_masks(matrix_mdev->kvm,
+				  matrix_mdev->matrix.apm,
+				  matrix_mdev->matrix.aqm,
+				  matrix_mdev->matrix.adm);
+}
+
 /**
  * vfio_ap_queue_dev_remove:
  *
@@ -74,6 +159,13 @@ static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
 	struct vfio_ap_queue *q;
 
 	q = dev_get_drvdata(&apdev->device);
+	if (!q)
+		return;
+
+	vfio_ap_update_crycb(q);
+	vfio_ap_zapq(q);
+
+	vfio_ap_free_irq(q);
 	kfree(q);
 }
 
drivers/s390/crypto/vfio_ap_ops.c +1 -1
index 5664cf3..7ec957c 100644
@@ -85,7 +85,7 @@ static void vfio_ap_put_queue(struct vfio_ap_queue *q)
  * Unregister the ISC from the GIB alert
  * Clear the vfio_ap_queue intern fields
  */
-static void vfio_ap_free_irq(struct vfio_ap_queue *q)
+void vfio_ap_free_irq(struct vfio_ap_queue *q)
 {
 	unsigned long pfn = q->nib >> PAGE_SHIFT;
 
drivers/s390/crypto/vfio_ap_private.h +2 -0
index 16c99e9..d108c6d 100644
@@ -4,6 +4,7 @@
  *
  * Author(s): Tony Krowiak <[email protected]>
  *	      Halil Pasic <[email protected]>
+ *	      Pierre Morel <[email protected]>
  *
  * Copyright IBM Corp. 2018
  */
@@ -95,4 +96,5 @@ struct vfio_ap_queue {
 	unsigned long nib;
 	unsigned char isc;
 };
+void vfio_ap_free_irq(struct vfio_ap_queue *q);
 #endif /* _VFIO_AP_PRIVATE_H_ */
Signature · 1 line
2.7.4
maintainer
#58 lore raw

Re: [PATCH v3 8/9] s390: ap: Cleanup on removing the AP device

Quoted 75 lines · Pierre Morel

When the device is remove, we must make sure to
clear the interruption and reset the AP device.

We also need to clear the CRYCB of the guest.

---
  drivers/s390/crypto/vfio_ap_drv.c     | 92 +++++++++++++++++++++++++++++++++++
  drivers/s390/crypto/vfio_ap_ops.c     |  2 +-
  drivers/s390/crypto/vfio_ap_private.h |  2 +
  3 files changed, 95 insertions(+), 1 deletion(-)
drivers/s390/crypto/vfio_ap_drv.c +41 -0
index 03153e6..50428be 100644
@@ -5,6 +5,7 @@
   * Copyright IBM Corp. 2018
   *
   * Author(s): Tony Krowiak <[email protected]>
+ *	      Pierre Morel <[email protected]>
   */
 
  #include <linux/module.h>
@@ -12,6 +13,8 @@
  #include <linux/slab.h>
  #include <linux/string.h>
  #include <asm/facility.h>
+#include <linux/bitops.h>
+#include <linux/kvm_host.h>
  #include "vfio_ap_private.h"
 
  #define VFIO_AP_ROOT_NAME "vfio_ap"
@@ -64,6 +67,88 @@ static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
  	return 0;
  }
 
+/*
+ * vfio_ap_drain_queue
+ * @q: the queue to drain
+ *
+ * This function waits until the queue is empty.
+ */
+static void vfio_ap_drain_queue(struct vfio_ap_queue *q)
+{
+	struct ap_queue_status status;
+	int retry = 20;
+
+	status = ap_tapq(q->apqn, NULL);
+	while (!status.queue_empty && retry--)  {
+		msleep(200);
+		status = ap_tapq(q->apqn, NULL);
+	}
+	if (retry <= 0) {
+		pr_warn("%s: queue not empty after zapq on apqn 0x%04x\n",
+			__func__, q->apqn);
+	}
+}
+
+/*
+ * vfio_ap_zapq
+ * @q: The queue to zerro
+ *
+ * It is best effort, no return value is done, however on success
+ * we will drain the queue before getting the queue back to the
+ * AP bus.
+ */
+static void vfio_ap_zapq(struct vfio_ap_queue *q)
+{
+	struct ap_queue_status status;
+	int retry = 20;
+
+	do {
+		status = ap_zapq(q->apqn);
+		switch (status.response_code) {

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_queue_dev_probe(struct ap_device *apdev) · line 117

Quoted 10 lines
drivers/s390/crypto/vfio_ap_drv.c +10 -0
+		case AP_RESPONSE_RESET_IN_PROGRESS:
+		case AP_RESPONSE_BUSY:
+			msleep(20);
+			break;
+		default:
+			pr_warn("%s: zapq error %02x on apqn 0x%04x\n",
+				__func__, status.response_code, q->apqn);
+			return;
+		case AP_RESPONSE_NORMAL:
+			vfio_ap_drain_queue(q);

I don't think this is necessary. The zeroize is performed on
each AP-queue entry in an AP queue. My understanding is that when a
reset or zeroize is pending, any AP instructions subsequently issued
are rejected with condition-code 3 indicating an AP queue reset is in
progress. It is also my understanding that once the AP commands currently executing in a given AP queue entry complete, the queue entry will be zeroized. So it seems to me that there is no need to
"drain" the queue, it will have already been done by the zeroize.

If you agree we don't need to "drain" the queue, then I'd rather just make the zapq function in the vfio_ap_ops.c non-static and make it available to the driver. There is no sense in duplicating this code. In fact, even if you keep the draining function, you still don't need to duplicate a zaapq instruction here, you can just call the vfio_ap_ops.c version and then drain the queue on AP_RESPONSE_NORMAL.

Quoted 38 lines
drivers/s390/crypto/vfio_ap_drv.c +34 -0
+			return;
+		}
+	} while (retry--);
+	pr_warn("%s: zapq retry count exceeded code %02x on apqn 0x%04x\n",
+		__func__, status.response_code, q->apqn);
+}
+
+/**
+ * vfio_ap_update_crycb
+ * @q: A pointer to the queue being removed
+ *
+ * We clear the APID of the queue, making this queue unusable for the guest.
+ * After this function we can reset the queue without to fear a race with
+ * the guest to access the queue again.
+ * We do not fear race with the host as we still get the device.
+ */
+static void vfio_ap_update_crycb(struct vfio_ap_queue *q)
+{
+	struct ap_matrix_mdev *matrix_mdev = q->matrix;
+
+	if (!matrix_mdev)
+		return;
+
+	clear_bit_inv(AP_QID_CARD(q->apqn), matrix_mdev->matrix.apm);
+
+	if (!matrix_mdev->kvm)
+		return;
+
+	kvm_arch_crypto_set_masks(matrix_mdev->kvm,
+				  matrix_mdev->matrix.apm,
+				  matrix_mdev->matrix.aqm,
+				  matrix_mdev->matrix.adm);
+}
+
  /**
   * vfio_ap_queue_dev_remove:
   *

drivers/s390/crypto/vfio_ap_drv.c static void vfio_ap_queue_dev_remove(struct ap_device *apdev) · line 168

Quoted 10 lines
drivers/s390/crypto/vfio_ap_drv.c +7 -0
@@ -74,6 +159,13 @@ static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
  	struct vfio_ap_queue *q;
 
  	q = dev_get_drvdata(&apdev->device);
+	if (!q)
+		return;
+
+	vfio_ap_update_crycb(q);
+	vfio_ap_zapq(q);
+
+	vfio_ap_free_irq(q);

If you make the zapq function in vfio_ap_ops.c available to the driver rather than duplicating it in this file, you won't need this call to vfio_ap_free_irq because it is done as part of the zapq in vfio_ap_ops.c.

Quoted 35 lines
drivers/s390/crypto/vfio_ap_drv.c +0 -0
  	kfree(q);
  }
 
drivers/s390/crypto/vfio_ap_ops.c +1 -1
index 5664cf3..7ec957c 100644
@@ -85,7 +85,7 @@ static void vfio_ap_put_queue(struct vfio_ap_queue *q)
   * Unregister the ISC from the GIB alert
   * Clear the vfio_ap_queue intern fields
   */
-static void vfio_ap_free_irq(struct vfio_ap_queue *q)
+void vfio_ap_free_irq(struct vfio_ap_queue *q)
  {
  	unsigned long pfn = q->nib >> PAGE_SHIFT;
 
drivers/s390/crypto/vfio_ap_private.h +2 -0
index 16c99e9..d108c6d 100644
@@ -4,6 +4,7 @@
   *
   * Author(s): Tony Krowiak <[email protected]>
   *	      Halil Pasic <[email protected]>
+ *	      Pierre Morel <[email protected]>
   *
   * Copyright IBM Corp. 2018
   */
@@ -95,4 +96,5 @@ struct vfio_ap_queue {
  	unsigned long nib;
  	unsigned char isc;
  };
+void vfio_ap_free_irq(struct vfio_ap_queue *q);
  #endif /* _VFIO_AP_PRIVATE_H_ */
#59 lore raw

Re: [PATCH v3 8/9] s390: ap: Cleanup on removing the AP device

Quoted 86 lines · Tony Krowiak
Quoted 74 lines · Pierre Morel

When the device is remove, we must make sure to
clear the interruption and reset the AP device.

We also need to clear the CRYCB of the guest.

---
  drivers/s390/crypto/vfio_ap_drv.c     | 92
+++++++++++++++++++++++++++++++++++
  drivers/s390/crypto/vfio_ap_ops.c     |  2 +-
  drivers/s390/crypto/vfio_ap_private.h |  2 +

  3 files changed, 95 insertions(+), 1 deletion(-)
drivers/s390/crypto/vfio_ap_drv.c +41 -0
index 03153e6..50428be 100644
@@ -5,6 +5,7 @@
    * Copyright IBM Corp. 2018
    *
    * Author(s): Tony Krowiak <[email protected]>
+ *          Pierre Morel <[email protected]>
    */
   #include <linux/module.h>
@@ -12,6 +13,8 @@
   #include <linux/slab.h>
   #include <linux/string.h>
   #include <asm/facility.h>
+#include <linux/bitops.h>
+#include <linux/kvm_host.h>
   #include "vfio_ap_private.h"
   #define VFIO_AP_ROOT_NAME "vfio_ap"
@@ -64,6 +67,88 @@ static int vfio_ap_queue_dev_probe(struct ap_device 
 *apdev)
       return 0;
   }
+/*
+ * vfio_ap_drain_queue
+ * @q: the queue to drain
+ *
+ * This function waits until the queue is empty.
+ */
+static void vfio_ap_drain_queue(struct vfio_ap_queue *q)
+{
+    struct ap_queue_status status;
+    int retry = 20;
+
+    status = ap_tapq(q->apqn, NULL);
+    while (!status.queue_empty && retry--)  {
+        msleep(200);
+        status = ap_tapq(q->apqn, NULL);
+    }
+    if (retry <= 0) {
+        pr_warn("%s: queue not empty after zapq on apqn 0x%04x\n",
+            __func__, q->apqn);
+    }
+}
+
+/*
+ * vfio_ap_zapq
+ * @q: The queue to zerro
+ *
+ * It is best effort, no return value is done, however on success
+ * we will drain the queue before getting the queue back to the
+ * AP bus.
+ */
+static void vfio_ap_zapq(struct vfio_ap_queue *q)
+{
+    struct ap_queue_status status;
+    int retry = 20;
+
+    do {
+        status = ap_zapq(q->apqn);
+        switch (status.response_code) {

drivers/s390/crypto/vfio_ap_drv.c static int vfio_ap_queue_dev_probe(struct ap_device · line 117

Quoted 10 lines
drivers/s390/crypto/vfio_ap_drv.c +10 -0
+        case AP_RESPONSE_RESET_IN_PROGRESS:
+        case AP_RESPONSE_BUSY:
+            msleep(20);
+            break;
+        default:
+            pr_warn("%s: zapq error %02x on apqn 0x%04x\n",
+                __func__, status.response_code, q->apqn);
+            return;
+        case AP_RESPONSE_NORMAL:
+            vfio_ap_drain_queue(q);
Quoted 7 lines

I don't think this is necessary. The zeroize is performed on
each AP-queue entry in an AP queue. My understanding is that when a
reset or zeroize is pending, any AP instructions subsequently issued
are rejected with condition-code 3 indicating an AP queue reset is in
progress. It is also my understanding that once the AP commands currently executing in a given AP queue entry complete, the queue entry will be zeroized. So it seems to me that there is no need to
"drain" the queue, it will have already been done by the zeroize.

My understanding from the specifications is that after a RAPQ or a ZAPQ we should wait for the queue to be really empty.

Quoted 7 lines

If you agree we don't need to "drain" the queue, then I'd rather just make the zapq function in the vfio_ap_ops.c non-static and make it available to the driver. There is no sense in duplicating this code. In fact, even if you keep the draining function, you still don't need to duplicate a zaapq instruction here, you can just call the vfio_ap_ops.c version and then drain the queue on AP_RESPONSE_NORMAL.

OK I will see how to optimize this.

Quoted 11 lines

drivers/s390/crypto/vfio_ap_drv.c static void vfio_ap_queue_dev_remove(struct ap_device *apdev) · line 168

Quoted 6 lines
drivers/s390/crypto/vfio_ap_drv.c +6 -0
+        return;
+
+    vfio_ap_update_crycb(q);
+    vfio_ap_zapq(q);
+
+    vfio_ap_free_irq(q);

If you make the zapq function in vfio_ap_ops.c available to the driver rather than duplicating it in this file, you won't need this call to vfio_ap_free_irq because it is done as part of the zapq in vfio_ap_ops.c.

Another solution.
OK I will look at this.

Thanks,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
maintainer
#60 lore raw

Re: [PATCH v3 8/9] s390: ap: Cleanup on removing the AP device

In reply to Pierre Morel
Quoted 123 lines · Pierre Morel

When the device is remove, we must make sure to
clear the interruption and reset the AP device.

We also need to clear the CRYCB of the guest.

---
  drivers/s390/crypto/vfio_ap_drv.c     | 92 +++++++++++++++++++++++++++++++++++
  drivers/s390/crypto/vfio_ap_ops.c     |  2 +-
  drivers/s390/crypto/vfio_ap_private.h |  2 +
  3 files changed, 95 insertions(+), 1 deletion(-)
drivers/s390/crypto/vfio_ap_drv.c +85 -0
index 03153e6..50428be 100644
@@ -5,6 +5,7 @@
   * Copyright IBM Corp. 2018
   *
   * Author(s): Tony Krowiak <[email protected]>
+ *	      Pierre Morel <[email protected]>
   */
 
  #include <linux/module.h>
@@ -12,6 +13,8 @@
  #include <linux/slab.h>
  #include <linux/string.h>
  #include <asm/facility.h>
+#include <linux/bitops.h>
+#include <linux/kvm_host.h>
  #include "vfio_ap_private.h"
 
  #define VFIO_AP_ROOT_NAME "vfio_ap"
@@ -64,6 +67,88 @@ static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
  	return 0;
  }
 
+/*
+ * vfio_ap_drain_queue
+ * @q: the queue to drain
+ *
+ * This function waits until the queue is empty.
+ */
+static void vfio_ap_drain_queue(struct vfio_ap_queue *q)
+{
+	struct ap_queue_status status;
+	int retry = 20;
+
+	status = ap_tapq(q->apqn, NULL);
+	while (!status.queue_empty && retry--)  {
+		msleep(200);
+		status = ap_tapq(q->apqn, NULL);
+	}
+	if (retry <= 0) {
+		pr_warn("%s: queue not empty after zapq on apqn 0x%04x\n",
+			__func__, q->apqn);
+	}
+}
+
+/*
+ * vfio_ap_zapq
+ * @q: The queue to zerro
+ *
+ * It is best effort, no return value is done, however on success
+ * we will drain the queue before getting the queue back to the
+ * AP bus.
+ */
+static void vfio_ap_zapq(struct vfio_ap_queue *q)
+{
+	struct ap_queue_status status;
+	int retry = 20;
+
+	do {
+		status = ap_zapq(q->apqn);
+		switch (status.response_code) {
+		case AP_RESPONSE_RESET_IN_PROGRESS:
+		case AP_RESPONSE_BUSY:
+			msleep(20);
+			break;
+		default:
+			pr_warn("%s: zapq error %02x on apqn 0x%04x\n",
+				__func__, status.response_code, q->apqn);
+			return;
+		case AP_RESPONSE_NORMAL:
+			vfio_ap_drain_queue(q);
+			return;
+		}
+	} while (retry--);
+	pr_warn("%s: zapq retry count exceeded code %02x on apqn 0x%04x\n",
+		__func__, status.response_code, q->apqn);
+}
+
+/**
+ * vfio_ap_update_crycb
+ * @q: A pointer to the queue being removed
+ *
+ * We clear the APID of the queue, making this queue unusable for the guest.
+ * After this function we can reset the queue without to fear a race with
+ * the guest to access the queue again.
+ * We do not fear race with the host as we still get the device.
+ */
+static void vfio_ap_update_crycb(struct vfio_ap_queue *q)
+{
+	struct ap_matrix_mdev *matrix_mdev = q->matrix;
+
+	if (!matrix_mdev)
+		return;
+
+	clear_bit_inv(AP_QID_CARD(q->apqn), matrix_mdev->matrix.apm);
+
+	if (!matrix_mdev->kvm)
+		return;
+
+	kvm_arch_crypto_set_masks(matrix_mdev->kvm,
+				  matrix_mdev->matrix.apm,
+				  matrix_mdev->matrix.aqm,
+				  matrix_mdev->matrix.adm);
+}
+
  /**
   * vfio_ap_queue_dev_remove:
   *

drivers/s390/crypto/vfio_ap_drv.c static void vfio_ap_queue_dev_remove(struct ap_device *apdev) · line 165

Quoted 7 lines
drivers/s390/crypto/vfio_ap_drv.c +4 -0
@@ -74,6 +159,13 @@ static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
  	struct vfio_ap_queue *q;
 
  	q = dev_get_drvdata(&apdev->device);
+	if (!q)
+		return;
+
+	vfio_ap_update_crycb(q);

The root user is warned in the Limitations section of the vfio-ap.txt doc delivered with the AP pass-through support warns that the administrator (i.e., root user) should ensure that AP devices are not removed without taking proper care to ensure they are not in use by a guest. I am currently working on a patch set to handle this, so this may simply get ripped out when those patches are integrated. That may very well be simultaneously with this patch series as I plan on posting those soon.

If this call is to remain, then you ought to update the vfio-ap.txt document to let users know that when queues are unbound, the guests will lose access to them unbeknown to the admin of the guest.

drivers/s390/crypto/vfio_ap_drv.c static void vfio_ap_queue_dev_remove(struct ap_device *apdev) · line 166

Quoted 1 line
drivers/s390/crypto/vfio_ap_drv.c +1 -0
+	vfio_ap_zapq(q);

One last thing. I've explained before that prior to the AP bus invoking this remove callback, it flushes and zeroizes the queue. Why do you insist it needs to be done again in the remove callback?

Quoted 37 lines
drivers/s390/crypto/vfio_ap_drv.c +2 -0
+
+	vfio_ap_free_irq(q);
  	kfree(q);
  }
 
drivers/s390/crypto/vfio_ap_ops.c +1 -1
index 5664cf3..7ec957c 100644
@@ -85,7 +85,7 @@ static void vfio_ap_put_queue(struct vfio_ap_queue *q)
   * Unregister the ISC from the GIB alert
   * Clear the vfio_ap_queue intern fields
   */
-static void vfio_ap_free_irq(struct vfio_ap_queue *q)
+void vfio_ap_free_irq(struct vfio_ap_queue *q)
  {
  	unsigned long pfn = q->nib >> PAGE_SHIFT;
 
drivers/s390/crypto/vfio_ap_private.h +2 -0
index 16c99e9..d108c6d 100644
@@ -4,6 +4,7 @@
   *
   * Author(s): Tony Krowiak <[email protected]>
   *	      Halil Pasic <[email protected]>
+ *	      Pierre Morel <[email protected]>
   *
   * Copyright IBM Corp. 2018
   */
@@ -95,4 +96,5 @@ struct vfio_ap_queue {
  	unsigned long nib;
  	unsigned char isc;
  };
+void vfio_ap_free_irq(struct vfio_ap_queue *q);
  #endif /* _VFIO_AP_PRIVATE_H_ */
#61 lore raw

Re: [PATCH v3 8/9] s390: ap: Cleanup on removing the AP device

Quoted 4 lines · Tony Krowiak
Quoted 3 lines · Pierre Morel

When the device is remove, we must make sure to
clear the interruption and reset the AP device.

...snip...

Quoted 18 lines

drivers/s390/crypto/vfio_ap_drv.c static void vfio_ap_queue_dev_remove(struct · line 165

Quoted 8 lines
drivers/s390/crypto/vfio_ap_drv.c +4 -0
@@ -74,6 +159,13 @@ static void vfio_ap_queue_dev_remove(struct 
 ap_device *apdev)
       struct vfio_ap_queue *q;
       q = dev_get_drvdata(&apdev->device);
+    if (!q)
+        return;
+
+    vfio_ap_update_crycb(q);

The root user is warned in the Limitations section of the vfio-ap.txt doc delivered with the AP pass-through support warns that the administrator (i.e., root user) should ensure that AP devices are not removed without taking proper care to ensure they are not in use by a guest. I am currently working on a patch set to handle this, so this may simply get ripped out when those patches are integrated. That may very well be simultaneously with this patch series as I plan on posting those soon.

Quoted 3 lines

If this call is to remain, then you ought to update the vfio-ap.txt document to let users know that when queues are unbound, the guests will lose access to them unbeknown to the admin of the guest.

I do not see where is the problem, the admin should still take care the APQN are not in use by the guest when he does an unbind.

This just makes sure it is not used anymore by the guest when the admin rebound it to the host or another guest.

Quoted 7 lines

drivers/s390/crypto/vfio_ap_drv.c static void vfio_ap_queue_dev_remove(struct ap_device *apdev) · line 166

Quoted 2 lines
drivers/s390/crypto/vfio_ap_drv.c +1 -0
+    vfio_ap_zapq(q);

One last thing. I've explained before that prior to the AP bus invoking this remove callback, it flushes and zeroizes the queue. Why do you insist it needs to be done again in the remove callback?

The problem is that the AP_BUS is not aware from the CRYCB and let the guest play with the queue.

The sequence an be like:

-> AP_BUS remove RESET the queue and zeroes with ZAPQ -> AP_BUS call remove from driver

	- the APQN still belong to the guest !
		-> the guest issue a NQAP

===> We need to take the queue away from the guest ===> and we need to RESET the queue with ZAPQ and wait
until no more message is in the queue
-> driver remove ends

Regards,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany
#62 lore raw

PATCH v3 9/9 s390: ap: kvm: add AP Queue Interruption Control facility

In reply to Pierre Morel

AP Queue Interruption Control (AQIC) facility gives the guest the possibility to control interruption for the Cryptographic Adjunct Processor queues.

---
 arch/s390/tools/gen_facilities.c | 1 +
 1 file changed, 1 insertion(+)
arch/s390/tools/gen_facilities.c +1 -0
index fd788e0..18d317d 100644
@@ -108,6 +108,7 @@ static struct facility_def facility_defs[] = {
 		.bits = (int[]){
 			12, /* AP Query Configuration Information */
 			15, /* AP Facilities Test */
+			65, /* AP Queue Interruption Control */
 			156, /* etoken facility */
 			-1  /* END */
 		}
Signature · 1 line
2.7.4
maintainer
#63 lore raw
In reply to Pierre Morel

On 2/14/19 8:51 AM, Pierre Morel wrote:

The subject leads one to believe this patch series introduces ioctl definitions for AQIC, but there is not a single ioctl definition in the series. Something like this might be more appropriate:

vfio: ap: support for AP Queue Interrupt Control

Regards
T. Krow

Quoted 94 lines

This patch implement PQAP/AQIC interception in KVM.

To implement this we need to add a new structure, vfio_ap_queue,to be able to retrieve the mediated device associated with a queue and specific values needed to register/unregister the interrupt structures:
- APQN: to be able to issue the commands and search for queue structures
- NIB : to unpin the NIB on clear IRQ
- ISC : to unregister with the GIB interface
- MATRIX: a pointer to the matrix mediated device
- DEV: a pointer to the AP queue device from AP bus.

1) Phase 1, probe and remove from vfio_ap_queue

The vfio_ap_queue structures are dynamically allocated when a queue is probed by the ap_vfio_driver.
It is linked to the ap_queue device as the driver data. We store the APQN of the ap_queue device inside the vfio_ap_queue. The vfio_ap_queue are free during remove.

2) Phase 2, assignment of vfio_ap_queue to a mediated device

When the VFIO device is opened the queues are associated to the mediated device, at the same time the CRYCB is setup.

When the device is closed or if a queue is removed the queue is dissociated from the mediated device, as the same time the CRYCB is cleared.

Two new functions are used for this: associate/disassociate.

3) Phase 3 intercepting the PQAP/AQIC instruction

On interception of the PQAP/AQIC instruction, the interception code makes sure the pqap_hook is initialized and allowed to be called and call it.
Otherwise it reports the usual -EOPNOTSUPP return code to let QEMU handle the fault.

the pqap callback search for the queue asociated with the APQN stored in the register 0, setting the code to "illegal APQN" if the vfio_ap_queue can not be found.

Depending on the "i" bit of the register 1, the pqap callback setup or clear the interruption by calling the host format PQAP/AQIC instruction.
When seting up the interruption it uses the NIB and the guest ISC provided by the guest and the host ISC provided by the registration to the GIB code, pin the NIB and also stores ISC and NIB inside the vfio_ap_queue structure.
When clearing the interrupt it retrieves the host ISC to unregister with the GIB code and unpin the NIB.

There is a QEMU patch which is needed to enable the PQAP/AQIC facility in the guest.

Posted in [email protected] as:
Message-Id: <[email protected]>

4) Phase 4 clean dissociation from the mediated device on remove

On removing of the AP device the remove callback is called. To be sure that the guest will not access the queue anymore we clear the APID CRYCB bit.
Cleaning the APID, over the APQI, is chosen because the architecture specifies that only the APID can be dynamically changed outside IPL. After this the queue is zeroes, care is taken to correctly wait until the queue is empty.

Pierre Morel (9):
s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem
s390: ap: kvm: setting a hook for PQAP instructions
s390: ap: new vfio_ap_queue structure
s390: ap: tools to find a queue with a specific APQN
s390: ap: tools to associate a queue to a matrix
vfio: ap: register IOMMU VFIO notifier
s390: ap: implement PAPQ AQIC interception in kernel
s390: ap: Cleanup on removing the AP device
s390: ap: kvm: add AP Queue Interruption Control facility

  arch/s390/include/asm/kvm_host.h      |   1 +
  arch/s390/kvm/priv.c                  |  50 +++++
  arch/s390/tools/gen_facilities.c      |   1 +
  drivers/s390/crypto/ap_bus.h          |   1 +
  drivers/s390/crypto/vfio_ap_drv.c     | 178 ++++++++++++++++-
  drivers/s390/crypto/vfio_ap_ops.c     | 363 +++++++++++++++++++++++++++++++++-
  drivers/s390/crypto/vfio_ap_private.h |  12 ++
  7 files changed, 593 insertions(+), 13 deletions(-)
#64 lore raw
Quoted 6 lines · Tony Krowiak

On 2/14/19 8:51 AM, Pierre Morel wrote:

The subject leads one to believe this patch series introduces ioctl definitions for AQIC, but there is not a single ioctl definition in the series. Something like this might be more appropriate:

This is right Tony, no ioctl here.
I kept the original subject and increment the version number to let people know that this is a new version of the implementation of PQAP/AQIC interception for which we already had 2 iterations.

May be you are right and I should have change the subject.

Thanks for making this clear.

Regards,
Pierre

Signature · 2 lines
Pierre Morel
Linux/KVM/QEMU in Böblingen - Germany