diff options
Diffstat (limited to 'drivers/rapidio/rio.c')
-rw-r--r-- | drivers/rapidio/rio.c | 95 |
1 files changed, 93 insertions, 2 deletions
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index c40665a4fa33..d4bd69013c50 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c | |||
@@ -33,6 +33,7 @@ | |||
33 | 33 | ||
34 | static LIST_HEAD(rio_mports); | 34 | static LIST_HEAD(rio_mports); |
35 | static unsigned char next_portid; | 35 | static unsigned char next_portid; |
36 | static DEFINE_SPINLOCK(rio_mmap_lock); | ||
36 | 37 | ||
37 | /** | 38 | /** |
38 | * rio_local_get_device_id - Get the base/extended device id for a port | 39 | * rio_local_get_device_id - Get the base/extended device id for a port |
@@ -398,6 +399,49 @@ int rio_release_inb_pwrite(struct rio_dev *rdev) | |||
398 | EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); | 399 | EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); |
399 | 400 | ||
400 | /** | 401 | /** |
402 | * rio_map_inb_region -- Map inbound memory region. | ||
403 | * @mport: Master port. | ||
404 | * @lstart: physical address of memory region to be mapped | ||
405 | * @rbase: RIO base address assigned to this window | ||
406 | * @size: Size of the memory region | ||
407 | * @rflags: Flags for mapping. | ||
408 | * | ||
409 | * Return: 0 -- Success. | ||
410 | * | ||
411 | * This function will create the mapping from RIO space to local memory. | ||
412 | */ | ||
413 | int rio_map_inb_region(struct rio_mport *mport, dma_addr_t local, | ||
414 | u64 rbase, u32 size, u32 rflags) | ||
415 | { | ||
416 | int rc = 0; | ||
417 | unsigned long flags; | ||
418 | |||
419 | if (!mport->ops->map_inb) | ||
420 | return -1; | ||
421 | spin_lock_irqsave(&rio_mmap_lock, flags); | ||
422 | rc = mport->ops->map_inb(mport, local, rbase, size, rflags); | ||
423 | spin_unlock_irqrestore(&rio_mmap_lock, flags); | ||
424 | return rc; | ||
425 | } | ||
426 | EXPORT_SYMBOL_GPL(rio_map_inb_region); | ||
427 | |||
428 | /** | ||
429 | * rio_unmap_inb_region -- Unmap the inbound memory region | ||
430 | * @mport: Master port | ||
431 | * @lstart: physical address of memory region to be unmapped | ||
432 | */ | ||
433 | void rio_unmap_inb_region(struct rio_mport *mport, dma_addr_t lstart) | ||
434 | { | ||
435 | unsigned long flags; | ||
436 | if (!mport->ops->unmap_inb) | ||
437 | return; | ||
438 | spin_lock_irqsave(&rio_mmap_lock, flags); | ||
439 | mport->ops->unmap_inb(mport, lstart); | ||
440 | spin_unlock_irqrestore(&rio_mmap_lock, flags); | ||
441 | } | ||
442 | EXPORT_SYMBOL_GPL(rio_unmap_inb_region); | ||
443 | |||
444 | /** | ||
401 | * rio_mport_get_physefb - Helper function that returns register offset | 445 | * rio_mport_get_physefb - Helper function that returns register offset |
402 | * for Physical Layer Extended Features Block. | 446 | * for Physical Layer Extended Features Block. |
403 | * @port: Master port to issue transaction | 447 | * @port: Master port to issue transaction |
@@ -1216,15 +1260,62 @@ static int __devinit rio_init(void) | |||
1216 | return 0; | 1260 | return 0; |
1217 | } | 1261 | } |
1218 | 1262 | ||
1263 | static struct workqueue_struct *rio_wq; | ||
1264 | |||
1265 | struct rio_disc_work { | ||
1266 | struct work_struct work; | ||
1267 | struct rio_mport *mport; | ||
1268 | }; | ||
1269 | |||
1270 | static void __devinit disc_work_handler(struct work_struct *_work) | ||
1271 | { | ||
1272 | struct rio_disc_work *work; | ||
1273 | |||
1274 | work = container_of(_work, struct rio_disc_work, work); | ||
1275 | pr_debug("RIO: discovery work for mport %d %s\n", | ||
1276 | work->mport->id, work->mport->name); | ||
1277 | rio_disc_mport(work->mport); | ||
1278 | |||
1279 | kfree(work); | ||
1280 | } | ||
1281 | |||
1219 | int __devinit rio_init_mports(void) | 1282 | int __devinit rio_init_mports(void) |
1220 | { | 1283 | { |
1221 | struct rio_mport *port; | 1284 | struct rio_mport *port; |
1285 | struct rio_disc_work *work; | ||
1286 | int no_disc = 0; | ||
1222 | 1287 | ||
1223 | list_for_each_entry(port, &rio_mports, node) { | 1288 | list_for_each_entry(port, &rio_mports, node) { |
1224 | if (port->host_deviceid >= 0) | 1289 | if (port->host_deviceid >= 0) |
1225 | rio_enum_mport(port); | 1290 | rio_enum_mport(port); |
1226 | else | 1291 | else if (!no_disc) { |
1227 | rio_disc_mport(port); | 1292 | if (!rio_wq) { |
1293 | rio_wq = alloc_workqueue("riodisc", 0, 0); | ||
1294 | if (!rio_wq) { | ||
1295 | pr_err("RIO: unable allocate rio_wq\n"); | ||
1296 | no_disc = 1; | ||
1297 | continue; | ||
1298 | } | ||
1299 | } | ||
1300 | |||
1301 | work = kzalloc(sizeof *work, GFP_KERNEL); | ||
1302 | if (!work) { | ||
1303 | pr_err("RIO: no memory for work struct\n"); | ||
1304 | no_disc = 1; | ||
1305 | continue; | ||
1306 | } | ||
1307 | |||
1308 | work->mport = port; | ||
1309 | INIT_WORK(&work->work, disc_work_handler); | ||
1310 | queue_work(rio_wq, &work->work); | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | if (rio_wq) { | ||
1315 | pr_debug("RIO: flush discovery workqueue\n"); | ||
1316 | flush_workqueue(rio_wq); | ||
1317 | pr_debug("RIO: flush discovery workqueue finished\n"); | ||
1318 | destroy_workqueue(rio_wq); | ||
1228 | } | 1319 | } |
1229 | 1320 | ||
1230 | rio_init(); | 1321 | rio_init(); |