diff mbox series

[v18,15/18] s390/vfio-ap: handle config changed and scan complete notification

Message ID 20220215005040.52697-16-akrowiak@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series s390/vfio-ap: dynamic configuration support | expand

Commit Message

Anthony Krowiak Feb. 15, 2022, 12:50 a.m. UTC
This patch implements two new AP driver callbacks:

void (*on_config_changed)(struct ap_config_info *new_config_info,
                      struct ap_config_info *old_config_info);

void (*on_scan_complete)(struct ap_config_info *new_config_info,
                     struct ap_config_info *old_config_info);

The on_config_changed callback is invoked at the start of the AP bus scan
function when it determines that the host AP configuration information
has changed since the previous scan.

The vfio_ap device driver registers a callback function for this callback
that performs the following operations:

1. Unplugs the adapters, domains and control domains removed from the
   host's AP configuration from the guests to which they are
   assigned in a single operation.

2. Stores bitmaps identifying the adapters, domains and control domains
   added to the host's AP configuration with the structure representing
   the mediated device. When the vfio_ap device driver's probe callback is
   subsequently invoked, the probe function will recognize that the
   queue is being probed due to a change in the host's AP configuration
   and the plugging of the queue into the guest will be bypassed.

The on_scan_complete callback is invoked after the ap bus scan is
completed if the host AP configuration data has changed. The vfio_ap
device driver registers a callback function for this callback that hot
plugs each queue and control domain added to the AP configuration for each
guest using them in a single hot plug operation.

Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com>
---
 drivers/s390/crypto/vfio_ap_drv.c     |   4 +-
 drivers/s390/crypto/vfio_ap_ops.c     | 347 ++++++++++++++++++++++++--
 drivers/s390/crypto/vfio_ap_private.h |  15 +-
 3 files changed, 338 insertions(+), 28 deletions(-)

Comments

Jason J. Herne March 24, 2022, 2:09 p.m. UTC | #1
On 2/14/22 19:50, Tony Krowiak wrote:
...
> @@ -790,13 +788,17 @@ static void vfio_ap_unlink_apqn_fr_mdev(struct ap_matrix_mdev *matrix_mdev,
>   
>   	q = vfio_ap_mdev_get_queue(matrix_mdev, AP_MKQID(apid, apqi));
>   	/* If the queue is assigned to the matrix mdev, unlink it. */
> -	if (q)
> +	if (q) {
>   		vfio_ap_unlink_queue_fr_mdev(q);
>   
> -	/* If the queue is assigned to the APCB, store it in @qtable. */
> -	if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
> -	    test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm))
> -		hash_add(qtable->queues, &q->mdev_qnode, q->apqn);
> +		/* If the queue is assigned to the APCB, store it in @qtable. */
> +		if (qtable) {
> +			if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
> +			    test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm))
> +				hash_add(qtable->queues, &q->mdev_qnode,
> +					 q->apqn);
> +		}
> +	}
>   }

This appears to be an unrelated change. Does this belong in this patch?


