提交 a7b1868a 编写于 作者: H Harald Freudenberger 提交者: Martin Schwidefsky

s390/zcrypt: rework ap scan bus code

Rework of the AP bus scan code. The ap_scan_bus() function
is large, so this patch splits the code by introducing a new
new function _ap_scan_bus_adapter() which deals with just
one adapter and thus reduces the scan function code complexity.

Now the AP bus scan can handle a type change of an crypto
adapter on the fly (e.g. from CEX5 to CEX6). This may be
the case with newer versions of zVM where the card may
be pure virtual and a type change is just one click.
However a type or function change requires to unregister
all queue devices and the card device and re-register them.

Comments around the AP bus scan code have been added and/or
improved to provide some hopefully useful hints about what
the code is actually doing.
Signed-off-by: NHarald Freudenberger <freude@linux.ibm.com>
Signed-off-by: NMartin Schwidefsky <schwidefsky@de.ibm.com>
上级 42a87d41
......@@ -299,7 +299,7 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type,
ap_max_domain_id = 15;
switch (*device_type) {
/* For CEX2 and CEX3 the available functions
* are not refrected by the facilities bits.
* are not reflected by the facilities bits.
* Instead it is coded into the type. So here
* modify the function bits based on the type.
*/
......@@ -1317,7 +1317,7 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func)
}
/*
* helper function to be used with bus_find_dev
* Helper function to be used with bus_find_dev
* matches for the card device with the given id
*/
static int __match_card_device_with_id(struct device *dev, void *data)
......@@ -1325,7 +1325,8 @@ static int __match_card_device_with_id(struct device *dev, void *data)
return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data;
}
/* helper function to be used with bus_find_dev
/*
* Helper function to be used with bus_find_dev
* matches for the queue device with a given qid
*/
static int __match_queue_device_with_qid(struct device *dev, void *data)
......@@ -1333,51 +1334,80 @@ static int __match_queue_device_with_qid(struct device *dev, void *data)
return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data;
}
/**
* ap_scan_bus(): Scan the AP bus for new devices
* Runs periodically, workqueue timer (ap_config_time)
/*
* Helper function for ap_scan_bus().
* Does the scan bus job for the given adapter id.
*/
static void ap_scan_bus(struct work_struct *unused)
static void _ap_scan_bus_adapter(int id)
{
struct ap_queue *aq;
ap_qid_t qid;
unsigned int func;
struct ap_card *ac;
struct device *dev;
ap_qid_t qid;
int comp_type, depth = 0, type = 0;
unsigned int func = 0;
int rc, id, dom, borked, domains, defdomdevs = 0;
AP_DBF(DBF_DEBUG, "%s running\n", __func__);
ap_query_configuration(ap_configuration);
ap_select_domain();
struct ap_queue *aq;
int rc, dom, depth, type, comp_type, borked;
for (id = 0; id < AP_DEVICES; id++) {
/* check if device is registered */
/* check if there is a card device registered with this id */
dev = bus_find_device(&ap_bus_type, NULL,
(void *)(long) id,
__match_card_device_with_id);
ac = dev ? to_ap_card(dev) : NULL;
if (!ap_test_config_card_id(id)) {
if (dev) {
/* Card device has been removed from
* configuration, remove the belonging
* queue devices.
/* Card device has been removed from configuration */
bus_for_each_dev(&ap_bus_type, NULL,
(void *)(long) id,
__ap_queue_devices_with_id_unregister);
device_unregister(dev);
put_device(dev);
}
return;
}
/*
* This card id is enabled in the configuration. If we already have
* a card device with this id, check if type and functions are still
* the very same. Also verify that at least one queue is available.
*/
if (ac) {
/* find the first valid queue */
for (dom = 0; dom < AP_DOMAINS; dom++) {
qid = AP_MKQID(id, dom);
if (ap_query_queue(qid, &depth, &type, &func) == 0)
break;
}
borked = 0;
if (dom >= AP_DOMAINS) {
/* no accessible queue on this card */
borked = 1;
} else if (ac->raw_hwtype != type) {
/* card type has changed */
AP_DBF(DBF_INFO, "card=%02x type changed.\n", id);
borked = 1;
} else if (ac->functions != func) {
/* card functions have changed */
AP_DBF(DBF_INFO, "card=%02x functions changed.\n", id);
borked = 1;
}
if (borked) {
/* unregister card device and associated queues */
bus_for_each_dev(&ap_bus_type, NULL,
(void *)(long) id,
__ap_queue_devices_with_id_unregister);
/* now remove the card device */
device_unregister(dev);
put_device(dev);
/* go back if there is no valid queue on this card */
if (dom >= AP_DOMAINS)
return;
ac = NULL;
}
continue;
}
/* According to the configuration there should be a card
* device, so check if there is at least one valid queue
* and maybe create queue devices and the card device.
/*
* Go through all possible queue ids. Check and maybe create or release
* queue devices for this card. If there exists no card device yet,
* create a card device also.
*/
domains = 0;
for (dom = 0; dom < AP_DOMAINS; dom++) {
qid = AP_MKQID(id, dom);
dev = bus_find_device(&ap_bus_type, NULL,
......@@ -1394,25 +1424,21 @@ static void ap_scan_bus(struct work_struct *unused)
}
continue;
}
/* try to fetch infos about this queue */
rc = ap_query_queue(qid, &depth, &type, &func);
if (dev) {
if (rc == -ENODEV)
borked = 1;
else {
spin_lock_bh(&aq->lock);
if (rc == -ENODEV ||
/* adapter reconfiguration */
(ac && ac->functions != func))
aq->state = AP_STATE_BORKED;
borked = aq->state == AP_STATE_BORKED;
spin_unlock_bh(&aq->lock);
}
if (borked) /* Remove broken device */
device_unregister(dev);
put_device(dev);
if (!borked) {
domains++;
if (dom == ap_domain_index)
defdomdevs++;
continue;
}
}
if (rc)
continue;
/* a new queue device is needed, check out comp type */
......@@ -1421,15 +1447,13 @@ static void ap_scan_bus(struct work_struct *unused)
continue;
/* maybe a card device needs to be created first */
if (!ac) {
ac = ap_card_create(id, depth, type,
comp_type, func);
ac = ap_card_create(id, depth, type, comp_type, func);
if (!ac)
continue;
ac->ap_dev.device.bus = &ap_bus_type;
ac->ap_dev.device.parent = ap_root_device;
dev_set_name(&ac->ap_dev.device,
"card%02x", id);
/* Register card with AP bus */
dev_set_name(&ac->ap_dev.device, "card%02x", id);
/* Register card device with AP bus */
rc = device_register(&ac->ap_dev.device);
if (rc) {
put_device(&ac->ap_dev.device);
......@@ -1446,30 +1470,49 @@ static void ap_scan_bus(struct work_struct *unused)
aq->card = ac;
aq->ap_dev.device.bus = &ap_bus_type;
aq->ap_dev.device.parent = &ac->ap_dev.device;
dev_set_name(&aq->ap_dev.device,
"%02x.%04x", id, dom);
/* Register device */
dev_set_name(&aq->ap_dev.device, "%02x.%04x", id, dom);
/* Register queue device */
rc = device_register(&aq->ap_dev.device);
if (rc) {
put_device(&aq->ap_dev.device);
continue;
}
domains++;
if (dom == ap_domain_index)
defdomdevs++;
} /* end domain loop */
if (ac) {
/* remove card dev if there are no queue devices */
if (!domains)
device_unregister(&ac->ap_dev.device);
if (ac)
put_device(&ac->ap_dev.device);
}
} /* end device loop */
}
/**
* 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;
if (ap_domain_index >= 0 && defdomdevs < 1)
AP_DBF(DBF_DEBUG, "%s running\n", __func__);
ap_query_configuration(ap_configuration);
ap_select_domain();
/* loop over all possible adapters */
for (id = 0; id < AP_DEVICES; id++)
_ap_scan_bus_adapter(id);
/* check if there is at least one queue available with default domain */
if (ap_domain_index >= 0) {
struct device *dev =
bus_find_device(&ap_bus_type, NULL,
(void *)(long) ap_domain_index,
__match_queue_device_with_qid);
if (dev)
put_device(dev);
else
AP_DBF(DBF_INFO,
"no queue device with default domain %d available\n",
ap_domain_index);
}
mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册