init_waitqueue_head(&ch_gk20a->notifier_wq);
init_waitqueue_head(&ch_gk20a->semaphore_wq);
+ init_waitqueue_head(&ch_gk20a->submit_wq);
return ctx;
}
return 0;
}
+static u32 get_gp_free_count(struct channel_gk20a *c)
+{
+ update_gp_get(c->g, c);
+ return gp_free_count(c);
+}
+
int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
struct nvhost_gpfifo *gpfifo,
u32 num_entries,
struct nvhost_device_data *pdata = nvhost_get_devdata(g->dev);
struct device *d = dev_from_gk20a(g);
struct nvhost_syncpt *sp = syncpt_from_gk20a(g);
- u32 free_count;
- u32 extra_count = 0;
u32 i, incr_id = ~0, wait_id = ~0;
u32 err = 0;
int incr_cmd_size;
bool wfi_cmd;
struct priv_cmd_entry *wait_cmd = NULL;
struct priv_cmd_entry *incr_cmd = NULL;
+ /* we might need two extra gpfifo entries - one for syncpoint
+ * wait and one for syncpoint increment */
+ const int extra_entries = 2;
nvhost_dbg_info("channel %d", c->hw_chid);
nvhost_dbg_info("pre-submit put %d, get %d, size %d",
c->gpfifo.put, c->gpfifo.get, c->gpfifo.entry_num);
- free_count = gp_free_count(c);
-
/* If the caller has requested a fence "get" then we need to be
* sure the fence represents work completion. In that case
* issue a wait-for-idle before the syncpoint increment.
*/
wfi_cmd = !!(flags & NVHOST_SUBMIT_GPFIFO_FLAGS_FENCE_GET);
+ /* Invalidate tlb if it's dirty... */
+ /* TBD: this should be done in the cmd stream, not with PRIs. */
+ /* We don't know what context is currently running... */
+ /* Note also: there can be more than one context associated with the */
+ /* address space (vm). */
+ if (c->vm->tlb_dirty) {
+ c->vm->tlb_inval(c->vm);
+ c->vm->tlb_dirty = false;
+ }
+
+ /* Make sure we have enough space for gpfifo entries. If not,
+ * wait for signals from completed submits */
+ if (gp_free_count(c) < num_entries + extra_entries) {
+ err = wait_event_interruptible(c->submit_wq,
+ get_gp_free_count(c) >= num_entries + extra_entries);
+ }
+
+ if (err) {
+ nvhost_err(d, "not enough gpfifo space");
+ err = -EAGAIN;
+ goto clean_up;
+ }
+
/* optionally insert syncpt wait in the beginning of gpfifo submission
when user requested and the wait hasn't expired.
*/
err = -EAGAIN;
goto clean_up;
}
- extra_count++;
}
/* always insert syncpt increment at end of gpfifo submission
err = -EAGAIN;
goto clean_up;
}
- extra_count++;
-
- if (num_entries + extra_count > free_count) {
- nvhost_err(d, "not enough gpfifo space");
- err = -EAGAIN;
- goto clean_up;
- }
if (wait_cmd) {
wait_id = fence->syncpt_id;
#include "nvhost_channel.h"
#include "nvhost_hwctx.h"
#include "chip_support.h"
+#include "gk20a/channel_gk20a.h"
/*** Wait list management ***/
}
+static void action_gpfifo_submit_complete(struct nvhost_waitlist *waiter)
+{
+ struct channel_gk20a *ch20a = waiter->data;
+ int nr_completed = waiter->count;
+ wake_up(&ch20a->submit_wq);
+ nvhost_module_idle_mult(ch20a->ch->dev, nr_completed);
+ /* TODO: add trace function */
+}
+
static void action_ctxsave(struct nvhost_waitlist *waiter)
{
struct nvhost_hwctx *hwctx = waiter->data;
static action_handler action_handlers[NVHOST_INTR_ACTION_COUNT] = {
action_submit_complete,
+ action_gpfifo_submit_complete,
action_ctxsave,
action_signal_sync_pt,
action_wakeup,
struct nvhost_gpfifo *gpfifo, u32 num_entries,
struct nvhost_fence *fence, u32 flags)
{
- struct nvhost_channel *ch = hwctx->channel;
+ struct channel_gk20a *ch = hwctx->priv;
+ struct nvhost_channel *nvhost_ch = hwctx->channel;
void *completed_waiter = NULL;
int err, ret;
if (!completed_waiter)
return -ENOMEM;
- nvhost_module_busy(ch->dev);
+ nvhost_module_busy(nvhost_ch->dev);
+
ret = gk20a_submit_channel_gpfifo(hwctx->priv, gpfifo, num_entries,
fence, flags);
if (!ret) {
- err = nvhost_intr_add_action(&nvhost_get_host(ch->dev)->intr,
+ err = nvhost_intr_add_action(
+ &nvhost_get_host(nvhost_ch->dev)->intr,
fence->syncpt_id, fence->value,
- NVHOST_INTR_ACTION_SUBMIT_COMPLETE, ch,
+ NVHOST_INTR_ACTION_GPFIFO_SUBMIT_COMPLETE,
+ ch,
completed_waiter,
NULL);
WARN(err, "Failed to set submit complete interrupt");
} else {
+ pr_err("submit error %d\n", ret);
kfree(completed_waiter);
}
return ret;