>   /**
> @@ -1271,7 +1273,7 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = {
>    * @matrix_mdev: a mediated matrix device
>    * @kvm: reference to KVM instance
>    *
> - * Note: The matrix_dev->lock must be taken prior to calling
> + * Note: The matrix_dev->mdevs_lock must be taken prior to calling

This also seems to be unrelated.


>    * this function; however, the lock will be temporarily released while the
>    * guest's AP configuration is set to avoid a potential lockdep splat.
>    * The kvm->lock is taken to set the guest's AP configuration which, under
> @@ -1355,7 +1357,7 @@ static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
>    * @matrix_mdev: a matrix mediated device
>    * @kvm: the pointer to the kvm structure being unset.
>    *
> - * Note: The matrix_dev->lock must be taken prior to calling
> + * Note: The matrix_dev->mdevs_lock must be taken prior to calling

Same here.

>    * this function; however, the lock will be temporarily released while the
>    * guest's AP configuration is cleared to avoid a potential lockdep splat.
>    * The kvm->lock is taken to clear the guest's AP configuration which, under
> @@ -1708,6 +1710,27 @@ static void vfio_ap_mdev_put_qlocks(struct ap_matrix_mdev *matrix_mdev)
>   	mutex_unlock(&matrix_dev->guests_lock);
>   }
>   
> +static bool vfio_ap_mdev_do_filter_matrix(struct ap_matrix_mdev *matrix_mdev,
> +					  struct vfio_ap_queue *q)
> +{
> +	unsigned long apid = AP_QID_CARD(q->apqn);
> +	unsigned long apqi = AP_QID_QUEUE(q->apqn);
> +
> +	/*
> +	 * If the queue is being probed because its APID or APQI is in the
> +	 * process of being added to the host's AP configuration, then we don't
> +	 * want to filter the matrix now as the filtering will be done after
> +	 * the driver is notified that the AP bus scan operation has completed
> +	 * (see the vfio_ap_on_scan_complete callback function).
> +	 */
> +	if (test_bit_inv(apid, matrix_mdev->apm_add) ||
> +	    test_bit_inv(apqi, matrix_mdev->aqm_add))
> +		return false;
> +
> +
> +	return true;
> +}
> +
>   int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
>   {
>   	struct vfio_ap_queue *q;
> @@ -1725,10 +1748,15 @@ int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
>   		vfio_ap_mdev_link_queue(matrix_mdev, q);
>   		memset(apm, 0, sizeof(apm));
>   		set_bit_inv(AP_QID_CARD(q->apqn), apm);
> -		if (vfio_ap_mdev_filter_matrix(apm, q->matrix_mdev->matrix.aqm,
> -					       q->matrix_mdev))
> -			vfio_ap_mdev_hotplug_apcb(q->matrix_mdev);
> +
> +		if (vfio_ap_mdev_do_filter_matrix(q->matrix_mdev, q)) {
> +			if (vfio_ap_mdev_filter_matrix(apm,
> +						q->matrix_mdev->matrix.aqm,
> +						q->matrix_mdev))
> +				vfio_ap_mdev_hotplug_apcb(q->matrix_mdev);
> +		}
>   	}
> +
>   	dev_set_drvdata(&apdev->device, q);
>   	vfio_ap_mdev_put_qlocks(matrix_mdev);
>   
> @@ -1783,10 +1811,15 @@ void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
>   
>   		apid = AP_QID_CARD(q->apqn);
>   		apqi = AP_QID_QUEUE(q->apqn);
> -		if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
> -		    test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm)) {
> -			clear_bit_inv(apid, matrix_mdev->shadow_apcb.apm);
> -			vfio_ap_mdev_hotplug_apcb(matrix_mdev);
> +
> +		/*
> +		 * If the queue is assigned to the guest's APCB, then remove
> +		 * the adapter's APID from the APCB and hot it into the guest.
> +		 */
> +		if (test_bit_inv(apid, q->matrix_mdev->shadow_apcb.apm) &&
> +		    test_bit_inv(apqi, q->matrix_mdev->shadow_apcb.aqm)) {
> +			clear_bit_inv(apid, q->matrix_mdev->shadow_apcb.apm);
> +			vfio_ap_mdev_hotplug_apcb(q->matrix_mdev);

It looks like this a bug fix unrelated to this patch...?

>   
> @@ -1842,3 +1875,267 @@ int vfio_ap_mdev_resource_in_use(unsigned long *apm, unsigned long *aqm)
>   
>   	return ret;
>   }
> +
> +/**
> + * vfio_ap_mdev_hot_unplug_cfg - hot unplug the adapters, domains and control
> + *				 domains that have been removed from the host's
> + *				 AP configuration from a guest.
> + *
> + * @guest: the guest
> + * @aprem: the adapters that have been removed from the host's AP configuration
> + * @aqrem: the domains that have been removed from the host's AP configuration
> + * @cdrem: the control domains that have been removed from the host's AP
> + *	   configuration.
> + */
> +static void vfio_ap_mdev_hot_unplug_cfg(struct ap_matrix_mdev *matrix_mdev,
> +					unsigned long *aprem,
> +					unsigned long *aqrem,
> +					unsigned long *cdrem)
> +{
> +	bool do_hotplug = false;

__bitmap_andnot() returns an int, so I think you should use an int here.


> +	if (!bitmap_empty(aprem, AP_DEVICES)) {
> +		do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.apm,
> +					    matrix_mdev->shadow_apcb.apm,
> +					    aprem, AP_DEVICES);

Also, replace the |= with an = here. This is the first assignment so no
need to do a logical OR as there is no pre-existing data to preserve.


> +	}
> +
> +	if (!bitmap_empty(aqrem, AP_DOMAINS)) {
> +		do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.aqm,
> +					    matrix_mdev->shadow_apcb.aqm,
> +					    aqrem, AP_DEVICES);
> +	}
> +
> +	if (!bitmap_empty(cdrem, AP_DOMAINS))
> +		do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.adm,
> +					    matrix_mdev->shadow_apcb.adm,
> +					    cdrem, AP_DOMAINS);
> +
> +	if (do_hotplug)
> +		vfio_ap_mdev_hotplug_apcb(matrix_mdev);
> +}
> +
> +/**
> + * vfio_ap_mdev_cfg_remove - determines which guests are using the adapters,
> + *			     domains and control domains that have been removed
> + *			     from the host AP configuration and unplugs them
> + *			     from those guests.
> + *
> + * @ap_remove:	bitmap specifying which adapters have been removed from the host
> + *		config.
> + * @aq_remove:	bitmap specifying which domains have been removed from the host
> + *		config.
> + * @cd_remove:	bitmap specifying which control domains have been removed from
> + *		the host config.
> + */
...
> +/**
> + * vfio_ap_mdev_on_cfg_remove - responds to the removal of adapters, domains and
> + *				control domains from the host AP configuration
> + *				by unplugging them from the guests that are
> + *				using them.
> + */
> +static void vfio_ap_mdev_on_cfg_remove(void)
> +{
> +	int ap_remove, aq_remove, cd_remove;

These can all be replaced with a single variable, just like you did with do_add.

> +	DECLARE_BITMAP(aprem, AP_DEVICES);
> +	DECLARE_BITMAP(aqrem, AP_DOMAINS);
> +	DECLARE_BITMAP(cdrem, AP_DOMAINS);
> +	unsigned long *cur_apm, *cur_aqm, *cur_adm;
> +	unsigned long *prev_apm, *prev_aqm, *prev_adm;
> +
> +	cur_apm = (unsigned long *)matrix_dev->config_info.apm;
> +	cur_aqm = (unsigned long *)matrix_dev->config_info.aqm;
> +	cur_adm = (unsigned long *)matrix_dev->config_info.adm;
> +	prev_apm = (unsigned long *)matrix_dev->config_info_prev.apm;
> +	prev_aqm = (unsigned long *)matrix_dev->config_info_prev.aqm;
> +	prev_adm = (unsigned long *)matrix_dev->config_info_prev.adm;
> +
> +	ap_remove = bitmap_andnot(aprem, prev_apm, cur_apm, AP_DEVICES);
> +	aq_remove = bitmap_andnot(aqrem, prev_aqm, cur_aqm, AP_DOMAINS);
> +	cd_remove = bitmap_andnot(cdrem, prev_adm, cur_adm, AP_DOMAINS);
> +
> +	if (ap_remove || aq_remove || cd_remove)
> +		vfio_ap_mdev_cfg_remove(aprem, aqrem, cdrem);
> +}
...
> +/**
> + * vfio_ap_on_cfg_changed - handles notification of changes to the host AP
> + *			    configuration.
> + *
> + * @new_config_info: the new host AP configuration
> + * @old_config_info: the previous host AP configuration
> + */
> +void vfio_ap_on_cfg_changed(struct ap_config_info *new_config_info,
> +			    struct ap_config_info *old_config_info)
> +{
> +	mutex_lock(&matrix_dev->guests_lock);
> +
> +	memcpy(&matrix_dev->config_info_prev, old_config_info,
> +		       sizeof(struct ap_config_info));
> +	memcpy(&matrix_dev->config_info, new_config_info,
> +	       sizeof(struct ap_config_info));

Why are we storing old_config_info in the matrix_dev? It appears to only
be used within the functions called from right here. Why not just pass it
as an argument?

> +	vfio_ap_mdev_on_cfg_remove();
> +	vfio_ap_mdev_on_cfg_add();
> +
> +	mutex_unlock(&matrix_dev->guests_lock);
> +}

Here is an idea to restructure things... consider combining logic from
vfio_ap_mdev_on_cfg_remove and vfio_ap_mdev_on_cfg_add with
vfio_ap_on_cfg_changed. This makes vfio_ap_on_cfg_changed() longer but
it eliminates some duplicated code and gets rid of both
vfio_ap_mdev_on_cfg_remove and vfio_ap_mdev_on_cfg_add.
note: Untested... :)

void vfio_ap_on_cfg_changed(struct ap_config_info *new_config_info,
			    struct ap_config_info *old_config_info)
{
	DECLARE_BITMAP(changed_adapters, AP_DEVICES);
	DECLARE_BITMAP(changed_domains, AP_DOMAINS);
	DECLARE_BITMAP(changed_cdoms, AP_DOMAINS);
	unsigned long *cur_apm, *cur_aqm, *cur_adm;
	unsigned long *prev_apm, *prev_aqm, *prev_adm;

