matrix->adm_max = info->apxa ? info->Nd : 15;
 }
 
+static void vfio_ap_mdev_filter_cdoms(struct ap_matrix_mdev *matrix_mdev)
+{
+       bitmap_and(matrix_mdev->shadow_apcb.adm, matrix_mdev->matrix.adm,
+                  (unsigned long *)matrix_dev->info.adm, AP_DOMAINS);
+}
+
+/*
+ * vfio_ap_mdev_filter_matrix - filter the APQNs assigned to the matrix mdev
+ *                             to ensure no queue devices are passed through to
+ *                             the guest that are not bound to the vfio_ap
+ *                             device driver.
+ *
+ * @matrix_mdev: the matrix mdev whose matrix is to be filtered.
+ *
+ * Note: If an APQN referencing a queue device that is not bound to the vfio_ap
+ *      driver, its APID will be filtered from the guest's APCB. The matrix
+ *      structure precludes filtering an individual APQN, so its APID will be
+ *      filtered.
+ */
+static void vfio_ap_mdev_filter_matrix(unsigned long *apm, unsigned long *aqm,
+                                      struct ap_matrix_mdev *matrix_mdev)
+{
+       int ret;
+       unsigned long apid, apqi, apqn;
+
+       ret = ap_qci(&matrix_dev->info);
+       if (ret)
+               return;
+
+       vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->shadow_apcb);
+
+       /*
+        * Copy the adapters, domains and control domains to the shadow_apcb
+        * from the matrix mdev, but only those that are assigned to the host's
+        * AP configuration.
+        */
+       bitmap_and(matrix_mdev->shadow_apcb.apm, matrix_mdev->matrix.apm,
+                  (unsigned long *)matrix_dev->info.apm, AP_DEVICES);
+       bitmap_and(matrix_mdev->shadow_apcb.aqm, matrix_mdev->matrix.aqm,
+                  (unsigned long *)matrix_dev->info.aqm, AP_DOMAINS);
+
+       for_each_set_bit_inv(apid, apm, AP_DEVICES) {
+               for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) {
+                       /*
+                        * If the APQN is not bound to the vfio_ap device
+                        * driver, then we can't assign it to the guest's
+                        * AP configuration. The AP architecture won't
+                        * allow filtering of a single APQN, so let's filter
+                        * the APID since an adapter represents a physical
+                        * hardware device.
+                        */
+                       apqn = AP_MKQID(apid, apqi);
+
+                       if (!vfio_ap_mdev_get_queue(matrix_mdev, apqn)) {
+                               clear_bit_inv(apid,
+                                             matrix_mdev->shadow_apcb.apm);
+                               break;
+                       }
+               }
+       }
+}
+
 static int vfio_ap_mdev_probe(struct mdev_device *mdev)
 {
        struct ap_matrix_mdev *matrix_mdev;
 {
        int ret;
        unsigned long apid;
+       DECLARE_BITMAP(apm_delta, AP_DEVICES);
+
        struct ap_matrix_mdev *matrix_mdev = dev_get_drvdata(dev);
 
        mutex_lock(&matrix_dev->lock);
                goto share_err;
 
        vfio_ap_mdev_link_adapter(matrix_mdev, apid);
+       memset(apm_delta, 0, sizeof(apm_delta));
+       set_bit_inv(apid, apm_delta);
+       vfio_ap_mdev_filter_matrix(apm_delta,
+                                  matrix_mdev->matrix.aqm, matrix_mdev);
        ret = count;
        goto done;
 
 
        clear_bit_inv((unsigned long)apid, matrix_mdev->matrix.apm);
        vfio_ap_mdev_unlink_adapter(matrix_mdev, apid);
+
+       if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm))
+               clear_bit_inv(apid, matrix_mdev->shadow_apcb.apm);
+
        ret = count;
 done:
        mutex_unlock(&matrix_dev->lock);
 {
        int ret;
        unsigned long apqi;
+       DECLARE_BITMAP(aqm_delta, AP_DOMAINS);
        struct ap_matrix_mdev *matrix_mdev = dev_get_drvdata(dev);
        unsigned long max_apqi = matrix_mdev->matrix.aqm_max;
 
                goto share_err;
 
        vfio_ap_mdev_link_domain(matrix_mdev, apqi);
+       memset(aqm_delta, 0, sizeof(aqm_delta));
+       set_bit_inv(apqi, aqm_delta);
+       vfio_ap_mdev_filter_matrix(matrix_mdev->matrix.apm, aqm_delta,
+                                  matrix_mdev);
        ret = count;
        goto done;
 
 
        clear_bit_inv((unsigned long)apqi, matrix_mdev->matrix.aqm);
        vfio_ap_mdev_unlink_domain(matrix_mdev, apqi);
+
+       if (test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm))
+               clear_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm);
+
        ret = count;
 
 done:
         * number of control domains that can be assigned.
         */
        set_bit_inv(id, matrix_mdev->matrix.adm);
+       vfio_ap_mdev_filter_cdoms(matrix_mdev);
        ret = count;
 done:
        mutex_unlock(&matrix_dev->lock);
        }
 
        clear_bit_inv(domid, matrix_mdev->matrix.adm);
+
+       if (test_bit_inv(domid, matrix_mdev->shadow_apcb.adm))
+               clear_bit_inv(domid, matrix_mdev->shadow_apcb.adm);
+
        ret = count;
 done:
        mutex_unlock(&matrix_dev->lock);
 
                kvm_get_kvm(kvm);
                matrix_mdev->kvm = kvm;
-               memcpy(&matrix_mdev->shadow_apcb, &matrix_mdev->matrix,
-                      sizeof(struct ap_matrix));
                kvm_arch_crypto_set_masks(kvm, matrix_mdev->shadow_apcb.apm,
                                          matrix_mdev->shadow_apcb.aqm,
                                          matrix_mdev->shadow_apcb.adm);
        q->apqn = to_ap_queue(&apdev->device)->qid;
        q->saved_isc = VFIO_AP_ISC_INVALID;
        vfio_ap_queue_link_mdev(q);
+       if (q->matrix_mdev) {
+               vfio_ap_mdev_filter_matrix(q->matrix_mdev->matrix.apm,
+                                          q->matrix_mdev->matrix.aqm,
+                                          q->matrix_mdev);
+       }
        dev_set_drvdata(&apdev->device, q);
        mutex_unlock(&matrix_dev->lock);
 
 
 void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
 {
+       unsigned long apid;
        struct vfio_ap_queue *q;
 
        mutex_lock(&matrix_dev->lock);
        sysfs_remove_group(&apdev->device.kobj, &vfio_queue_attr_group);
        q = dev_get_drvdata(&apdev->device);
 
-       if (q->matrix_mdev)
+       if (q->matrix_mdev) {
                vfio_ap_unlink_queue_fr_mdev(q);
 
+               apid = AP_QID_CARD(q->apqn);
+               if (test_bit_inv(apid, q->matrix_mdev->shadow_apcb.apm))
+                       clear_bit_inv(apid, q->matrix_mdev->shadow_apcb.apm);
+       }
+
        vfio_ap_mdev_reset_queue(q, 1);
        dev_set_drvdata(&apdev->device, NULL);
        kfree(q);