int rio_init_mports()

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;
}