	cur_apm = (unsigned long *)new_config_info->apm;
	cur_aqm = (unsigned long *)new_config_info->aqm;
	cur_adm = (unsigned long *)new_config_info->adm;
	prev_apm = (unsigned long *)old_config_info->apm;
	prev_aqm = (unsigned long *)old_config_info->.aqm;
	prev_adm = (unsigned long *)old_config_info->adm;

	mutex_lock(&matrix_dev->guests_lock);
	
	/* Handle host configuration removals */
	bitmap_andnot(changed_adapters, prev_apm, cur_apm, AP_DEVICES);
	bitmap_andnot(changed_domains, prev_aqm, cur_aqm, AP_DOMAINS);
	bitmap_andnot(changed_cdoms, prev_adm, cur_adm, AP_DOMAINS);

	if (changed_adapters || changed_domains || changed_cdoms)
		vfio_ap_mdev_cfg_remove(aprem, aqrem, cdrem);

	bitmap_clear(changed_adapters, 0, AP_DEVICES);
	bitmap_clear(changed_domains, 0, AP_DOMAINS);
	bitmap_clear(changed_cdoms, 0, AP_DOMAINS);

	/* Handle host configuration additions */
	bitmap_andnot(changed_adapters, cur_apm, prev_apm, AP_DEVICES);
	bitmap_andnot(changed_domains, cur_aqm, prev_aqm, AP_DOMAINS);
	bitmap_andnot(changed_cdoms, cur_adm, prev_adm, AP_DOMAINS);

	if (changed_adapters || changed_domains || changed_cdoms) {
		vfio_ap_mdev_cfg_add(apm_add, aqm_add, adm_add);
	}
	mutex_unlock(&matrix_dev->guests_lock);
}

Not sure if where I put the locking is 100% correct. We could do a
lock/unlock around each call to vfio_ap_mdev_cfg_{remove|add} but
there is probablyt no point to that, right?

Also, a side effect of these changes is that matrix_dev->config_info
is no longer updated. I guess we either would need to update it here
or update it wherever it was originally updated before this patrch.
Anthony Krowiak March 30, 2022, 7:26 p.m. UTC | #2
On 3/24/22 10:09, Jason J. Herne wrote:
> On 2/14/22 19:50, Tony Krowiak wrote:
> ...
>> @@ -790,13 +788,17 @@ static void vfio_ap_unlink_apqn_fr_mdev(struct 
>> ap_matrix_mdev *matrix_mdev,
>>         q = vfio_ap_mdev_get_queue(matrix_mdev, AP_MKQID(apid, apqi));
>>       /* If the queue is assigned to the matrix mdev, unlink it. */
>> -    if (q)
>> +    if (q) {
>>           vfio_ap_unlink_queue_fr_mdev(q);
>>   -    /* If the queue is assigned to the APCB, store it in @qtable. */
>> -    if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
>> -        test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm))
>> -        hash_add(qtable->queues, &q->mdev_qnode, q->apqn);
>> +        /* If the queue is assigned to the APCB, store it in 
>> @qtable. */
>> +        if (qtable) {
>> +            if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
>> +                test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm))
>> +                hash_add(qtable->queues, &q->mdev_qnode,
>> +                     q->apqn);
>> +        }
>> +    }
>>   }
>
> This appears to be an unrelated change. Does this belong in this patch?

No, that does not belong in this patch, it belongs in patch
[PATCH v18 12/18] s390/vfio-ap: reset queues after adapter/domain 
unassignment.

