@@ -82,6 +82,7 @@ static atomic64_t ap_scan_bus_count;
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.
@@ -1579,6 +1580,52 @@ static int __match_queue_device_with_queue_id(struct device *dev, const void *da
&& 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.
@@ -1857,15 +1904,51 @@ static inline void ap_scan_adapter(int ap)
put_device(&ac->ap_dev.device);
}
+/*
+ * ap_get_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.
+ *
+ * Returns true if the host AP configuration changed between calls to QCI;
+ * otherwise, returns false.
+ */
+static bool ap_get_configuration(void)
+{
+ bool cfg_chg = false;
+
+ if (ap_qci_info) {
+ if (!ap_qci_info_old) {
+ ap_qci_info_old = kzalloc(sizeof(*ap_qci_info_old),
+ GFP_KERNEL);
+ if (!ap_qci_info_old)
+ return false;
+ } else {
+ memcpy(ap_qci_info_old, ap_qci_info,
+ sizeof(struct ap_config_info));
+ }
+ ap_fetch_qci_info(ap_qci_info);
+ cfg_chg = memcmp(ap_qci_info,
+ ap_qci_info_old,
+ sizeof(struct ap_config_info)) != 0;
+ }
+
+ return cfg_chg;
+}
+
/**
* 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__);
@@ -1874,6 +1957,10 @@ static void ap_scan_bus(struct work_struct *unused)
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 =
@@ -146,6 +146,18 @@ struct ap_driver {
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)