diff options
Diffstat (limited to 'drivers/rapidio/rio.c')
| -rw-r--r-- | drivers/rapidio/rio.c | 75 |
1 files changed, 47 insertions, 28 deletions
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index d4bd69013c50..c17ae22567e0 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c | |||
| @@ -1275,49 +1275,68 @@ static void __devinit disc_work_handler(struct work_struct *_work) | |||
| 1275 | pr_debug("RIO: discovery work for mport %d %s\n", | 1275 | pr_debug("RIO: discovery work for mport %d %s\n", |
| 1276 | work->mport->id, work->mport->name); | 1276 | work->mport->id, work->mport->name); |
| 1277 | rio_disc_mport(work->mport); | 1277 | rio_disc_mport(work->mport); |
| 1278 | |||
| 1279 | kfree(work); | ||
| 1280 | } | 1278 | } |
| 1281 | 1279 | ||
| 1282 | int __devinit rio_init_mports(void) | 1280 | int __devinit rio_init_mports(void) |
| 1283 | { | 1281 | { |
| 1284 | struct rio_mport *port; | 1282 | struct rio_mport *port; |
| 1285 | struct rio_disc_work *work; | 1283 | struct rio_disc_work *work; |
| 1286 | int no_disc = 0; | 1284 | int n = 0; |
| 1285 | |||
| 1286 | if (!next_portid) | ||
| 1287 | return -ENODEV; | ||
| 1287 | 1288 | ||
| 1289 | /* | ||
| 1290 | * First, run enumerations and check if we need to perform discovery | ||
| 1291 | * on any of the registered mports. | ||
| 1292 | */ | ||
| 1288 | list_for_each_entry(port, &rio_mports, node) { | 1293 | list_for_each_entry(port, &rio_mports, node) { |
| 1289 | if (port->host_deviceid >= 0) | 1294 | if (port->host_deviceid >= 0) |
| 1290 | rio_enum_mport(port); | 1295 | rio_enum_mport(port); |
| 1291 | else if (!no_disc) { | 1296 | else |
| 1292 | if (!rio_wq) { | 1297 | n++; |
| 1293 | rio_wq = alloc_workqueue("riodisc", 0, 0); | 1298 | } |
| 1294 | if (!rio_wq) { | 1299 | |
| 1295 | pr_err("RIO: unable allocate rio_wq\n"); | 1300 | if (!n) |
| 1296 | no_disc = 1; | 1301 | goto no_disc; |
| 1297 | continue; | 1302 | |
| 1298 | } | 1303 | /* |
| 1299 | } | 1304 | * If we have mports that require discovery schedule a discovery work |
| 1300 | 1305 | * for each of them. If the code below fails to allocate needed | |
| 1301 | work = kzalloc(sizeof *work, GFP_KERNEL); | 1306 | * resources, exit without error to keep results of enumeration |
| 1302 | if (!work) { | 1307 | * process (if any). |
| 1303 | pr_err("RIO: no memory for work struct\n"); | 1308 | * TODO: Implement restart of dicovery process for all or |
| 1304 | no_disc = 1; | 1309 | * individual discovering mports. |
| 1305 | continue; | 1310 | */ |
| 1306 | } | 1311 | rio_wq = alloc_workqueue("riodisc", 0, 0); |
| 1307 | 1312 | if (!rio_wq) { | |
| 1308 | work->mport = port; | 1313 | pr_err("RIO: unable allocate rio_wq\n"); |
| 1309 | INIT_WORK(&work->work, disc_work_handler); | 1314 | goto no_disc; |
| 1310 | queue_work(rio_wq, &work->work); | ||
| 1311 | } | ||
| 1312 | } | 1315 | } |
| 1313 | 1316 | ||
| 1314 | if (rio_wq) { | 1317 | work = kcalloc(n, sizeof *work, GFP_KERNEL); |
| 1315 | pr_debug("RIO: flush discovery workqueue\n"); | 1318 | if (!work) { |
| 1316 | flush_workqueue(rio_wq); | 1319 | pr_err("RIO: no memory for work struct\n"); |
| 1317 | pr_debug("RIO: flush discovery workqueue finished\n"); | ||
| 1318 | destroy_workqueue(rio_wq); | 1320 | destroy_workqueue(rio_wq); |
| 1321 | goto no_disc; | ||
| 1319 | } | 1322 | } |
| 1320 | 1323 | ||
| 1324 | n = 0; | ||
| 1325 | list_for_each_entry(port, &rio_mports, node) { | ||
| 1326 | if (port->host_deviceid < 0) { | ||
| 1327 | work[n].mport = port; | ||
| 1328 | INIT_WORK(&work[n].work, disc_work_handler); | ||
| 1329 | queue_work(rio_wq, &work[n].work); | ||
| 1330 | n++; | ||
| 1331 | } | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | flush_workqueue(rio_wq); | ||
| 1335 | pr_debug("RIO: destroy discovery workqueue\n"); | ||
| 1336 | destroy_workqueue(rio_wq); | ||
| 1337 | kfree(work); | ||
| 1338 | |||
| 1339 | no_disc: | ||
| 1321 | rio_init(); | 1340 | rio_init(); |
| 1322 | 1341 | ||
| 1323 | return 0; | 1342 | return 0; |