>
>
>>   /**
>> @@ -1271,7 +1273,7 @@ static const struct attribute_group 
>> *vfio_ap_mdev_attr_groups[] = {
>>    * @matrix_mdev: a mediated matrix device
>>    * @kvm: reference to KVM instance
>>    *
>> - * Note: The matrix_dev->lock must be taken prior to calling
>> + * Note: The matrix_dev->mdevs_lock must be taken prior to calling
>
> This also seems to be unrelated.

The change of the name of the matrix_dev->lock to matrix_dev->mdevs_lock
was done in [PATCH v18 09/18] s390/vfio-ap: introduce new mutex to control
access to the KVM pointer; however, this comment is not valid. A commit has
been pushed for upstream merge which includes removal of this comment.

>
>
>>    * this function; however, the lock will be temporarily released 
>> while the
>>    * guest's AP configuration is set to avoid a potential lockdep splat.
>>    * The kvm->lock is taken to set the guest's AP configuration 
>> which, under
>> @@ -1355,7 +1357,7 @@ static int vfio_ap_mdev_iommu_notifier(struct 
>> notifier_block *nb,
>>    * @matrix_mdev: a matrix mediated device
>>    * @kvm: the pointer to the kvm structure being unset.
>>    *
>> - * Note: The matrix_dev->lock must be taken prior to calling
>> + * Note: The matrix_dev->mdevs_lock must be taken prior to calling
>
> Same here.

Ditto

>
>>    * this function; however, the lock will be temporarily released 
>> while the
>>    * guest's AP configuration is cleared to avoid a potential lockdep 
>> splat.
>>    * The kvm->lock is taken to clear the guest's AP configuration 
>> which, under
>> @@ -1708,6 +1710,27 @@ static void vfio_ap_mdev_put_qlocks(struct 
>> ap_matrix_mdev *matrix_mdev)
>>       mutex_unlock(&matrix_dev->guests_lock);
>>   }
>>   +static bool vfio_ap_mdev_do_filter_matrix(struct ap_matrix_mdev 
>> *matrix_mdev,
>> +                      struct vfio_ap_queue *q)
>> +{
>> +    unsigned long apid = AP_QID_CARD(q->apqn);
>> +    unsigned long apqi = AP_QID_QUEUE(q->apqn);
>> +
>> +    /*
>> +     * If the queue is being probed because its APID or APQI is in the
>> +     * process of being added to the host's AP configuration, then 
>> we don't
>> +     * want to filter the matrix now as the filtering will be done 
>> after
>> +     * the driver is notified that the AP bus scan operation has 
>> completed
>> +     * (see the vfio_ap_on_scan_complete callback function).
>> +     */
>> +    if (test_bit_inv(apid, matrix_mdev->apm_add) ||
>> +        test_bit_inv(apqi, matrix_mdev->aqm_add))
>> +        return false;
>> +
>> +
>> +    return true;
>> +}
>> +
>>   int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
>>   {
>>       struct vfio_ap_queue *q;
>> @@ -1725,10 +1748,15 @@ int vfio_ap_mdev_probe_queue(struct ap_device 
>> *apdev)
>>           vfio_ap_mdev_link_queue(matrix_mdev, q);
>>           memset(apm, 0, sizeof(apm));
>>           set_bit_inv(AP_QID_CARD(q->apqn), apm);
>> -        if (vfio_ap_mdev_filter_matrix(apm, q->matrix_mdev->matrix.aqm,
>> -                           q->matrix_mdev))
>> -            vfio_ap_mdev_hotplug_apcb(q->matrix_mdev);
>> +
>> +        if (vfio_ap_mdev_do_filter_matrix(q->matrix_mdev, q)) {
>> +            if (vfio_ap_mdev_filter_matrix(apm,
>> +                        q->matrix_mdev->matrix.aqm,
>> +                        q->matrix_mdev))
>> +                vfio_ap_mdev_hotplug_apcb(q->matrix_mdev);
>> +        }
>>       }
>> +
>>       dev_set_drvdata(&apdev->device, q);
>>       vfio_ap_mdev_put_qlocks(matrix_mdev);
>>   @@ -1783,10 +1811,15 @@ void vfio_ap_mdev_remove_queue(struct 
>> ap_device *apdev)
>>             apid = AP_QID_CARD(q->apqn);
>>           apqi = AP_QID_QUEUE(q->apqn);
>> -        if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
>> -            test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm)) {
>> -            clear_bit_inv(apid, matrix_mdev->shadow_apcb.apm);
>> -            vfio_ap_mdev_hotplug_apcb(matrix_mdev);
>> +
>> +        /*
>> +         * If the queue is assigned to the guest's APCB, then remove
>> +         * the adapter's APID from the APCB and hot it into the guest.
>> +         */
>> +        if (test_bit_inv(apid, q->matrix_mdev->shadow_apcb.apm) &&
>> +            test_bit_inv(apqi, q->matrix_mdev->shadow_apcb.aqm)) {
>> +            clear_bit_inv(apid, q->matrix_mdev->shadow_apcb.apm);
>> +            vfio_ap_mdev_hotplug_apcb(q->matrix_mdev);
>
> It looks like this a bug fix unrelated to this patch...?

It's not a bug fix, but it is unnecessary. Both what was removed and the 
code
added are fine, but the former makes more sense. I have no idea how this
happened other than the code was accidentally changed while merging code
during one of the multitude of rebases undertaken while developing this
series.
>
>>   @@ -1842,3 +1875,267 @@ int vfio_ap_mdev_resource_in_use(unsigned 
>> long *apm, unsigned long *aqm)
>>         return ret;
>>   }
>> +
>> +/**
>> + * vfio_ap_mdev_hot_unplug_cfg - hot unplug the adapters, domains 
>> and control
>> + *                 domains that have been removed from the host's
>> + *                 AP configuration from a guest.
>> + *
>> + * @guest: the guest
>> + * @aprem: the adapters that have been removed from the host's AP 
>> configuration
>> + * @aqrem: the domains that have been removed from the host's AP 
>> configuration
>> + * @cdrem: the control domains that have been removed from the 
>> host's AP
>> + *       configuration.
>> + */
>> +static void vfio_ap_mdev_hot_unplug_cfg(struct ap_matrix_mdev 
>> *matrix_mdev,
>> +                    unsigned long *aprem,
>> +                    unsigned long *aqrem,
>> +                    unsigned long *cdrem)
>> +{
>> +    bool do_hotplug = false;
>
> __bitmap_andnot() returns an int, so I think you should use an int here.

Okay

>
>
>> +    if (!bitmap_empty(aprem, AP_DEVICES)) {
>> +        do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.apm,
>> +                        matrix_mdev->shadow_apcb.apm,
>> +                        aprem, AP_DEVICES);
>
> Also, replace the |= with an = here. This is the first assignment so no
> need to do a logical OR as there is no pre-existing data to preserve.

We don't know which, if any, of the bitmaps (aprem, aqrem, cdrem) passed to
this function contain set bits, so the |= is necessary because this code
block won't be be executed if aprem is empty. That is why the do_hotplug
variable is initialized to false when it is declared (i.e., each of the 
bitmaps
might be empty).

>
>
>> +    }
>> +
>> +    if (!bitmap_empty(aqrem, AP_DOMAINS)) {
>> +        do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.aqm,
>> +                        matrix_mdev->shadow_apcb.aqm,
>> +                        aqrem, AP_DEVICES);
>> +    }
>> +
>> +    if (!bitmap_empty(cdrem, AP_DOMAINS))
>> +        do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.adm,
>> +                        matrix_mdev->shadow_apcb.adm,
>> +                        cdrem, AP_DOMAINS);
>> +
>> +    if (do_hotplug)
>> +        vfio_ap_mdev_hotplug_apcb(matrix_mdev);
>> +}
>> +
>> +/**
>> + * vfio_ap_mdev_cfg_remove - determines which guests are using the 
>> adapters,
>> + *                 domains and control domains that have been removed
>> + *                 from the host AP configuration and unplugs them
>> + *                 from those guests.
>> + *
>> + * @ap_remove:    bitmap specifying which adapters have been removed 
>> from the host
>> + *        config.
>> + * @aq_remove:    bitmap specifying which domains have been removed 
>> from the host
>> + *        config.
>> + * @cd_remove:    bitmap specifying which control domains have been 
>> removed from
>> + *        the host config.
>> + */
> ...
>> +/**
>> + * vfio_ap_mdev_on_cfg_remove - responds to the removal of adapters, 
>> domains and
>> + *                control domains from the host AP configuration
>> + *                by unplugging them from the guests that are
>> + *                using them.
>> + */
>> +static void vfio_ap_mdev_on_cfg_remove(void)
>> +{
>> +    int ap_remove, aq_remove, cd_remove;
>
> These can all be replaced with a single variable, just like you did 
> with do_add.

True, consider it done.

>
>> +    DECLARE_BITMAP(aprem, AP_DEVICES);
>> +    DECLARE_BITMAP(aqrem, AP_DOMAINS);
>> +    DECLARE_BITMAP(cdrem, AP_DOMAINS);
>> +    unsigned long *cur_apm, *cur_aqm, *cur_adm;
>> +    unsigned long *prev_apm, *prev_aqm, *prev_adm;
>> +
>> +    cur_apm = (unsigned long *)matrix_dev->config_info.apm;
>> +    cur_aqm = (unsigned long *)matrix_dev->config_info.aqm;
>> +    cur_adm = (unsigned long *)matrix_dev->config_info.adm;
>> +    prev_apm = (unsigned long *)matrix_dev->config_info_prev.apm;
>> +    prev_aqm = (unsigned long *)matrix_dev->config_info_prev.aqm;
>> +    prev_adm = (unsigned long *)matrix_dev->config_info_prev.adm;
>> +
>> +    ap_remove = bitmap_andnot(aprem, prev_apm, cur_apm, AP_DEVICES);
>> +    aq_remove = bitmap_andnot(aqrem, prev_aqm, cur_aqm, AP_DOMAINS);
>> +    cd_remove = bitmap_andnot(cdrem, prev_adm, cur_adm, AP_DOMAINS);
>> +
>> +    if (ap_remove || aq_remove || cd_remove)
>> +        vfio_ap_mdev_cfg_remove(aprem, aqrem, cdrem);
>> +}
> ...
>> +/**
>> + * vfio_ap_on_cfg_changed - handles notification of changes to the 
>> host AP
>> + *                configuration.
>> + *
>> + * @new_config_info: the new host AP configuration
>> + * @old_config_info: the previous host AP configuration
>> + */
>> +void vfio_ap_on_cfg_changed(struct ap_config_info *new_config_info,
>> +                struct ap_config_info *old_config_info)
>> +{
>> +    mutex_lock(&matrix_dev->guests_lock);
>> +
>> +    memcpy(&matrix_dev->config_info_prev, old_config_info,
>> +               sizeof(struct ap_config_info));
>> +    memcpy(&matrix_dev->config_info, new_config_info,
>> +           sizeof(struct ap_config_info));
>
> Why are we storing old_config_info in the matrix_dev? It appears to only
> be used within the functions called from right here. Why not just pass it
> as an argument? 

At the time I thought it might be valuable to keep around. I suppose it can
be passed to the functions that need it.

>
>
>> +    vfio_ap_mdev_on_cfg_remove();
>> +    vfio_ap_mdev_on_cfg_add();
>> +
>> +    mutex_unlock(&matrix_dev->guests_lock);
>> +}
>
> Here is an idea to restructure things... consider combining logic from
> vfio_ap_mdev_on_cfg_remove and vfio_ap_mdev_on_cfg_add with
> vfio_ap_on_cfg_changed. This makes vfio_ap_on_cfg_changed() longer but
> it eliminates some duplicated code and gets rid of both
> vfio_ap_mdev_on_cfg_remove and vfio_ap_mdev_on_cfg_add.
> note: Untested... :) 

