diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-05 22:09:16 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-05 22:09:16 +0400 |
commit | 11126c611e10abb18b6f1ed0300c0548c3906b54 (patch) | |
tree | 246227ad730c1e68f5a9c03db57cd4592abe7687 /drivers/rapidio/rio.c | |
parent | 67966e088b0c7dc926f4ce19565ebf208e18d058 (diff) | |
parent | 33e2a4227ddff7c18921ac175fae3ab0e3ff8a76 (diff) | |
download | linux-11126c611e10abb18b6f1ed0300c0548c3906b54.tar.xz |
Merge branch 'akpm' (Andrew's patch-bomb)
Merge misc patches from Andrew Morton:
"The MM tree is rather stuck while I wait to find out what the heck is
happening with sched/numa. Probably I'll need to route around all the
code which was added to -next, sigh.
So this is "everything else", or at least most of it - other small
bits are still awaiting resolutions of various kinds."
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (180 commits)
lib/decompress.c add __init to decompress_method and data
kernel/resource.c: fix stack overflow in __reserve_region_with_split()
omfs: convert to use beXX_add_cpu()
taskstats: cgroupstats_user_cmd() may leak on error
aoe: update aoe-internal version number to 50
aoe: update documentation to better reflect aoe-plus-udev usage
aoe: remove unused code
aoe: make dynamic block minor numbers the default
aoe: update and specify AoE address guards and error messages
aoe: retain static block device numbers for backwards compatibility
aoe: support more AoE addresses with dynamic block device minor numbers
aoe: update documentation with new URL and VM settings reference
aoe: update copyright year in touched files
aoe: update internal version number to 49
aoe: remove unused code and add cosmetic improvements
aoe: increase net_device reference count while using it
aoe: associate frames with the AoE storage target
aoe: disallow unsupported AoE minor addresses
aoe: do revalidation steps in order
aoe: failover remote interface based on aoe_deadsecs parameter
...
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 @@ static LIST_HEAD(rio_mports); static unsigned char next_portid; +static DEFINE_SPINLOCK(rio_mmap_lock); /** * 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) EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); /** + * rio_map_inb_region -- Map inbound memory region. + * @mport: Master port. + * @lstart: physical address of memory region to be mapped + * @rbase: RIO base address assigned to this window + * @size: Size of the memory region + * @rflags: Flags for mapping. + * + * Return: 0 -- Success. + * + * This function will create the mapping from RIO space to local memory. + */ +int rio_map_inb_region(struct rio_mport *mport, dma_addr_t local, + u64 rbase, u32 size, u32 rflags) +{ + int rc = 0; + unsigned long flags; + + if (!mport->ops->map_inb) + return -1; + spin_lock_irqsave(&rio_mmap_lock, flags); + rc = mport->ops->map_inb(mport, local, rbase, size, rflags); + spin_unlock_irqrestore(&rio_mmap_lock, flags); + return rc; +} +EXPORT_SYMBOL_GPL(rio_map_inb_region); + +/** + * rio_unmap_inb_region -- Unmap the inbound memory region + * @mport: Master port + * @lstart: physical address of memory region to be unmapped + */ +void rio_unmap_inb_region(struct rio_mport *mport, dma_addr_t lstart) +{ + unsigned long flags; + if (!mport->ops->unmap_inb) + return; + spin_lock_irqsave(&rio_mmap_lock, flags); + mport->ops->unmap_inb(mport, lstart); + spin_unlock_irqrestore(&rio_mmap_lock, flags); +} +EXPORT_SYMBOL_GPL(rio_unmap_inb_region); + +/** * rio_mport_get_physefb - Helper function that returns register offset * for Physical Layer Extended Features Block. * @port: Master port to issue transaction @@ -1216,15 +1260,62 @@ static int __devinit rio_init(void) return 0; } +static struct workqueue_struct *rio_wq; + +struct rio_disc_work { + struct work_struct work; + struct rio_mport *mport; +}; + +static void __devinit disc_work_handler(struct work_struct *_work) +{ + struct rio_disc_work *work; + + work = container_of(_work, struct rio_disc_work, work); + pr_debug("RIO: discovery work for mport %d %s\n", + work->mport->id, work->mport->name); + rio_disc_mport(work->mport); + + kfree(work); +} + int __devinit rio_init_mports(void) { struct rio_mport *port; + struct rio_disc_work *work; + int no_disc = 0; list_for_each_entry(port, &rio_mports, node) { if (port->host_deviceid >= 0) rio_enum_mport(port); - else - rio_disc_mport(port); + else if (!no_disc) { + if (!rio_wq) { + rio_wq = alloc_workqueue("riodisc", 0, 0); + if (!rio_wq) { + pr_err("RIO: unable allocate rio_wq\n"); + no_disc = 1; + continue; + } + } + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (!work) { + pr_err("RIO: no memory for work struct\n"); + no_disc = 1; + continue; + } + + work->mport = port; + INIT_WORK(&work->work, disc_work_handler); + queue_work(rio_wq, &work->work); + } + } + + if (rio_wq) { + pr_debug("RIO: flush discovery workqueue\n"); + flush_workqueue(rio_wq); + pr_debug("RIO: flush discovery workqueue finished\n"); + destroy_workqueue(rio_wq); } rio_init(); |