@@ -73,8 +73,12 @@ struct ap_perms ap_perms;
EXPORT_SYMBOL(ap_perms);
DEFINE_MUTEX(ap_perms_mutex);
EXPORT_SYMBOL(ap_perms_mutex);
+DEFINE_MUTEX(ap_config_lock);
+
+/* current and old qci info structs */
+static struct ap_config_info *ap_config_info;
+static struct ap_config_info *ap_old_config_info;
-static struct ap_config_info *ap_configuration;
static bool initialised;
/*
@@ -183,8 +187,8 @@ static int ap_apft_available(void)
*/
static inline int ap_qact_available(void)
{
- if (ap_configuration)
- return ap_configuration->qact;
+ if (ap_config_info)
+ return ap_config_info->qact;
return 0;
}
@@ -213,13 +217,15 @@ static void ap_init_configuration(void)
if (!ap_configuration_available())
return;
- ap_configuration = kzalloc(sizeof(*ap_configuration), GFP_KERNEL);
- if (!ap_configuration)
- return;
- if (ap_query_configuration(ap_configuration) != 0) {
- kfree(ap_configuration);
- ap_configuration = NULL;
+ /* allocate current qci info struct */
+ ap_config_info = kzalloc(sizeof(*ap_config_info), GFP_KERNEL);
+ if (!ap_config_info)
return;
+
+ /* fetch qci info into the current qci info struct */
+ if (ap_query_configuration(ap_config_info)) {
+ kfree(ap_config_info);
+ ap_config_info = NULL;
}
}
@@ -242,10 +248,10 @@ static inline int ap_test_config(unsigned int *field, unsigned int nr)
*/
static inline int ap_test_config_card_id(unsigned int id)
{
- if (!ap_configuration) /* QCI not supported */
- /* only ids 0...3F may be probed */
+ if (!ap_config_info)
+ /* QCI not available, only ids 0...3F may be probed */
return id < 0x40 ? 1 : 0;
- return ap_test_config(ap_configuration->apm, id);
+ return ap_test_config(ap_config_info->apm, id);
}
/*
@@ -259,9 +265,9 @@ static inline int ap_test_config_card_id(unsigned int id)
*/
int ap_test_config_usage_domain(unsigned int domain)
{
- if (!ap_configuration) /* QCI not supported */
+ if (!ap_config_info) /* QCI not supported */
return domain < 16;
- return ap_test_config(ap_configuration->aqm, domain);
+ return ap_test_config(ap_config_info->aqm, domain);
}
EXPORT_SYMBOL(ap_test_config_usage_domain);
@@ -275,9 +281,9 @@ EXPORT_SYMBOL(ap_test_config_usage_domain);
*/
int ap_test_config_ctrl_domain(unsigned int domain)
{
- if (!ap_configuration) /* QCI not supported */
+ if (!ap_config_info) /* QCI not supported */
return 0;
- return ap_test_config(ap_configuration->adm, domain);
+ return ap_test_config(ap_config_info->adm, domain);
}
EXPORT_SYMBOL(ap_test_config_ctrl_domain);
@@ -953,45 +959,45 @@ static BUS_ATTR_RW(ap_domain);
static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf)
{
- if (!ap_configuration) /* QCI not supported */
- return scnprintf(buf, PAGE_SIZE, "not supported\n");
+ if (!ap_config_info) /* QCI not supported */
+ return snprintf(buf, PAGE_SIZE, "not supported\n");
- return scnprintf(buf, PAGE_SIZE,
- "0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
- ap_configuration->adm[0], ap_configuration->adm[1],
- ap_configuration->adm[2], ap_configuration->adm[3],
- ap_configuration->adm[4], ap_configuration->adm[5],
- ap_configuration->adm[6], ap_configuration->adm[7]);
+ return snprintf(buf, PAGE_SIZE,
+ "0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
+ ap_config_info->adm[0], ap_config_info->adm[1],
+ ap_config_info->adm[2], ap_config_info->adm[3],
+ ap_config_info->adm[4], ap_config_info->adm[5],
+ ap_config_info->adm[6], ap_config_info->adm[7]);
}
static BUS_ATTR_RO(ap_control_domain_mask);
static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf)
{
- if (!ap_configuration) /* QCI not supported */
- return scnprintf(buf, PAGE_SIZE, "not supported\n");
+ if (!ap_config_info) /* QCI not supported */
+ return snprintf(buf, PAGE_SIZE, "not supported\n");
- return scnprintf(buf, PAGE_SIZE,
- "0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
- ap_configuration->aqm[0], ap_configuration->aqm[1],
- ap_configuration->aqm[2], ap_configuration->aqm[3],
- ap_configuration->aqm[4], ap_configuration->aqm[5],
- ap_configuration->aqm[6], ap_configuration->aqm[7]);
+ return snprintf(buf, PAGE_SIZE,
+ "0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
+ ap_config_info->aqm[0], ap_config_info->aqm[1],
+ ap_config_info->aqm[2], ap_config_info->aqm[3],
+ ap_config_info->aqm[4], ap_config_info->aqm[5],
+ ap_config_info->aqm[6], ap_config_info->aqm[7]);
}
static BUS_ATTR_RO(ap_usage_domain_mask);
static ssize_t ap_adapter_mask_show(struct bus_type *bus, char *buf)
{
- if (!ap_configuration) /* QCI not supported */
- return scnprintf(buf, PAGE_SIZE, "not supported\n");
+ if (!ap_config_info) /* QCI not supported */
+ return snprintf(buf, PAGE_SIZE, "not supported\n");
- return scnprintf(buf, PAGE_SIZE,
- "0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
- ap_configuration->apm[0], ap_configuration->apm[1],
- ap_configuration->apm[2], ap_configuration->apm[3],
- ap_configuration->apm[4], ap_configuration->apm[5],
- ap_configuration->apm[6], ap_configuration->apm[7]);
+ return snprintf(buf, PAGE_SIZE,
+ "0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
+ ap_config_info->apm[0], ap_config_info->apm[1],
+ ap_config_info->apm[2], ap_config_info->apm[3],
+ ap_config_info->apm[4], ap_config_info->apm[5],
+ ap_config_info->apm[6], ap_config_info->apm[7]);
}
static BUS_ATTR_RO(ap_adapter_mask);
@@ -1079,7 +1085,7 @@ static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf)
{
int max_domain_id;
- if (ap_configuration)
+ if (ap_config_info)
max_domain_id = ap_max_domain_id ? : -1;
else
max_domain_id = 15;
@@ -1373,6 +1379,50 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func)
return comp_type;
}
+/* 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_config_info,
+ ap_old_config_info);
+ 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_config_info,
+ ap_old_config_info);
+ 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 to be used with bus_find_dev
* matches for the card device with the given id
@@ -1555,23 +1605,57 @@ static void _ap_scan_bus_adapter(int id)
put_device(&ac->ap_dev.device);
}
+static int ap_config_changed(void)
+{
+ int cfg_chg = 0;
+
+ if (ap_config_info) {
+ if (!ap_old_config_info) {
+ ap_old_config_info = kzalloc(
+ sizeof(*ap_old_config_info), GFP_KERNEL);
+ if (!ap_old_config_info)
+ return 0;
+ } else {
+ memcpy(ap_old_config_info, ap_config_info,
+ sizeof(struct ap_config_info));
+ }
+ ap_query_configuration(ap_config_info);
+ cfg_chg = memcmp(ap_config_info,
+ ap_old_config_info,
+ 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 id;
+ int id, config_changed = 0;
AP_DBF(DBF_DEBUG, "%s running\n", __func__);
- ap_query_configuration(ap_configuration);
+ mutex_lock(&ap_config_lock);
+
+ /* config change notify */
+ config_changed = ap_config_changed();
+ if (config_changed)
+ notify_config_changed();
ap_select_domain();
/* loop over all possible adapters */
for (id = 0; id < AP_DEVICES; id++)
_ap_scan_bus_adapter(id);
+ /* scan complete notify */
+ if (config_changed)
+ notify_scan_complete();
+
+ mutex_unlock(&ap_config_lock);
+
/* check if there is at least one queue available with default domain */
if (ap_domain_index >= 0) {
struct device *dev =
@@ -1654,7 +1738,7 @@ static int __init ap_module_init(void)
/* Get AP configuration data if available */
ap_init_configuration();
- if (ap_configuration)
+ if (ap_config_info)
max_domain_id =
ap_max_domain_id ? ap_max_domain_id : AP_DOMAINS - 1;
else
@@ -1723,7 +1807,8 @@ static int __init ap_module_init(void)
out:
if (ap_using_interrupts())
unregister_adapter_interrupt(&ap_airq);
- kfree(ap_configuration);
+ kfree(ap_config_info);
+ kfree(ap_old_config_info);
return rc;
}
device_initcall(ap_module_init);
@@ -137,6 +137,18 @@ struct ap_driver {
int (*probe)(struct ap_device *);
void (*remove)(struct ap_device *);
bool (*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)