It seems like a lot of busy work for little gain. I prefer shorter 
functions that
perform a specific task. Since we're solely in the realm of personal 
preferences,
I'm going to leave this function as-is.
diff mbox series

Patch

diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c
index c4f0e28b1e91..711d5f2645b8 100644
--- a/drivers/s390/crypto/vfio_ap_drv.c
+++ b/drivers/s390/crypto/vfio_ap_drv.c
@@ -104,6 +104,8 @@  static struct ap_driver vfio_ap_drv = {
 	.probe = vfio_ap_mdev_probe_queue,
 	.remove = vfio_ap_mdev_remove_queue,
 	.in_use = vfio_ap_mdev_resource_in_use,
+	.on_config_changed = vfio_ap_on_cfg_changed,
+	.on_scan_complete = vfio_ap_on_scan_complete,
 	.ids = ap_queue_ids,
 };
 
@@ -151,7 +153,7 @@  static int vfio_ap_matrix_dev_create(void)
 
 	/* Fill in config info via PQAP(QCI), if available */
 	if (test_facility(12)) {
-		ret = ap_qci(&matrix_dev->info);
+		ret = ap_qci(&matrix_dev->config_info);
 		if (ret)
 			goto matrix_alloc_err;
 	}
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index 02f75c4207b0..3304088d1012 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -333,7 +333,7 @@  static bool vfio_ap_mdev_filter_cdoms(struct ap_matrix_mdev *matrix_mdev)
 
 	bitmap_copy(shadow_adm, matrix_mdev->shadow_apcb.adm, AP_DOMAINS);
 	bitmap_and(matrix_mdev->shadow_apcb.adm, matrix_mdev->matrix.adm,
-		   (unsigned long *)matrix_dev->info.adm, AP_DOMAINS);
+		   (unsigned long *)matrix_dev->config_info.adm, AP_DOMAINS);
 
 	return !bitmap_equal(shadow_adm, matrix_mdev->shadow_apcb.adm,
 			     AP_DOMAINS);
@@ -353,19 +353,15 @@  static bool vfio_ap_mdev_filter_cdoms(struct ap_matrix_mdev *matrix_mdev)
 static bool vfio_ap_mdev_filter_matrix(unsigned long *apm, unsigned long *aqm,
 				       struct ap_matrix_mdev *matrix_mdev)
 {
-	int ret;
 	unsigned long apid, apqi, apqn;
 	DECLARE_BITMAP(shadow_apm, AP_DEVICES);
 	DECLARE_BITMAP(shadow_aqm, AP_DOMAINS);
 	struct vfio_ap_queue *q;
 
-	ret = ap_qci(&matrix_dev->info);
-	if (ret)
-		return false;
-
 	bitmap_copy(shadow_apm, matrix_mdev->shadow_apcb.apm, AP_DEVICES);
 	bitmap_copy(shadow_aqm, matrix_mdev->shadow_apcb.aqm, AP_DOMAINS);
-	vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->shadow_apcb);
+	vfio_ap_matrix_init(&matrix_dev->config_info,
+			    &matrix_mdev->shadow_apcb);
 
 	/*
 	 * Copy the adapters, domains and control domains to the shadow_apcb
@@ -373,9 +369,9 @@  static bool vfio_ap_mdev_filter_matrix(unsigned long *apm, unsigned long *aqm,
 	 * AP configuration.
 	 */
 	bitmap_and(matrix_mdev->shadow_apcb.apm, matrix_mdev->matrix.apm,
-		   (unsigned long *)matrix_dev->info.apm, AP_DEVICES);
+		   (unsigned long *)matrix_dev->config_info.apm, AP_DEVICES);
 	bitmap_and(matrix_mdev->shadow_apcb.aqm, matrix_mdev->matrix.aqm,
-		   (unsigned long *)matrix_dev->info.aqm, AP_DOMAINS);
+		   (unsigned long *)matrix_dev->config_info.aqm, AP_DOMAINS);
 
 	for_each_set_bit_inv(apid, apm, AP_DEVICES) {
 		for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) {
@@ -389,6 +385,7 @@  static bool vfio_ap_mdev_filter_matrix(unsigned long *apm, unsigned long *aqm,
 			 */
 			apqn = AP_MKQID(apid, apqi);
 			q = vfio_ap_mdev_get_queue(matrix_mdev, apqn);
+
 			if (!q || q->reset_rc) {
 				clear_bit_inv(apid,
 					      matrix_mdev->shadow_apcb.apm);
@@ -420,9 +417,10 @@  static int vfio_ap_mdev_probe(struct mdev_device *mdev)
 			    &vfio_ap_matrix_dev_ops);
 
 	matrix_mdev->mdev = mdev;
-	vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix);
+	vfio_ap_matrix_init(&matrix_dev->config_info, &matrix_mdev->matrix);
+	vfio_ap_matrix_init(&matrix_dev->config_info,
+			    &matrix_mdev->shadow_apcb);
 	matrix_mdev->pqap_hook = handle_pqap;
-	vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->shadow_apcb);
 	hash_init(matrix_mdev->qtable.queues);
 	mdev_set_drvdata(mdev, matrix_mdev);
 	mutex_lock(&matrix_dev->guests_lock);
