static DECLARE_COMPLETION(ap_init_apqn_bindings_complete);
 
 static struct ap_config_info *ap_qci_info;
+static struct ap_config_info *ap_qci_info_old;
 
 /*
  * AP bus related debug feature things.
        ap_qci_info = kzalloc(sizeof(*ap_qci_info), GFP_KERNEL);
        if (!ap_qci_info)
                return;
+       ap_qci_info_old = kzalloc(sizeof(*ap_qci_info_old), GFP_KERNEL);
+       if (!ap_qci_info_old)
+               return;
        if (ap_fetch_qci_info(ap_qci_info) != 0) {
                kfree(ap_qci_info);
+               kfree(ap_qci_info_old);
                ap_qci_info = NULL;
+               ap_qci_info_old = NULL;
                return;
        }
        AP_DBF_INFO("%s successful fetched initial qci info\n", __func__);
                                    __func__, ap_max_domain_id);
                }
        }
+
+       memcpy(ap_qci_info_old, ap_qci_info, sizeof(*ap_qci_info));
 }
 
 /*
                && AP_QID_QUEUE(to_ap_queue(dev)->qid) == (int)(long) data;
 }
 
+/* Helper function for notify_config_changed */
+static int __drv_notify_config_changed(struct device_driver *drv, void *data)
+{
+       struct ap_driver *ap_drv = to_ap_drv(drv);
+
+       if (try_module_get(drv->owner)) {
+               if (ap_drv->on_config_changed)
+                       ap_drv->on_config_changed(ap_qci_info, ap_qci_info_old);
+               module_put(drv->owner);
+       }
+
+       return 0;
+}
+
+/* Notify all drivers about an qci config change */
+static inline void notify_config_changed(void)
+{
+       bus_for_each_drv(&ap_bus_type, NULL, NULL,
+                        __drv_notify_config_changed);
+}
+
+/* Helper function for notify_scan_complete */
+static int __drv_notify_scan_complete(struct device_driver *drv, void *data)
+{
+       struct ap_driver *ap_drv = to_ap_drv(drv);
+
+       if (try_module_get(drv->owner)) {
+               if (ap_drv->on_scan_complete)
+                       ap_drv->on_scan_complete(ap_qci_info,
+                                                ap_qci_info_old);
+               module_put(drv->owner);
+       }
+
+       return 0;
+}
+
+/* Notify all drivers about bus scan complete */
+static inline void notify_scan_complete(void)
+{
+       bus_for_each_drv(&ap_bus_type, NULL, NULL,
+                        __drv_notify_scan_complete);
+}
+
 /*
  * Helper function for ap_scan_bus().
  * Remove card device and associated queue devices.
        put_device(&ac->ap_dev.device);
 }
 
+/**
+ * ap_get_configuration - get the host AP configuration
+ *
+ * Stores the host AP configuration information returned from the previous call
+ * to Query Configuration Information (QCI), then retrieves and stores the
+ * current AP configuration returned from QCI.
+ *
+ * Return: true if the host AP configuration changed between calls to QCI;
+ * otherwise, return false.
+ */
+static bool ap_get_configuration(void)
+{
+       memcpy(ap_qci_info_old, ap_qci_info, sizeof(*ap_qci_info));
+       ap_fetch_qci_info(ap_qci_info);
+
+       return memcmp(ap_qci_info, ap_qci_info_old,
+                     sizeof(struct ap_config_info)) != 0;
+}
+
 /**
  * ap_scan_bus(): Scan the AP bus for new devices
  * Runs periodically, workqueue timer (ap_config_time)
  */
 static void ap_scan_bus(struct work_struct *unused)
 {
-       int ap;
+       int ap, config_changed = 0;
 
-       ap_fetch_qci_info(ap_qci_info);
+       /* config change notify */
+       config_changed = ap_get_configuration();
+       if (config_changed)
+               notify_config_changed();
        ap_select_domain();
 
        AP_DBF_DBG("%s running\n", __func__);
        for (ap = 0; ap <= ap_max_adapter_id; ap++)
                ap_scan_adapter(ap);
 
+       /* scan complete notify */
+       if (config_changed)
+               notify_scan_complete();
+
        /* check if there is at least one queue available with default domain */
        if (ap_domain_index >= 0) {
                struct device *dev =
 
        int (*probe)(struct ap_device *);
        void (*remove)(struct ap_device *);
        int (*in_use)(unsigned long *apm, unsigned long *aqm);
+       /*
+        * Called at the start of the ap bus scan function when
+        * the crypto config information (qci) has changed.
+        */
+       void (*on_config_changed)(struct ap_config_info *new_config_info,
+                                 struct ap_config_info *old_config_info);
+       /*
+        * Called at the end of the ap bus scan function when
+        * the crypto config information (qci) has changed.
+        */
+       void (*on_scan_complete)(struct ap_config_info *new_config_info,
+                                struct ap_config_info *old_config_info);
 };
 
 #define to_ap_drv(x) container_of((x), struct ap_driver, driver)