in rio.c [2064:2131]
int rio_init_mports(void)
{
struct rio_mport *port;
struct rio_disc_work *work;
int n = 0;
if (!next_portid)
return -ENODEV;
/*
* First, run enumerations and check if we need to perform discovery
* on any of the registered mports.
*/
mutex_lock(&rio_mport_list_lock);
list_for_each_entry(port, &rio_mports, node) {
if (port->host_deviceid >= 0) {
if (port->nscan && try_module_get(port->nscan->owner)) {
port->nscan->enumerate(port, 0);
module_put(port->nscan->owner);
}
} else
n++;
}
mutex_unlock(&rio_mport_list_lock);
if (!n)
goto no_disc;
/*
* If we have mports that require discovery schedule a discovery work
* for each of them. If the code below fails to allocate needed
* resources, exit without error to keep results of enumeration
* process (if any).
* TODO: Implement restart of discovery process for all or
* individual discovering mports.
*/
rio_wq = alloc_workqueue("riodisc", 0, 0);
if (!rio_wq) {
pr_err("RIO: unable allocate rio_wq\n");
goto no_disc;
}
work = kcalloc(n, sizeof *work, GFP_KERNEL);
if (!work) {
destroy_workqueue(rio_wq);
goto no_disc;
}
n = 0;
mutex_lock(&rio_mport_list_lock);
list_for_each_entry(port, &rio_mports, node) {
if (port->host_deviceid < 0 && port->nscan) {
work[n].mport = port;
INIT_WORK(&work[n].work, disc_work_handler);
queue_work(rio_wq, &work[n].work);
n++;
}
}
flush_workqueue(rio_wq);
mutex_unlock(&rio_mport_list_lock);
pr_debug("RIO: destroy discovery workqueue\n");
destroy_workqueue(rio_wq);
kfree(work);
no_disc:
return 0;
}