@@ -790,13 +788,17 @@  static void vfio_ap_unlink_apqn_fr_mdev(struct ap_matrix_mdev *matrix_mdev,
 
 	q = vfio_ap_mdev_get_queue(matrix_mdev, AP_MKQID(apid, apqi));
 	/* If the queue is assigned to the matrix mdev, unlink it. */
-	if (q)
+	if (q) {
 		vfio_ap_unlink_queue_fr_mdev(q);
 
-	/* If the queue is assigned to the APCB, store it in @qtable. */
-	if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
-	    test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm))
-		hash_add(qtable->queues, &q->mdev_qnode, q->apqn);
+		/* If the queue is assigned to the APCB, store it in @qtable. */
+		if (qtable) {
+			if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
+			    test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm))
+				hash_add(qtable->queues, &q->mdev_qnode,
+					 q->apqn);
+		}
+	}
 }
 
 /**
@@ -1271,7 +1273,7 @@  static const struct attribute_group *vfio_ap_mdev_attr_groups[] = {
  * @matrix_mdev: a mediated matrix device
  * @kvm: reference to KVM instance
  *
- * Note: The matrix_dev->lock must be taken prior to calling
+ * Note: The matrix_dev->mdevs_lock must be taken prior to calling
  * this function; however, the lock will be temporarily released while the
  * guest's AP configuration is set to avoid a potential lockdep splat.
  * The kvm->lock is taken to set the guest's AP configuration which, under
@@ -1355,7 +1357,7 @@  static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
  * @matrix_mdev: a matrix mediated device
  * @kvm: the pointer to the kvm structure being unset.
  *
- * Note: The matrix_dev->lock must be taken prior to calling
+ * Note: The matrix_dev->mdevs_lock must be taken prior to calling
  * this function; however, the lock will be temporarily released while the
  * guest's AP configuration is cleared to avoid a potential lockdep splat.
  * The kvm->lock is taken to clear the guest's AP configuration which, under
@@ -1708,6 +1710,27 @@  static void vfio_ap_mdev_put_qlocks(struct ap_matrix_mdev *matrix_mdev)
 	mutex_unlock(&matrix_dev->guests_lock);
 }
 
+static bool vfio_ap_mdev_do_filter_matrix(struct ap_matrix_mdev *matrix_mdev,
+					  struct vfio_ap_queue *q)
+{
+	unsigned long apid = AP_QID_CARD(q->apqn);
+	unsigned long apqi = AP_QID_QUEUE(q->apqn);
+
+	/*
+	 * If the queue is being probed because its APID or APQI is in the
+	 * process of being added to the host's AP configuration, then we don't
+	 * want to filter the matrix now as the filtering will be done after
+	 * the driver is notified that the AP bus scan operation has completed
+	 * (see the vfio_ap_on_scan_complete callback function).
+	 */
+	if (test_bit_inv(apid, matrix_mdev->apm_add) ||
+	    test_bit_inv(apqi, matrix_mdev->aqm_add))
+		return false;
+
+
+	return true;
+}
+
 int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
 {
 	struct vfio_ap_queue *q;
@@ -1725,10 +1748,15 @@  int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
 		vfio_ap_mdev_link_queue(matrix_mdev, q);
 		memset(apm, 0, sizeof(apm));
 		set_bit_inv(AP_QID_CARD(q->apqn), apm);
-		if (vfio_ap_mdev_filter_matrix(apm, q->matrix_mdev->matrix.aqm,
-					       q->matrix_mdev))
-			vfio_ap_mdev_hotplug_apcb(q->matrix_mdev);
+
+		if (vfio_ap_mdev_do_filter_matrix(q->matrix_mdev, q)) {
+			if (vfio_ap_mdev_filter_matrix(apm,
+						q->matrix_mdev->matrix.aqm,
+						q->matrix_mdev))
+				vfio_ap_mdev_hotplug_apcb(q->matrix_mdev);
+		}
 	}
+
 	dev_set_drvdata(&apdev->device, q);
 	vfio_ap_mdev_put_qlocks(matrix_mdev);
 
@@ -1783,10 +1811,15 @@  void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
 
 		apid = AP_QID_CARD(q->apqn);
 		apqi = AP_QID_QUEUE(q->apqn);
-		if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
-		    test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm)) {
-			clear_bit_inv(apid, matrix_mdev->shadow_apcb.apm);
-			vfio_ap_mdev_hotplug_apcb(matrix_mdev);
+
+		/*
+		 * If the queue is assigned to the guest's APCB, then remove
+		 * the adapter's APID from the APCB and hot it into the guest.
+		 */
+		if (test_bit_inv(apid, q->matrix_mdev->shadow_apcb.apm) &&
+		    test_bit_inv(apqi, q->matrix_mdev->shadow_apcb.aqm)) {
+			clear_bit_inv(apid, q->matrix_mdev->shadow_apcb.apm);
+			vfio_ap_mdev_hotplug_apcb(q->matrix_mdev);
 		}
 	}
 
@@ -1842,3 +1875,267 @@  int vfio_ap_mdev_resource_in_use(unsigned long *apm, unsigned long *aqm)
 
 	return ret;
 }
