From ba2e59dc41f593bb011e0ec58c969337a35f4cf1 Mon Sep 17 00:00:00 2001 From: Konsta Holtta Date: Wed, 22 Nov 2017 15:57:11 +0200 Subject: gpu: nvgpu: use submit callback only in linux code Move the implementation for channel job update callbacks that is based on Linux specific work_struct usage to Linux-specific code. This requires a bit of extra work for allocating OS-specific priv data for channels which is also done in this patch. The priv data will be used more when more OS-specific features are moved. Jira NVGPU-259 Change-Id: I24bc0148a827f375b56a1c96044685affc2d1e8c Signed-off-by: Konsta Holtta Reviewed-on: https://git-master.nvidia.com/r/1589321 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/linux/channel.c | 157 ++++++++++++++++++++++++++++++ drivers/gpu/nvgpu/common/linux/channel.h | 32 ++++++ drivers/gpu/nvgpu/common/linux/module.c | 26 +++++ drivers/gpu/nvgpu/common/linux/os_linux.h | 2 + 4 files changed, 217 insertions(+) (limited to 'drivers/gpu/nvgpu/common/linux') diff --git a/drivers/gpu/nvgpu/common/linux/channel.c b/drivers/gpu/nvgpu/common/linux/channel.c index 40b11b86..8366ed88 100644 --- a/drivers/gpu/nvgpu/common/linux/channel.c +++ b/drivers/gpu/nvgpu/common/linux/channel.c @@ -27,6 +27,9 @@ #include "gk20a/gk20a.h" +#include "channel.h" +#include "os_linux.h" + #include #include @@ -34,6 +37,160 @@ #include #include +static void gk20a_channel_update_runcb_fn(struct work_struct *work) +{ + struct nvgpu_channel_completion_cb *completion_cb = + container_of(work, struct nvgpu_channel_completion_cb, work); + struct nvgpu_channel_linux *priv = + container_of(completion_cb, + struct nvgpu_channel_linux, completion_cb); + struct channel_gk20a *ch = priv->ch; + void (*fn)(struct channel_gk20a *, void *); + void *user_data; + + nvgpu_spinlock_acquire(&completion_cb->lock); + fn = completion_cb->fn; + user_data = completion_cb->user_data; + nvgpu_spinlock_release(&completion_cb->lock); + + if (fn) + fn(ch, user_data); +} + +static void nvgpu_channel_work_completion_init(struct channel_gk20a *ch) +{ + struct nvgpu_channel_linux *priv = ch->os_priv; + + priv->completion_cb.fn = NULL; + priv->completion_cb.user_data = NULL; + nvgpu_spinlock_init(&priv->completion_cb.lock); + INIT_WORK(&priv->completion_cb.work, gk20a_channel_update_runcb_fn); +} + +static void nvgpu_channel_work_completion_clear(struct channel_gk20a *ch) +{ + struct nvgpu_channel_linux *priv = ch->os_priv; + + nvgpu_spinlock_acquire(&priv->completion_cb.lock); + priv->completion_cb.fn = NULL; + priv->completion_cb.user_data = NULL; + nvgpu_spinlock_release(&priv->completion_cb.lock); + cancel_work_sync(&priv->completion_cb.work); +} + +static void nvgpu_channel_work_completion_signal(struct channel_gk20a *ch) +{ + struct nvgpu_channel_linux *priv = ch->os_priv; + + if (priv->completion_cb.fn) + schedule_work(&priv->completion_cb.work); +} + +static void nvgpu_channel_work_completion_cancel_sync(struct channel_gk20a *ch) +{ + struct nvgpu_channel_linux *priv = ch->os_priv; + + if (priv->completion_cb.fn) + cancel_work_sync(&priv->completion_cb.work); +} + +struct channel_gk20a *gk20a_open_new_channel_with_cb(struct gk20a *g, + void (*update_fn)(struct channel_gk20a *, void *), + void *update_fn_data, + int runlist_id, + bool is_privileged_channel) +{ + struct channel_gk20a *ch; + struct nvgpu_channel_linux *priv; + + ch = gk20a_open_new_channel(g, runlist_id, is_privileged_channel); + + if (ch) { + priv = ch->os_priv; + nvgpu_spinlock_acquire(&priv->completion_cb.lock); + priv->completion_cb.fn = update_fn; + priv->completion_cb.user_data = update_fn_data; + nvgpu_spinlock_release(&priv->completion_cb.lock); + } + + return ch; +} + +static void nvgpu_channel_open_linux(struct channel_gk20a *ch) +{ +} + +static void nvgpu_channel_close_linux(struct channel_gk20a *ch) +{ + nvgpu_channel_work_completion_clear(ch); +} + +static int nvgpu_channel_alloc_linux(struct gk20a *g, struct channel_gk20a *ch) +{ + struct nvgpu_channel_linux *priv; + + priv = nvgpu_kzalloc(g, sizeof(*priv)); + if (!priv) + return -ENOMEM; + + ch->os_priv = priv; + priv->ch = ch; + + nvgpu_channel_work_completion_init(ch); + + return 0; +} + +static void nvgpu_channel_free_linux(struct gk20a *g, struct channel_gk20a *ch) +{ + nvgpu_kfree(g, ch->os_priv); +} + +int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l) +{ + struct gk20a *g = &l->g; + struct fifo_gk20a *f = &g->fifo; + int chid; + int err; + + for (chid = 0; chid < (int)f->num_channels; chid++) { + struct channel_gk20a *ch = &f->channel[chid]; + + err = nvgpu_channel_alloc_linux(g, ch); + if (err) + goto err_clean; + } + + g->os_channel.open = nvgpu_channel_open_linux; + g->os_channel.close = nvgpu_channel_close_linux; + g->os_channel.work_completion_signal = + nvgpu_channel_work_completion_signal; + g->os_channel.work_completion_cancel_sync = + nvgpu_channel_work_completion_cancel_sync; + return 0; + +err_clean: + for (; chid >= 0; chid--) { + struct channel_gk20a *ch = &f->channel[chid]; + + nvgpu_channel_free_linux(g, ch); + } + return err; +} + +void nvgpu_remove_channel_support_linux(struct nvgpu_os_linux *l) +{ + struct gk20a *g = &l->g; + struct fifo_gk20a *f = &g->fifo; + unsigned int chid; + + for (chid = 0; chid < f->num_channels; chid++) { + struct channel_gk20a *ch = &f->channel[chid]; + + nvgpu_channel_free_linux(g, ch); + } +} + u32 nvgpu_get_gpfifo_entry_size(void) { return sizeof(struct nvgpu_gpfifo); diff --git a/drivers/gpu/nvgpu/common/linux/channel.h b/drivers/gpu/nvgpu/common/linux/channel.h index 785c03d6..ba1935f3 100644 --- a/drivers/gpu/nvgpu/common/linux/channel.h +++ b/drivers/gpu/nvgpu/common/linux/channel.h @@ -16,6 +16,8 @@ #ifndef __NVGPU_CHANNEL_H__ #define __NVGPU_CHANNEL_H__ +#include + #include struct channel_gk20a; @@ -24,6 +26,36 @@ struct nvgpu_submit_gpfifo_args; struct nvgpu_fence; struct gk20a_fence; struct fifo_profile_gk20a; +struct nvgpu_os_linux; + +struct nvgpu_channel_completion_cb { + /* + * Signal channel owner via a callback, if set, in job cleanup with + * schedule_work. Means that something finished on the channel (perhaps + * more than one job). + */ + void (*fn)(struct channel_gk20a *, void *); + void *user_data; + /* Make access to the two above atomic */ + struct nvgpu_spinlock lock; + /* Per-channel async work task, cannot reschedule itself */ + struct work_struct work; +}; + +struct nvgpu_channel_linux { + struct channel_gk20a *ch; + + struct nvgpu_channel_completion_cb completion_cb; +}; + +int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l); +void nvgpu_remove_channel_support_linux(struct nvgpu_os_linux *l); + +struct channel_gk20a *gk20a_open_new_channel_with_cb(struct gk20a *g, + void (*update_fn)(struct channel_gk20a *, void *), + void *update_fn_data, + int runlist_id, + bool is_privileged_channel); int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, struct nvgpu_gpfifo *gpfifo, diff --git a/drivers/gpu/nvgpu/common/linux/module.c b/drivers/gpu/nvgpu/common/linux/module.c index 796507a9..5012d8b5 100644 --- a/drivers/gpu/nvgpu/common/linux/module.c +++ b/drivers/gpu/nvgpu/common/linux/module.c @@ -59,6 +59,7 @@ #include "cde_gp10b.h" #include "ctxsw_trace.h" #include "driver_common.h" +#include "channel.h" #define CLASS_NAME "nvidia-gpu" /* TODO: Change to e.g. "nvidia-gpu%s" once we have symlinks in place. */ @@ -185,6 +186,25 @@ static int nvgpu_init_os_linux_ops(struct nvgpu_os_linux *l) return 0; } +static int nvgpu_finalize_poweron_linux(struct nvgpu_os_linux *l) +{ + struct gk20a *g = &l->g; + int err; + + if (l->init_done) + return 0; + + err = nvgpu_init_channel_support_linux(l); + if (err) { + nvgpu_err(g, "failed to init linux channel support"); + return err; + } + + l->init_done = true; + + return 0; +} + int gk20a_pm_finalize_poweron(struct device *dev) { struct gk20a *g = get_gk20a(dev); @@ -227,6 +247,10 @@ int gk20a_pm_finalize_poweron(struct device *dev) if (err) goto done; + err = nvgpu_finalize_poweron_linux(l); + if (err) + goto done; + trace_gk20a_finalize_poweron_done(dev_name(dev)); err = nvgpu_init_os_linux_ops(l); @@ -596,6 +620,8 @@ void gk20a_remove_support(struct gk20a *g) nvgpu_kfree(g, g->dbg_regops_tmp_buf); + nvgpu_remove_channel_support_linux(l); + if (g->pmu.remove_support) g->pmu.remove_support(&g->pmu); diff --git a/drivers/gpu/nvgpu/common/linux/os_linux.h b/drivers/gpu/nvgpu/common/linux/os_linux.h index 07be7edc..9b95ed84 100644 --- a/drivers/gpu/nvgpu/common/linux/os_linux.h +++ b/drivers/gpu/nvgpu/common/linux/os_linux.h @@ -149,6 +149,8 @@ struct nvgpu_os_linux { struct rw_semaphore busy_lock; struct gk20a_sched_ctrl sched_ctrl; + + bool init_done; }; static inline struct nvgpu_os_linux *nvgpu_os_linux_from_gk20a(struct gk20a *g) -- cgit v1.2.2