diff options
author | Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> | 2017-08-29 08:23:36 +0200 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2017-08-31 06:26:35 +0200 |
commit | bbfe59f8a7057f80f67a74e77fb4e941240e90b9 (patch) | |
tree | 78dc478c40d7b2af00bb2c1bffc2c8688f8bd645 /arch/powerpc/platforms | |
parent | powerpc/powernv/vas: Define helpers to init window context (diff) | |
download | linux-bbfe59f8a7057f80f67a74e77fb4e941240e90b9.tar.xz linux-bbfe59f8a7057f80f67a74e77fb4e941240e90b9.zip |
powerpc/powernv/vas: Define helpers to alloc/free windows
Define helpers to allocate/free VAS window objects. These will be used
in follow-on patches when opening/closing windows.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r-- | arch/powerpc/platforms/powernv/vas-window.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/powernv/vas-window.c b/arch/powerpc/platforms/powernv/vas-window.c index 68dfe538e0f6..bfc9dba24b65 100644 --- a/arch/powerpc/platforms/powernv/vas-window.c +++ b/arch/powerpc/platforms/powernv/vas-window.c @@ -485,6 +485,79 @@ int init_winctx_regs(struct vas_window *window, struct vas_winctx *winctx) return 0; } +static DEFINE_SPINLOCK(vas_ida_lock); + +static void vas_release_window_id(struct ida *ida, int winid) +{ + spin_lock(&vas_ida_lock); + ida_remove(ida, winid); + spin_unlock(&vas_ida_lock); +} + +static int vas_assign_window_id(struct ida *ida) +{ + int rc, winid; + + do { + rc = ida_pre_get(ida, GFP_KERNEL); + if (!rc) + return -EAGAIN; + + spin_lock(&vas_ida_lock); + rc = ida_get_new(ida, &winid); + spin_unlock(&vas_ida_lock); + } while (rc == -EAGAIN); + + if (rc) + return rc; + + if (winid > VAS_WINDOWS_PER_CHIP) { + pr_err("Too many (%d) open windows\n", winid); + vas_release_window_id(ida, winid); + return -EAGAIN; + } + + return winid; +} + +void vas_window_free(struct vas_window *window) +{ + int winid = window->winid; + struct vas_instance *vinst = window->vinst; + + unmap_winctx_mmio_bars(window); + kfree(window); + + vas_release_window_id(&vinst->ida, winid); +} + +struct vas_window *vas_window_alloc(struct vas_instance *vinst) +{ + int winid; + struct vas_window *window; + + winid = vas_assign_window_id(&vinst->ida); + if (winid < 0) + return ERR_PTR(winid); + + window = kzalloc(sizeof(*window), GFP_KERNEL); + if (!window) + goto out_free; + + window->vinst = vinst; + window->winid = winid; + + if (map_winctx_mmio_bars(window)) + goto out_free; + + return window; + +out_free: + kfree(window); + vas_release_window_id(&vinst->ida, winid); + return ERR_PTR(-ENOMEM); +} + /* stub for now */ int vas_win_close(struct vas_window *window) { |