+
+/**
+ * vfio_ap_mdev_hot_unplug_cfg - hot unplug the adapters, domains and control
+ *				 domains that have been removed from the host's
+ *				 AP configuration from a guest.
+ *
+ * @guest: the guest
+ * @aprem: the adapters that have been removed from the host's AP configuration
+ * @aqrem: the domains that have been removed from the host's AP configuration
+ * @cdrem: the control domains that have been removed from the host's AP
+ *	   configuration.
+ */
+static void vfio_ap_mdev_hot_unplug_cfg(struct ap_matrix_mdev *matrix_mdev,
+					unsigned long *aprem,
+					unsigned long *aqrem,
+					unsigned long *cdrem)
+{
+	bool do_hotplug = false;
+
+	if (!bitmap_empty(aprem, AP_DEVICES)) {
+		do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.apm,
+					    matrix_mdev->shadow_apcb.apm,
+					    aprem, AP_DEVICES);
+	}
+
+	if (!bitmap_empty(aqrem, AP_DOMAINS)) {
+		do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.aqm,
+					    matrix_mdev->shadow_apcb.aqm,
+					    aqrem, AP_DEVICES);
+	}
+
+	if (!bitmap_empty(cdrem, AP_DOMAINS))
+		do_hotplug |= bitmap_andnot(matrix_mdev->shadow_apcb.adm,
+					    matrix_mdev->shadow_apcb.adm,
+					    cdrem, AP_DOMAINS);
+
+	if (do_hotplug)
+		vfio_ap_mdev_hotplug_apcb(matrix_mdev);
+}
+
+/**
+ * vfio_ap_mdev_cfg_remove - determines which guests are using the adapters,
+ *			     domains and control domains that have been removed
+ *			     from the host AP configuration and unplugs them
+ *			     from those guests.
+ *
+ * @ap_remove:	bitmap specifying which adapters have been removed from the host
+ *		config.
+ * @aq_remove:	bitmap specifying which domains have been removed from the host
+ *		config.
+ * @cd_remove:	bitmap specifying which control domains have been removed from
+ *		the host config.
+ */
+static void vfio_ap_mdev_cfg_remove(unsigned long *ap_remove,
+				    unsigned long *aq_remove,
+				    unsigned long *cd_remove)
+{
+	struct ap_matrix_mdev *matrix_mdev;
+	DECLARE_BITMAP(aprem, AP_DEVICES);
+	DECLARE_BITMAP(aqrem, AP_DOMAINS);
+	DECLARE_BITMAP(cdrem, AP_DOMAINS);
+	int do_ap_remove, do_aq_remove, do_cd_remove;
+
+	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
+		if (!matrix_mdev->kvm)
+			continue;
+
+		mutex_lock(&matrix_mdev->kvm->lock);
+		mutex_lock(&matrix_dev->mdevs_lock);
+
+		do_ap_remove = bitmap_and(aprem, ap_remove,
+					  matrix_mdev->matrix.apm,
+					  AP_DEVICES);
+		do_aq_remove = bitmap_and(aqrem, aq_remove,
+					  matrix_mdev->matrix.aqm,
+					  AP_DOMAINS);
+		do_cd_remove = bitmap_andnot(cdrem, cd_remove,
+					     matrix_mdev->matrix.adm,
+					     AP_DOMAINS);
+
+		if (do_ap_remove || do_aq_remove || do_cd_remove)
+			vfio_ap_mdev_hot_unplug_cfg(matrix_mdev, aprem, aqrem,
+						    cdrem);
+
+		mutex_unlock(&matrix_dev->mdevs_lock);
+		mutex_unlock(&matrix_mdev->kvm->lock);
+	}
+}
+
+/**
+ * vfio_ap_mdev_on_cfg_remove - responds to the removal of adapters, domains and
+ *				control domains from the host AP configuration
+ *				by unplugging them from the guests that are
+ *				using them.
+ */
+static void vfio_ap_mdev_on_cfg_remove(void)
+{
+	int ap_remove, aq_remove, cd_remove;
+	DECLARE_BITMAP(aprem, AP_DEVICES);
+	DECLARE_BITMAP(aqrem, AP_DOMAINS);
+	DECLARE_BITMAP(cdrem, AP_DOMAINS);
+	unsigned long *cur_apm, *cur_aqm, *cur_adm;
+	unsigned long *prev_apm, *prev_aqm, *prev_adm;
+
+	cur_apm = (unsigned long *)matrix_dev->config_info.apm;
+	cur_aqm = (unsigned long *)matrix_dev->config_info.aqm;
+	cur_adm = (unsigned long *)matrix_dev->config_info.adm;
+	prev_apm = (unsigned long *)matrix_dev->config_info_prev.apm;
+	prev_aqm = (unsigned long *)matrix_dev->config_info_prev.aqm;
+	prev_adm = (unsigned long *)matrix_dev->config_info_prev.adm;
+
+	ap_remove = bitmap_andnot(aprem, prev_apm, cur_apm, AP_DEVICES);
+	aq_remove = bitmap_andnot(aqrem, prev_aqm, cur_aqm, AP_DOMAINS);
+	cd_remove = bitmap_andnot(cdrem, prev_adm, cur_adm, AP_DOMAINS);
+
+	if (ap_remove || aq_remove || cd_remove)
+		vfio_ap_mdev_cfg_remove(aprem, aqrem, cdrem);
+}
+
+/**
+ * vfio_ap_mdev_cfg_add - store bitmaps specifying the adapters, domains and
+ *			  control domains that have been added to the host's
+ *			  AP configuration for each matrix mdev to which they
+ *			  are assigned.
+ *
+ * @apm_add: a bitmap specifying the adapters that have been added to the AP
+ *	     configuration.
+ * @aqm_add: a bitmap specifying the domains that have been added to the AP
+ *	     configuration.
+ * @adm_add: a bitmap specifying the control domains that have been added to the
+ *	     AP configuration.
+ */
+static void vfio_ap_mdev_cfg_add(unsigned long *apm_add, unsigned long *aqm_add,
+				 unsigned long *adm_add)
+{
+	struct ap_matrix_mdev *matrix_mdev;
+
+	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
+		bitmap_and(matrix_mdev->apm_add,
+			   matrix_mdev->matrix.apm, apm_add, AP_DEVICES);
+		bitmap_and(matrix_mdev->aqm_add,
+			   matrix_mdev->matrix.aqm, aqm_add, AP_DOMAINS);
+		bitmap_and(matrix_mdev->adm_add,
+			   matrix_mdev->matrix.adm, adm_add, AP_DEVICES);
+	}
+}
+
+/**
+ * vfio_ap_mdev_on_cfg_add - responds to the addition of adapters, domains and
+ *			     control domains to the host AP configuration
+ *			     by updating the bitmaps that specify what adapters,
+ *			     domains and control domains have been added so they
+ *			     can be hot plugged into the guest when the AP bus
+ *			     scan completes (see vfio_ap_on_scan_complete
+ *			     function).
+ */
+static void vfio_ap_mdev_on_cfg_add(void)
+{
+	bool do_add;
+	DECLARE_BITMAP(apm_add, AP_DEVICES);
+	DECLARE_BITMAP(aqm_add, AP_DOMAINS);
+	DECLARE_BITMAP(adm_add, AP_DOMAINS);
+	unsigned long *cur_apm, *cur_aqm, *cur_adm;
+	unsigned long *prev_apm, *prev_aqm, *prev_adm;
+
+	cur_apm = (unsigned long *)matrix_dev->config_info.apm;
+	cur_aqm = (unsigned long *)matrix_dev->config_info.aqm;
+	cur_adm = (unsigned long *)matrix_dev->config_info.adm;
+
+	prev_apm = (unsigned long *)matrix_dev->config_info_prev.apm;
+	prev_aqm = (unsigned long *)matrix_dev->config_info_prev.aqm;
+	prev_adm = (unsigned long *)matrix_dev->config_info_prev.adm;
+
+	do_add = bitmap_andnot(apm_add, cur_apm, prev_apm, AP_DEVICES);
+	do_add |= bitmap_andnot(aqm_add, cur_aqm, prev_aqm, AP_DOMAINS);
+	do_add |= bitmap_andnot(adm_add, cur_adm, prev_adm, AP_DOMAINS);
+
+	if (do_add)
+		vfio_ap_mdev_cfg_add(apm_add, aqm_add, adm_add);
+}
+
+/**
+ * vfio_ap_on_cfg_changed - handles notification of changes to the host AP
+ *			    configuration.
+ *
+ * @new_config_info: the new host AP configuration
+ * @old_config_info: the previous host AP configuration
+ */
+void vfio_ap_on_cfg_changed(struct ap_config_info *new_config_info,
+			    struct ap_config_info *old_config_info)
+{
+	mutex_lock(&matrix_dev->guests_lock);
+
+	memcpy(&matrix_dev->config_info_prev, old_config_info,
+		       sizeof(struct ap_config_info));
+	memcpy(&matrix_dev->config_info, new_config_info,
+	       sizeof(struct ap_config_info));
+	vfio_ap_mdev_on_cfg_remove();
+	vfio_ap_mdev_on_cfg_add();
+
+	mutex_unlock(&matrix_dev->guests_lock);
+}
+
+static void vfio_ap_mdev_hot_plug_cfg(struct ap_matrix_mdev *matrix_mdev)
+{
+//	bool filter_matrix, filter_cdoms, do_hotplug = false;
+	bool do_hotplug = false;
+	bool filter_domains = false;
+	bool filter_adapters = false;
+	DECLARE_BITMAP(apm, AP_DEVICES);
+	DECLARE_BITMAP(aqm, AP_DOMAINS);
+
+	mutex_lock(&matrix_mdev->kvm->lock);
+	mutex_lock(&matrix_dev->mdevs_lock);
+
+	filter_adapters = bitmap_and(apm, matrix_mdev->matrix.apm,
+				     matrix_mdev->apm_add, AP_DEVICES);
+	filter_domains = bitmap_and(aqm, matrix_mdev->matrix.aqm,
+				    matrix_mdev->aqm_add, AP_DOMAINS);
+
+	if (filter_adapters && filter_domains)
+		do_hotplug |= vfio_ap_mdev_filter_matrix(apm, aqm, matrix_mdev);
+	else if (filter_adapters)
+		do_hotplug |=
+			vfio_ap_mdev_filter_matrix(apm,
+						   matrix_mdev->shadow_apcb.aqm,
+						   matrix_mdev);
+	else
+		do_hotplug |=
+			vfio_ap_mdev_filter_matrix(matrix_mdev->shadow_apcb.apm,
+						   aqm, matrix_mdev);
+
+	if (bitmap_intersects(matrix_mdev->matrix.adm, matrix_mdev->adm_add,
+			      AP_DOMAINS))
+		do_hotplug |= vfio_ap_mdev_filter_cdoms(matrix_mdev);
+
+	if (do_hotplug)
+		vfio_ap_mdev_hotplug_apcb(matrix_mdev);
+
+	mutex_unlock(&matrix_dev->mdevs_lock);
+	mutex_unlock(&matrix_mdev->kvm->lock);
+}
+
+void vfio_ap_on_scan_complete(struct ap_config_info *new_config_info,
+			      struct ap_config_info *old_config_info)
+{
+	struct ap_matrix_mdev *matrix_mdev;
+
+	mutex_lock(&matrix_dev->guests_lock);
+
+	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
+		if (bitmap_empty(matrix_mdev->apm_add, AP_DEVICES) &&
+		    bitmap_empty(matrix_mdev->aqm_add, AP_DOMAINS) &&
+		    bitmap_empty(matrix_mdev->adm_add, AP_DOMAINS))
+			continue;
+
+		vfio_ap_mdev_hot_plug_cfg(matrix_mdev);
+		bitmap_clear(matrix_mdev->apm_add, 0, AP_DEVICES);
+		bitmap_clear(matrix_mdev->aqm_add, 0, AP_DOMAINS);
+		bitmap_clear(matrix_mdev->adm_add, 0, AP_DOMAINS);
+	}
+
+	mutex_unlock(&matrix_dev->guests_lock);
+}
diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h
index e30f171f89ec..a7fe4a3cf896 100644
--- a/drivers/s390/crypto/vfio_ap_private.h
+++ b/drivers/s390/crypto/vfio_ap_private.h
@@ -31,7 +31,9 @@ 
  *
  * @device:	generic device structure associated with the AP matrix device
  * @available_instances: number of mediated matrix devices that can be created
