From d635711daa98be86d4c7fd01499c34f566b54ccb Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Fri, 10 Jun 2016 05:30:17 -0300 Subject: Linux-libre 4.6.2-gnu --- drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild | 7 +- .../gpu/drm/nouveau/nvkm/engine/fifo/changk104.h | 5 +- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 54 +++-- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h | 9 +- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 270 ++++++++++++++------- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h | 55 ++--- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c | 46 ++++ drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c | 46 ++++ drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c | 46 ++++ drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c | 46 ---- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c | 186 +++++++++----- .../gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk110.c | 34 +++ .../gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm200.c | 34 +++ .../gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c | 34 --- 15 files changed, 591 insertions(+), 283 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk110.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm200.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/fifo') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild index 74993c144..65e5d291e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild @@ -7,9 +7,11 @@ nvkm-y += nvkm/engine/fifo/nv50.o nvkm-y += nvkm/engine/fifo/g84.o nvkm-y += nvkm/engine/fifo/gf100.o nvkm-y += nvkm/engine/fifo/gk104.o +nvkm-y += nvkm/engine/fifo/gk110.o nvkm-y += nvkm/engine/fifo/gk208.o nvkm-y += nvkm/engine/fifo/gk20a.o -nvkm-y += nvkm/engine/fifo/gm204.o +nvkm-y += nvkm/engine/fifo/gm107.o +nvkm-y += nvkm/engine/fifo/gm200.o nvkm-y += nvkm/engine/fifo/gm20b.o nvkm-y += nvkm/engine/fifo/chan.o @@ -27,4 +29,5 @@ nvkm-y += nvkm/engine/fifo/gpfifonv50.o nvkm-y += nvkm/engine/fifo/gpfifog84.o nvkm-y += nvkm/engine/fifo/gpfifogf100.o nvkm-y += nvkm/engine/fifo/gpfifogk104.o -nvkm-y += nvkm/engine/fifo/gpfifogm204.o +nvkm-y += nvkm/engine/fifo/gpfifogk110.o +nvkm-y += nvkm/engine/fifo/gpfifogm200.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h index 97bdddb76..e06f4d46f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h @@ -7,7 +7,7 @@ struct gk104_fifo_chan { struct nvkm_fifo_chan base; struct gk104_fifo *fifo; - int engine; + int runl; struct list_head head; bool killed; @@ -25,5 +25,6 @@ int gk104_fifo_gpfifo_new(struct nvkm_fifo *, const struct nvkm_oclass *, void *data, u32 size, struct nvkm_object **); extern const struct nvkm_fifo_chan_oclass gk104_fifo_gpfifo_oclass; -extern const struct nvkm_fifo_chan_oclass gm204_fifo_gpfifo_oclass; +extern const struct nvkm_fifo_chan_oclass gk110_fifo_gpfifo_oclass; +extern const struct nvkm_fifo_chan_oclass gm200_fifo_gpfifo_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 36a39c7fd..352a0baec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -54,6 +54,7 @@ gf100_fifo_runlist_commit(struct gf100_fifo *fifo) struct nvkm_device *device = subdev->device; struct nvkm_memory *cur; int nr = 0; + int target; mutex_lock(&subdev->mutex); cur = fifo->runlist.mem[fifo->runlist.active]; @@ -67,7 +68,10 @@ gf100_fifo_runlist_commit(struct gf100_fifo *fifo) } nvkm_done(cur); - nvkm_wr32(device, 0x002270, nvkm_memory_addr(cur) >> 12); + target = (nvkm_memory_target(cur) == NVKM_MEM_TARGET_HOST) ? 0x3 : 0x0; + + nvkm_wr32(device, 0x002270, (nvkm_memory_addr(cur) >> 12) | + (target << 28)); nvkm_wr32(device, 0x002274, 0x01f00000 | nr); if (wait_event_timeout(fifo->runlist.wait, @@ -130,9 +134,9 @@ gf100_fifo_engine(struct gf100_fifo *fifo, u32 engn) } static void -gf100_fifo_recover_work(struct work_struct *work) +gf100_fifo_recover_work(struct work_struct *w) { - struct gf100_fifo *fifo = container_of(work, typeof(*fifo), fault); + struct gf100_fifo *fifo = container_of(w, typeof(*fifo), recover.work); struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_engine *engine; unsigned long flags; @@ -140,15 +144,15 @@ gf100_fifo_recover_work(struct work_struct *work) u64 mask, todo; spin_lock_irqsave(&fifo->base.lock, flags); - mask = fifo->mask; - fifo->mask = 0ULL; + mask = fifo->recover.mask; + fifo->recover.mask = 0ULL; spin_unlock_irqrestore(&fifo->base.lock, flags); - for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) + for (todo = mask; engn = __ffs64(todo), todo; todo &= ~BIT_ULL(engn)) engm |= 1 << gf100_fifo_engidx(fifo, engn); nvkm_mask(device, 0x002630, engm, engm); - for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { + for (todo = mask; engn = __ffs64(todo), todo; todo &= ~BIT_ULL(engn)) { if ((engine = nvkm_device_engine(device, engn))) { nvkm_subdev_fini(&engine->subdev, false); WARN_ON(nvkm_subdev_init(&engine->subdev)); @@ -176,8 +180,8 @@ gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, list_del_init(&chan->head); chan->killed = true; - fifo->mask |= 1ULL << engine->subdev.index; - schedule_work(&fifo->fault); + fifo->recover.mask |= 1ULL << engine->subdev.index; + schedule_work(&fifo->recover.work); } static const struct nvkm_enum @@ -330,7 +334,7 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) snprintf(gpcid, sizeof(gpcid), "GPC%d/", gpc); } - if (eu) { + if (eu && eu->data2) { switch (eu->data2) { case NVKM_SUBDEV_BAR: nvkm_mask(device, 0x001704, 0x00000000, 0x00000000); @@ -544,9 +548,16 @@ static int gf100_fifo_oneinit(struct nvkm_fifo *base) { struct gf100_fifo *fifo = gf100_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; int ret; + /* Determine number of PBDMAs by checking valid enable bits. */ + nvkm_wr32(device, 0x002204, 0xffffffff); + fifo->pbdma_nr = hweight32(nvkm_rd32(device, 0x002204)); + nvkm_debug(subdev, "%d PBDMA(s)\n", fifo->pbdma_nr); + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, false, &fifo->runlist.mem[0]); if (ret) @@ -576,25 +587,22 @@ static void gf100_fifo_fini(struct nvkm_fifo *base) { struct gf100_fifo *fifo = gf100_fifo(base); - flush_work(&fifo->fault); + flush_work(&fifo->recover.work); } static void gf100_fifo_init(struct nvkm_fifo *base) { struct gf100_fifo *fifo = gf100_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_device *device = fifo->base.engine.subdev.device; int i; - nvkm_wr32(device, 0x000204, 0xffffffff); - nvkm_wr32(device, 0x002204, 0xffffffff); - - fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x002204)); - nvkm_debug(subdev, "%d PBDMA unit(s)\n", fifo->spoon_nr); + /* Enable PBDMAs. */ + nvkm_wr32(device, 0x000204, (1 << fifo->pbdma_nr) - 1); + nvkm_wr32(device, 0x002204, (1 << fifo->pbdma_nr) - 1); - /* assign engines to PBDMAs */ - if (fifo->spoon_nr >= 3) { + /* Assign engines to PBDMAs. */ + if (fifo->pbdma_nr >= 3) { nvkm_wr32(device, 0x002208, ~(1 << 0)); /* PGRAPH */ nvkm_wr32(device, 0x00220c, ~(1 << 1)); /* PVP */ nvkm_wr32(device, 0x002210, ~(1 << 1)); /* PMSPP */ @@ -604,7 +612,7 @@ gf100_fifo_init(struct nvkm_fifo *base) } /* PBDMA[n] */ - for (i = 0; i < fifo->spoon_nr; i++) { + for (i = 0; i < fifo->pbdma_nr; i++) { nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ @@ -652,7 +660,7 @@ gf100_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) return -ENOMEM; INIT_LIST_HEAD(&fifo->chan); - INIT_WORK(&fifo->fault, gf100_fifo_recover_work); + INIT_WORK(&fifo->recover.work, gf100_fifo_recover_work); *pfifo = &fifo->base; return nvkm_fifo_ctor(&gf100_fifo, device, index, 128, &fifo->base); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h index 08c33c3ce..70db58eab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h @@ -11,8 +11,12 @@ struct gf100_fifo { struct list_head chan; - struct work_struct fault; - u64 mask; + struct { + struct work_struct work; + u64 mask; + } recover; + + int pbdma_nr; struct { struct nvkm_memory *mem[2]; @@ -24,7 +28,6 @@ struct gf100_fifo { struct nvkm_memory *mem; struct nvkm_vma bar; } user; - int spoon_nr; }; void gf100_fifo_intr_engine(struct gf100_fifo *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 4fcd147d4..68acb36b3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -47,34 +47,41 @@ gk104_fifo_uevent_init(struct nvkm_fifo *fifo) } void -gk104_fifo_runlist_commit(struct gk104_fifo *fifo, u32 engine) +gk104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl) { - struct gk104_fifo_engn *engn = &fifo->engine[engine]; struct gk104_fifo_chan *chan; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_memory *cur; + struct nvkm_memory *mem; int nr = 0; + int target; mutex_lock(&subdev->mutex); - cur = engn->runlist[engn->cur_runlist]; - engn->cur_runlist = !engn->cur_runlist; + mem = fifo->runlist[runl].mem[fifo->runlist[runl].next]; + fifo->runlist[runl].next = !fifo->runlist[runl].next; - nvkm_kmap(cur); - list_for_each_entry(chan, &engn->chan, head) { - nvkm_wo32(cur, (nr * 8) + 0, chan->base.chid); - nvkm_wo32(cur, (nr * 8) + 4, 0x00000000); + nvkm_kmap(mem); + list_for_each_entry(chan, &fifo->runlist[runl].chan, head) { + nvkm_wo32(mem, (nr * 8) + 0, chan->base.chid); + nvkm_wo32(mem, (nr * 8) + 4, 0x00000000); nr++; } - nvkm_done(cur); - - nvkm_wr32(device, 0x002270, nvkm_memory_addr(cur) >> 12); - nvkm_wr32(device, 0x002274, (engine << 20) | nr); - - if (wait_event_timeout(engn->wait, !(nvkm_rd32(device, 0x002284 + - (engine * 0x08)) & 0x00100000), - msecs_to_jiffies(2000)) == 0) - nvkm_error(subdev, "runlist %d update timeout\n", engine); + nvkm_done(mem); + + if (nvkm_memory_target(mem) == NVKM_MEM_TARGET_VRAM) + target = 0; + else + target = 3; + + nvkm_wr32(device, 0x002270, (nvkm_memory_addr(mem) >> 12) | + (target << 28)); + nvkm_wr32(device, 0x002274, (runl << 20) | nr); + + if (wait_event_timeout(fifo->runlist[runl].wait, + !(nvkm_rd32(device, 0x002284 + (runl * 0x08)) + & 0x00100000), + msecs_to_jiffies(2000)) == 0) + nvkm_error(subdev, "runlist %d update timeout\n", runl); mutex_unlock(&subdev->mutex); } @@ -90,58 +97,51 @@ void gk104_fifo_runlist_insert(struct gk104_fifo *fifo, struct gk104_fifo_chan *chan) { mutex_lock(&fifo->base.engine.subdev.mutex); - list_add_tail(&chan->head, &fifo->engine[chan->engine].chan); + list_add_tail(&chan->head, &fifo->runlist[chan->runl].chan); mutex_unlock(&fifo->base.engine.subdev.mutex); } -static inline struct nvkm_engine * -gk104_fifo_engine(struct gk104_fifo *fifo, u32 engn) -{ - struct nvkm_device *device = fifo->base.engine.subdev.device; - u64 subdevs = gk104_fifo_engine_subdev(engn); - if (subdevs) - return nvkm_device_engine(device, __ffs(subdevs)); - return NULL; -} - static void -gk104_fifo_recover_work(struct work_struct *work) +gk104_fifo_recover_work(struct work_struct *w) { - struct gk104_fifo *fifo = container_of(work, typeof(*fifo), fault); + struct gk104_fifo *fifo = container_of(w, typeof(*fifo), recover.work); struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_engine *engine; unsigned long flags; - u32 engn, engm = 0; - u64 mask, todo; + u32 engm, runm, todo; + int engn, runl; spin_lock_irqsave(&fifo->base.lock, flags); - mask = fifo->mask; - fifo->mask = 0ULL; + runm = fifo->recover.runm; + engm = fifo->recover.engm; + fifo->recover.engm = 0; + fifo->recover.runm = 0; spin_unlock_irqrestore(&fifo->base.lock, flags); - for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) - engm |= 1 << gk104_fifo_subdev_engine(engn); - nvkm_mask(device, 0x002630, engm, engm); + nvkm_mask(device, 0x002630, runm, runm); - for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { - if ((engine = nvkm_device_engine(device, engn))) { + for (todo = engm; engn = __ffs(todo), todo; todo &= ~BIT(engn)) { + if ((engine = fifo->engine[engn].engine)) { nvkm_subdev_fini(&engine->subdev, false); WARN_ON(nvkm_subdev_init(&engine->subdev)); } - gk104_fifo_runlist_commit(fifo, gk104_fifo_subdev_engine(engn)); } - nvkm_wr32(device, 0x00262c, engm); - nvkm_mask(device, 0x002630, engm, 0x00000000); + for (todo = runm; runl = __ffs(todo), todo; todo &= ~BIT(runl)) + gk104_fifo_runlist_commit(fifo, runl); + + nvkm_wr32(device, 0x00262c, runm); + nvkm_mask(device, 0x002630, runm, 0x00000000); } static void gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, - struct gk104_fifo_chan *chan) + struct gk104_fifo_chan *chan) { struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; u32 chid = chan->base.chid; + int engn; nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", nvkm_subdev_name[engine->subdev.index], chid); @@ -151,8 +151,15 @@ gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, list_del_init(&chan->head); chan->killed = true; - fifo->mask |= 1ULL << engine->subdev.index; - schedule_work(&fifo->fault); + for (engn = 0; engn < fifo->engine_nr; engn++) { + if (fifo->engine[engn].engine == engine) { + fifo->recover.engm |= BIT(engn); + break; + } + } + + fifo->recover.runm |= BIT(chan->runl); + schedule_work(&fifo->recover.work); } static const struct nvkm_enum @@ -189,32 +196,31 @@ static void gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) { struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_engine *engine; struct gk104_fifo_chan *chan; unsigned long flags; u32 engn; spin_lock_irqsave(&fifo->base.lock, flags); - for (engn = 0; engn < ARRAY_SIZE(fifo->engine); engn++) { + for (engn = 0; engn < fifo->engine_nr; engn++) { + struct nvkm_engine *engine = fifo->engine[engn].engine; + int runl = fifo->engine[engn].runl; u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x08)); u32 busy = (stat & 0x80000000); - u32 next = (stat & 0x07ff0000) >> 16; + u32 next = (stat & 0x0fff0000) >> 16; u32 chsw = (stat & 0x00008000); u32 save = (stat & 0x00004000); u32 load = (stat & 0x00002000); - u32 prev = (stat & 0x000007ff); + u32 prev = (stat & 0x00000fff); u32 chid = load ? next : prev; (void)save; - if (busy && chsw) { - list_for_each_entry(chan, &fifo->engine[engn].chan, head) { - if (chan->base.chid == chid) { - engine = gk104_fifo_engine(fifo, engn); - if (!engine) - break; - gk104_fifo_recover(fifo, engine, chan); - break; - } + if (!busy || !chsw) + continue; + + list_for_each_entry(chan, &fifo->runlist[runl].chan, head) { + if (chan->base.chid == chid && engine) { + gk104_fifo_recover(fifo, engine, chan); + break; } } } @@ -395,7 +401,7 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) snprintf(gpcid, sizeof(gpcid), "GPC%d/", gpc); } - if (eu) { + if (eu && eu->data2) { switch (eu->data2) { case NVKM_SUBDEV_BAR: nvkm_mask(device, 0x001704, 0x00000000, 0x00000000); @@ -484,9 +490,10 @@ gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data)) show &= ~0x00800000; } - nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); } + nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); + if (show) { nvkm_snprintbf(msg, sizeof(msg), gk104_fifo_pbdma_intr_0, show); chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); @@ -537,10 +544,10 @@ gk104_fifo_intr_runlist(struct gk104_fifo *fifo) struct nvkm_device *device = fifo->base.engine.subdev.device; u32 mask = nvkm_rd32(device, 0x002a00); while (mask) { - u32 engn = __ffs(mask); - wake_up(&fifo->engine[engn].wait); - nvkm_wr32(device, 0x002a00, 1 << engn); - mask &= ~(1 << engn); + int runl = __ffs(mask); + wake_up(&fifo->runlist[runl].wait); + nvkm_wr32(device, 0x002a00, 1 << runl); + mask &= ~(1 << runl); } } @@ -647,7 +654,7 @@ gk104_fifo_fini(struct nvkm_fifo *base) { struct gk104_fifo *fifo = gk104_fifo(base); struct nvkm_device *device = fifo->base.engine.subdev.device; - flush_work(&fifo->fault); + flush_work(&fifo->recover.work); /* allow mmu fault interrupts, even when we're not using fifo */ nvkm_mask(device, 0x002140, 0x10000000, 0x10000000); } @@ -656,24 +663,122 @@ int gk104_fifo_oneinit(struct nvkm_fifo *base) { struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; int ret, i; + u32 *map; + + /* Determine number of PBDMAs by checking valid enable bits. */ + nvkm_wr32(device, 0x000204, 0xffffffff); + fifo->pbdma_nr = hweight32(nvkm_rd32(device, 0x000204)); + nvkm_debug(subdev, "%d PBDMA(s)\n", fifo->pbdma_nr); + + /* Read PBDMA->runlist(s) mapping from HW. */ + if (!(map = kzalloc(sizeof(*map) * fifo->pbdma_nr, GFP_KERNEL))) + return -ENOMEM; + + for (i = 0; i < fifo->pbdma_nr; i++) + map[i] = nvkm_rd32(device, 0x002390 + (i * 0x04)); + + /* Read device topology from HW. */ + for (i = 0; i < 64; i++) { + int type = -1, pbid = -1, engidx = -1; + int engn = -1, runl = -1, intr = -1, mcen = -1; + int fault = -1, j; + u32 data, addr = 0; + + do { + data = nvkm_rd32(device, 0x022700 + (i * 0x04)); + nvkm_trace(subdev, "%02x: %08x\n", i, data); + switch (data & 0x00000003) { + case 0x00000000: /* NOT_VALID */ + continue; + case 0x00000001: /* DATA */ + addr = (data & 0x00fff000); + fault = (data & 0x000000f8) >> 3; + break; + case 0x00000002: /* ENUM */ + if (data & 0x00000020) + engn = (data & 0x3c000000) >> 26; + if (data & 0x00000010) + runl = (data & 0x01e00000) >> 21; + if (data & 0x00000008) + intr = (data & 0x000f8000) >> 15; + if (data & 0x00000004) + mcen = (data & 0x00003e00) >> 9; + break; + case 0x00000003: /* ENGINE_TYPE */ + type = (data & 0x7ffffffc) >> 2; + break; + } + } while ((data & 0x80000000) && ++i < 64); + + if (!data) + continue; + + /* Determine which PBDMA handles requests for this engine. */ + for (j = 0; runl >= 0 && j < fifo->pbdma_nr; j++) { + if (map[j] & (1 << runl)) { + pbid = j; + break; + } + } + + /* Translate engine type to NVKM engine identifier. */ + switch (type) { + case 0x00000000: engidx = NVKM_ENGINE_GR; break; + case 0x00000001: engidx = NVKM_ENGINE_CE0; break; + case 0x00000002: engidx = NVKM_ENGINE_CE1; break; + case 0x00000003: engidx = NVKM_ENGINE_CE2; break; + case 0x00000008: engidx = NVKM_ENGINE_MSPDEC; break; + case 0x00000009: engidx = NVKM_ENGINE_MSPPP; break; + case 0x0000000a: engidx = NVKM_ENGINE_MSVLD; break; + case 0x0000000b: engidx = NVKM_ENGINE_MSENC; break; + case 0x0000000c: engidx = NVKM_ENGINE_VIC; break; + case 0x0000000d: engidx = NVKM_ENGINE_SEC; break; + case 0x0000000e: engidx = NVKM_ENGINE_NVENC0; break; + case 0x0000000f: engidx = NVKM_ENGINE_NVENC1; break; + case 0x00000010: engidx = NVKM_ENGINE_NVDEC; break; + break; + default: + break; + } + + nvkm_debug(subdev, "%02x (%8s): engine %2d runlist %2d " + "pbdma %2d intr %2d reset %2d " + "fault %2d addr %06x\n", type, + engidx < 0 ? NULL : nvkm_subdev_name[engidx], + engn, runl, pbid, intr, mcen, fault, addr); + + /* Mark the engine as supported if everything checks out. */ + if (engn >= 0 && runl >= 0) { + fifo->engine[engn].engine = engidx < 0 ? NULL : + nvkm_device_engine(device, engidx); + fifo->engine[engn].runl = runl; + fifo->engine[engn].pbid = pbid; + fifo->engine_nr = max(fifo->engine_nr, engn + 1); + fifo->runlist[runl].engm |= 1 << engn; + fifo->runlist_nr = max(fifo->runlist_nr, runl + 1); + } + } - for (i = 0; i < ARRAY_SIZE(fifo->engine); i++) { + kfree(map); + + for (i = 0; i < fifo->runlist_nr; i++) { ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x8000, 0x1000, false, - &fifo->engine[i].runlist[0]); + &fifo->runlist[i].mem[0]); if (ret) return ret; ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x8000, 0x1000, false, - &fifo->engine[i].runlist[1]); + &fifo->runlist[i].mem[1]); if (ret) return ret; - init_waitqueue_head(&fifo->engine[i].wait); - INIT_LIST_HEAD(&fifo->engine[i].chan); + init_waitqueue_head(&fifo->runlist[i].wait); + INIT_LIST_HEAD(&fifo->runlist[i].chan); } ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, @@ -695,24 +800,21 @@ void gk104_fifo_init(struct nvkm_fifo *base) { struct gk104_fifo *fifo = gk104_fifo(base); - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_device *device = fifo->base.engine.subdev.device; int i; - /* enable all available PBDMA units */ - nvkm_wr32(device, 0x000204, 0xffffffff); - fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x000204)); - nvkm_debug(subdev, "%d PBDMA unit(s)\n", fifo->spoon_nr); + /* Enable PBDMAs. */ + nvkm_wr32(device, 0x000204, (1 << fifo->pbdma_nr) - 1); /* PBDMA[n] */ - for (i = 0; i < fifo->spoon_nr; i++) { + for (i = 0; i < fifo->pbdma_nr; i++) { nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ } /* PBDMA[n].HCE */ - for (i = 0; i < fifo->spoon_nr; i++) { + for (i = 0; i < fifo->pbdma_nr; i++) { nvkm_wr32(device, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */ nvkm_wr32(device, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */ } @@ -732,9 +834,9 @@ gk104_fifo_dtor(struct nvkm_fifo *base) nvkm_vm_put(&fifo->user.bar); nvkm_memory_del(&fifo->user.mem); - for (i = 0; i < ARRAY_SIZE(fifo->engine); i++) { - nvkm_memory_del(&fifo->engine[i].runlist[1]); - nvkm_memory_del(&fifo->engine[i].runlist[0]); + for (i = 0; i < fifo->runlist_nr; i++) { + nvkm_memory_del(&fifo->runlist[i].mem[1]); + nvkm_memory_del(&fifo->runlist[i].mem[0]); } return fifo; @@ -748,7 +850,7 @@ gk104_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device, if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) return -ENOMEM; - INIT_WORK(&fifo->fault, gk104_fifo_recover_work); + INIT_WORK(&fifo->recover.work, gk104_fifo_recover_work); *pfifo = &fifo->base; return nvkm_fifo_ctor(func, device, index, nr, &fifo->base); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h index bec519d8f..9e5d00ba3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h @@ -6,25 +6,37 @@ #include struct gk104_fifo_chan; -struct gk104_fifo_engn { - struct nvkm_memory *runlist[2]; - int cur_runlist; - wait_queue_head_t wait; - struct list_head chan; -}; - struct gk104_fifo { struct nvkm_fifo base; - struct work_struct fault; - u64 mask; + struct { + struct work_struct work; + u32 engm; + u32 runm; + } recover; + + int pbdma_nr; + + struct { + struct nvkm_engine *engine; + int runl; + int pbid; + } engine[16]; + int engine_nr; + + struct { + struct nvkm_memory *mem[2]; + int next; + wait_queue_head_t wait; + struct list_head chan; + u32 engm; + } runlist[16]; + int runlist_nr; - struct gk104_fifo_engn engine[7]; struct { struct nvkm_memory *mem; struct nvkm_vma bar; } user; - int spoon_nr; }; int gk104_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, @@ -38,7 +50,7 @@ void gk104_fifo_uevent_init(struct nvkm_fifo *); void gk104_fifo_uevent_fini(struct nvkm_fifo *); void gk104_fifo_runlist_insert(struct gk104_fifo *, struct gk104_fifo_chan *); void gk104_fifo_runlist_remove(struct gk104_fifo *, struct gk104_fifo_chan *); -void gk104_fifo_runlist_commit(struct gk104_fifo *, u32 engine); +void gk104_fifo_runlist_commit(struct gk104_fifo *, int runl); static inline u64 gk104_fifo_engine_subdev(int engine) @@ -58,23 +70,4 @@ gk104_fifo_engine_subdev(int engine) return 0; } } - -static inline int -gk104_fifo_subdev_engine(int subdev) -{ - switch (subdev) { - case NVKM_ENGINE_GR: - case NVKM_ENGINE_SW: - case NVKM_ENGINE_CE2 : return 0; - case NVKM_ENGINE_MSPDEC: return 1; - case NVKM_ENGINE_MSPPP : return 2; - case NVKM_ENGINE_MSVLD : return 3; - case NVKM_ENGINE_CE0 : return 4; - case NVKM_ENGINE_CE1 : return 5; - case NVKM_ENGINE_MSENC : return 6; - default: - WARN_ON(1); - return 0; - } -} #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c new file mode 100644 index 000000000..41307fcd4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c @@ -0,0 +1,46 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "gk104.h" +#include "changk104.h" + +static const struct nvkm_fifo_func +gk110_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gk110_fifo_gpfifo_oclass, + NULL + }, +}; + +int +gk110_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gk110_fifo, device, index, 4096, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c new file mode 100644 index 000000000..6d59d6579 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c @@ -0,0 +1,46 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "gk104.h" +#include "changk104.h" + +static const struct nvkm_fifo_func +gm107_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gk110_fifo_gpfifo_oclass, + NULL + }, +}; + +int +gm107_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gm107_fifo, device, index, 2048, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c new file mode 100644 index 000000000..4bdd43078 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm200.c @@ -0,0 +1,46 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "gk104.h" +#include "changk104.h" + +static const struct nvkm_fifo_func +gm200_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gm200_fifo_gpfifo_oclass, + NULL + }, +}; + +int +gm200_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gm200_fifo, device, index, 4096, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c deleted file mode 100644 index 2db629f1b..000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ -#include "gk104.h" -#include "changk104.h" - -static const struct nvkm_fifo_func -gm204_fifo = { - .dtor = gk104_fifo_dtor, - .oneinit = gk104_fifo_oneinit, - .init = gk104_fifo_init, - .fini = gk104_fifo_fini, - .intr = gk104_fifo_intr, - .uevent_init = gk104_fifo_uevent_init, - .uevent_fini = gk104_fifo_uevent_fini, - .chan = { - &gm204_fifo_gpfifo_oclass, - NULL - }, -}; - -int -gm204_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) -{ - return gk104_fifo_new_(&gm204_fifo, device, index, 4096, pfifo); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c index ae6375d97..4c91d4aa1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c @@ -32,7 +32,7 @@ gm20b_fifo = { .uevent_init = gk104_fifo_uevent_init, .uevent_fini = gk104_fifo_uevent_fini, .chan = { - &gm204_fifo_gpfifo_oclass, + &gm200_fifo_gpfifo_oclass, NULL }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c index 2e1df01bd..ed4351032 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c @@ -63,9 +63,15 @@ gk104_fifo_gpfifo_engine_addr(struct nvkm_engine *engine) case NVKM_ENGINE_CE1 : case NVKM_ENGINE_CE2 : return 0x0000; case NVKM_ENGINE_GR : return 0x0210; + case NVKM_ENGINE_SEC : return 0x0220; case NVKM_ENGINE_MSPDEC: return 0x0250; case NVKM_ENGINE_MSPPP : return 0x0260; case NVKM_ENGINE_MSVLD : return 0x0270; + case NVKM_ENGINE_VIC : return 0x0280; + case NVKM_ENGINE_MSENC : return 0x0290; + case NVKM_ENGINE_NVDEC : return 0x02100270; + case NVKM_ENGINE_NVENC0: return 0x02100290; + case NVKM_ENGINE_NVENC1: return 0x0210; default: WARN_ON(1); return 0; @@ -76,9 +82,9 @@ static int gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, struct nvkm_engine *engine, bool suspend) { - const u32 offset = gk104_fifo_gpfifo_engine_addr(engine); struct gk104_fifo_chan *chan = gk104_fifo_chan(base); struct nvkm_gpuobj *inst = chan->base.inst; + u32 offset = gk104_fifo_gpfifo_engine_addr(engine); int ret; ret = gk104_fifo_gpfifo_kick(chan); @@ -87,8 +93,12 @@ gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, if (offset) { nvkm_kmap(inst); - nvkm_wo32(inst, offset + 0x00, 0x00000000); - nvkm_wo32(inst, offset + 0x04, 0x00000000); + nvkm_wo32(inst, (offset & 0xffff) + 0x00, 0x00000000); + nvkm_wo32(inst, (offset & 0xffff) + 0x04, 0x00000000); + if ((offset >>= 16)) { + nvkm_wo32(inst, offset + 0x00, 0x00000000); + nvkm_wo32(inst, offset + 0x04, 0x00000000); + } nvkm_done(inst); } @@ -99,15 +109,21 @@ static int gk104_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base, struct nvkm_engine *engine) { - const u32 offset = gk104_fifo_gpfifo_engine_addr(engine); struct gk104_fifo_chan *chan = gk104_fifo_chan(base); struct nvkm_gpuobj *inst = chan->base.inst; + u32 offset = gk104_fifo_gpfifo_engine_addr(engine); if (offset) { - u64 addr = chan->engn[engine->subdev.index].vma.offset; + u64 addr = chan->engn[engine->subdev.index].vma.offset; + u32 datalo = lower_32_bits(addr) | 0x00000004; + u32 datahi = upper_32_bits(addr); nvkm_kmap(inst); - nvkm_wo32(inst, offset + 0x00, lower_32_bits(addr) | 4); - nvkm_wo32(inst, offset + 0x04, upper_32_bits(addr)); + nvkm_wo32(inst, (offset & 0xffff) + 0x00, datalo); + nvkm_wo32(inst, (offset & 0xffff) + 0x04, datahi); + if ((offset >>= 16)) { + nvkm_wo32(inst, offset + 0x00, datalo); + nvkm_wo32(inst, offset + 0x04, datahi); + } nvkm_done(inst); } @@ -154,7 +170,8 @@ gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base) if (!list_empty(&chan->head)) { gk104_fifo_runlist_remove(fifo, chan); nvkm_mask(device, 0x800004 + coff, 0x00000800, 0x00000800); - gk104_fifo_runlist_commit(fifo, chan->engine); + gk104_fifo_gpfifo_kick(chan); + gk104_fifo_runlist_commit(fifo, chan->runl); } nvkm_wr32(device, 0x800000 + coff, 0x00000000); @@ -169,13 +186,13 @@ gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *base) u32 addr = chan->base.inst->addr >> 12; u32 coff = chan->base.chid * 8; - nvkm_mask(device, 0x800004 + coff, 0x000f0000, chan->engine << 16); + nvkm_mask(device, 0x800004 + coff, 0x000f0000, chan->runl << 16); nvkm_wr32(device, 0x800000 + coff, 0x80000000 | addr); if (list_empty(&chan->head) && !chan->killed) { gk104_fifo_runlist_insert(fifo, chan); nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400); - gk104_fifo_runlist_commit(fifo, chan->engine); + gk104_fifo_runlist_commit(fifo, chan->runl); nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400); } } @@ -201,73 +218,79 @@ gk104_fifo_gpfifo_func = { .engine_fini = gk104_fifo_gpfifo_engine_fini, }; -int -gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) +struct gk104_fifo_chan_func { + u32 engine; + u64 subdev; +}; + +static int +gk104_fifo_gpfifo_new_(const struct gk104_fifo_chan_func *func, + struct gk104_fifo *fifo, u32 *engmask, u16 *chid, + u64 vm, u64 ioffset, u64 ilength, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) { - union { - struct kepler_channel_gpfifo_a_v0 v0; - } *args = data; - struct gk104_fifo *fifo = gk104_fifo(base); struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_object *parent = oclass->parent; struct gk104_fifo_chan *chan; - u64 usermem, ioffset, ilength; - u32 engines; - int ret = -ENOSYS, i; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " - "ioffset %016llx ilength %08x engine %08x\n", - args->v0.version, args->v0.vm, args->v0.ioffset, - args->v0.ilength, args->v0.engine); - } else - return ret; - - /* determine which downstream engines are present */ - for (i = 0, engines = 0; i < ARRAY_SIZE(fifo->engine); i++) { - u64 subdevs = gk104_fifo_engine_subdev(i); - if (!nvkm_device_engine(device, __ffs64(subdevs))) - continue; - engines |= (1 << i); + int runlist = -1, ret = -ENOSYS, i, j; + u32 engines = 0, present = 0; + u64 subdevs = 0; + u64 usermem; + + /* Determine which downstream engines are present */ + for (i = 0; i < fifo->engine_nr; i++) { + struct nvkm_engine *engine = fifo->engine[i].engine; + if (engine) { + u64 submask = BIT_ULL(engine->subdev.index); + for (j = 0; func[j].subdev; j++) { + if (func[j].subdev & submask) { + present |= func[j].engine; + break; + } + } + + if (!func[j].subdev) + continue; + + if (runlist < 0 && (*engmask & present)) + runlist = fifo->engine[i].runl; + if (runlist == fifo->engine[i].runl) { + engines |= func[j].engine; + subdevs |= func[j].subdev; + } + } } - /* if this is an engine mask query, we're done */ - if (!args->v0.engine) { - args->v0.engine = engines; + /* Just an engine mask query? All done here! */ + if (!*engmask) { + *engmask = present; return nvkm_object_new(oclass, NULL, 0, pobject); } - /* check that we support a requested engine - note that the user - * argument is a mask in order to allow the user to request (for - * example) *any* copy engine, but doesn't matter which. - */ - args->v0.engine &= engines; - if (!args->v0.engine) { - nvif_ioctl(parent, "no supported engine\n"); + /* No runlist? No supported engines. */ + *engmask = present; + if (runlist < 0) return -ENODEV; - } + *engmask = engines; - /* allocate the channel */ + /* Allocate the channel. */ if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) return -ENOMEM; *pobject = &chan->base.object; chan->fifo = fifo; - chan->engine = __ffs(args->v0.engine); + chan->runl = runlist; INIT_LIST_HEAD(&chan->head); ret = nvkm_fifo_chan_ctor(&gk104_fifo_gpfifo_func, &fifo->base, - 0x1000, 0x1000, true, args->v0.vm, 0, - gk104_fifo_engine_subdev(chan->engine), + 0x1000, 0x1000, true, vm, 0, subdevs, 1, fifo->user.bar.offset, 0x200, oclass, &chan->base); if (ret) return ret; - args->v0.chid = chan->base.chid; + *chid = chan->base.chid; - /* page directory */ + /* Page directory. */ ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &chan->pgd); if (ret) return ret; @@ -283,10 +306,9 @@ gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, if (ret) return ret; - /* clear channel control registers */ + /* Clear channel control registers. */ usermem = chan->base.chid * 0x200; - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); + ilength = order_base_2(ilength / 8); nvkm_kmap(fifo->user.mem); for (i = 0; i < 0x200; i += 4) @@ -315,6 +337,56 @@ gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, return 0; } +static const struct gk104_fifo_chan_func +gk104_fifo_gpfifo[] = { + { NVA06F_V0_ENGINE_SW | NVA06F_V0_ENGINE_GR, + BIT_ULL(NVKM_ENGINE_SW) | BIT_ULL(NVKM_ENGINE_GR) + }, + { NVA06F_V0_ENGINE_SEC , BIT_ULL(NVKM_ENGINE_SEC ) }, + { NVA06F_V0_ENGINE_MSVLD , BIT_ULL(NVKM_ENGINE_MSVLD ) }, + { NVA06F_V0_ENGINE_MSPDEC, BIT_ULL(NVKM_ENGINE_MSPDEC) }, + { NVA06F_V0_ENGINE_MSPPP , BIT_ULL(NVKM_ENGINE_MSPPP ) }, + { NVA06F_V0_ENGINE_MSENC , BIT_ULL(NVKM_ENGINE_MSENC ) }, + { NVA06F_V0_ENGINE_VIC , BIT_ULL(NVKM_ENGINE_VIC ) }, + { NVA06F_V0_ENGINE_NVDEC , BIT_ULL(NVKM_ENGINE_NVDEC ) }, + { NVA06F_V0_ENGINE_NVENC0, BIT_ULL(NVKM_ENGINE_NVENC0) }, + { NVA06F_V0_ENGINE_NVENC1, BIT_ULL(NVKM_ENGINE_NVENC1) }, + { NVA06F_V0_ENGINE_CE0 , BIT_ULL(NVKM_ENGINE_CE0 ) }, + { NVA06F_V0_ENGINE_CE1 , BIT_ULL(NVKM_ENGINE_CE1 ) }, + { NVA06F_V0_ENGINE_CE2 , BIT_ULL(NVKM_ENGINE_CE2 ) }, + {} +}; + +int +gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + union { + struct kepler_channel_gpfifo_a_v0 v0; + } *args = data; + struct gk104_fifo *fifo = gk104_fifo(base); + int ret = -ENOSYS; + + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " + "ioffset %016llx ilength %08x engine %08x\n", + args->v0.version, args->v0.vm, args->v0.ioffset, + args->v0.ilength, args->v0.engines); + return gk104_fifo_gpfifo_new_(gk104_fifo_gpfifo, fifo, + &args->v0.engines, + &args->v0.chid, + args->v0.vm, + args->v0.ioffset, + args->v0.ilength, + oclass, pobject); + + } + + return ret; +} + const struct nvkm_fifo_chan_oclass gk104_fifo_gpfifo_oclass = { .base.oclass = KEPLER_CHANNEL_GPFIFO_A, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk110.c new file mode 100644 index 000000000..a9aa69c82 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk110.c @@ -0,0 +1,34 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "changk104.h" + +#include + +const struct nvkm_fifo_chan_oclass +gk110_fifo_gpfifo_oclass = { + .base.oclass = KEPLER_CHANNEL_GPFIFO_B, + .base.minver = 0, + .base.maxver = 0, + .ctor = gk104_fifo_gpfifo_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm200.c new file mode 100644 index 000000000..a13315147 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm200.c @@ -0,0 +1,34 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "changk104.h" + +#include + +const struct nvkm_fifo_chan_oclass +gm200_fifo_gpfifo_oclass = { + .base.oclass = MAXWELL_CHANNEL_GPFIFO_A, + .base.minver = 0, + .base.maxver = 0, + .ctor = gk104_fifo_gpfifo_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c deleted file mode 100644 index 6511d6e21..000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2015 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ -#include "changk104.h" - -#include - -const struct nvkm_fifo_chan_oclass -gm204_fifo_gpfifo_oclass = { - .base.oclass = MAXWELL_CHANNEL_GPFIFO_A, - .base.minver = 0, - .base.maxver = 0, - .ctor = gk104_fifo_gpfifo_new, -}; -- cgit v1.2.3-54-g00ecf