- * @info:	the struct containing the output from the PQAP(QCI) instruction
+ * @config_info: the object containing the current AP configuration for the host
+ * @config_info_prev: the object containing the previous AP configuration for
+ *		      Gthe host
  * @mdev_list:	the list of mediated matrix devices created
  * @mdevs_lock:	mutex for locking the ap_matrix_mdev devices under the control
  *		of the vfio_ap device driver. This lock will be taken every time
@@ -47,7 +49,8 @@ 
 struct ap_matrix_dev {
 	struct device device;
 	atomic_t available_instances;
-	struct ap_config_info info;
+	struct ap_config_info config_info;
+	struct ap_config_info config_info_prev;
 	struct list_head mdev_list;
 	struct mutex mdevs_lock;
 	struct ap_driver  *vfio_ap_drv;
@@ -118,6 +121,9 @@  struct ap_matrix_mdev {
 	crypto_hook pqap_hook;
 	struct mdev_device *mdev;
 	struct ap_queue_table qtable;
+	DECLARE_BITMAP(apm_add, AP_DEVICES);
+	DECLARE_BITMAP(aqm_add, AP_DOMAINS);
+	DECLARE_BITMAP(adm_add, AP_DOMAINS);
 };
 
 /**
@@ -148,4 +154,9 @@  void vfio_ap_mdev_remove_queue(struct ap_device *queue);
 
 int vfio_ap_mdev_resource_in_use(unsigned long *apm, unsigned long *aqm);
 
+void vfio_ap_on_cfg_changed(struct ap_config_info *new_config_info,
+			    struct ap_config_info *old_config_info);
+void vfio_ap_on_scan_complete(struct ap_config_info *new_config_info,
+			      struct ap_config_info *old_config_info);
+
 #endif /* _VFIO_AP_PRIVATE_H_ */