const struct nvkm_fifo_func *func;
struct nvkm_engine engine;
+ struct nvkm_chid *chid;
+ struct nvkm_chid *cgid;
+
DECLARE_BITMAP(mask, NVKM_FIFO_CHID_NR);
int nr;
struct list_head chan;
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/engine/fifo/base.o
+nvkm-y += nvkm/engine/fifo/chan.o
+nvkm-y += nvkm/engine/fifo/chid.o
+
nvkm-y += nvkm/engine/fifo/nv04.o
nvkm-y += nvkm/engine/fifo/nv10.o
nvkm-y += nvkm/engine/fifo/nv17.o
nvkm-y += nvkm/engine/fifo/tu102.o
nvkm-y += nvkm/engine/fifo/ga102.o
-nvkm-y += nvkm/engine/fifo/chan.o
nvkm-y += nvkm/engine/fifo/channv50.o
nvkm-y += nvkm/engine/fifo/chang84.o
*/
#include "priv.h"
#include "chan.h"
+#include "chid.h"
#include <core/gpuobj.h>
#include <subdev/mc.h>
nvkm_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data)
{
struct nvkm_fifo *fifo = nvkm_fifo(engine);
+
switch (mthd) {
- case NV_DEVICE_HOST_CHANNELS: *data = fifo->nr; return 0;
+ case NV_DEVICE_HOST_CHANNELS: *data = fifo->chid ? fifo->chid->nr : 0; return 0;
default:
if (fifo->func->info)
return fifo->func->info(fifo, mthd, data);
break;
}
+
return -ENOSYS;
}
nvkm_fifo_oneinit(struct nvkm_engine *engine)
{
struct nvkm_fifo *fifo = nvkm_fifo(engine);
+ int ret;
+
+ /* Initialise CHID/CGID allocator(s) on GPUs where they aren't per-runlist. */
+ if (fifo->func->chid_nr) {
+ ret = fifo->func->chid_ctor(fifo, fifo->func->chid_nr(fifo));
+ if (ret)
+ return ret;
+ }
+
if (fifo->func->oneinit)
return fifo->func->oneinit(fifo);
+
return 0;
}
{
struct nvkm_fifo *fifo = nvkm_fifo(engine);
void *data = fifo;
+
+ nvkm_chid_unref(&fifo->cgid);
+ nvkm_chid_unref(&fifo->chid);
+
if (fifo->func->dtor)
data = fifo->func->dtor(fifo);
nvkm_event_fini(&fifo->kevent);
fifo->nr = NVKM_FIFO_CHID_NR;
else
fifo->nr = nr;
- bitmap_clear(fifo->mask, 0, fifo->nr);
if (func->uevent_init) {
ret = nvkm_event_init(&nvkm_fifo_uevent_func, &fifo->engine.subdev, 1, 1,
#include <nvif/if0020.h>
+const struct nvkm_event_func
+nvkm_chan_event = {
+};
+
struct nvkm_fifo_chan_object {
struct nvkm_oproxy oproxy;
struct nvkm_fifo_chan *chan;
#define nvkm_chan(p) container_of((p), struct nvkm_chan, object) /*FIXME: remove later */
#include <engine/fifo.h>
+extern const struct nvkm_event_func nvkm_chan_event;
+
struct nvkm_chan_func {
void *(*dtor)(struct nvkm_fifo_chan *);
void (*init)(struct nvkm_fifo_chan *);
--- /dev/null
+/*
+ * Copyright 2020 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.
+ */
+#include "chid.h"
+
+static void
+nvkm_chid_del(struct kref *kref)
+{
+ struct nvkm_chid *chid = container_of(kref, typeof(*chid), kref);
+
+ nvkm_event_fini(&chid->event);
+
+ kvfree(chid->data);
+ kfree(chid);
+}
+
+void
+nvkm_chid_unref(struct nvkm_chid **pchid)
+{
+ struct nvkm_chid *chid = *pchid;
+
+ if (!chid)
+ return;
+
+ kref_put(&chid->kref, nvkm_chid_del);
+ *pchid = NULL;
+}
+
+struct nvkm_chid *
+nvkm_chid_ref(struct nvkm_chid *chid)
+{
+ if (chid)
+ kref_get(&chid->kref);
+
+ return chid;
+}
+
+int
+nvkm_chid_new(const struct nvkm_event_func *func, struct nvkm_subdev *subdev,
+ int nr, int first, int count, struct nvkm_chid **pchid)
+{
+ struct nvkm_chid *chid;
+ int id;
+
+ if (!(chid = *pchid = kzalloc(struct_size(chid, used, nr), GFP_KERNEL)))
+ return -ENOMEM;
+
+ kref_init(&chid->kref);
+ chid->nr = nr;
+ chid->mask = chid->nr - 1;
+ spin_lock_init(&chid->lock);
+
+ if (!(chid->data = kvzalloc(sizeof(*chid->data) * nr, GFP_KERNEL))) {
+ nvkm_chid_unref(pchid);
+ return -ENOMEM;
+ }
+
+ for (id = 0; id < first; id++)
+ __set_bit(id, chid->used);
+ for (id = first + count; id < nr; id++)
+ __set_bit(id, chid->used);
+
+ return nvkm_event_init(func, subdev, 1, nr, &chid->event);
+}
--- /dev/null
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVKM_CHID_H__
+#define __NVKM_CHID_H__
+#include <core/event.h>
+
+struct nvkm_chid {
+ struct kref kref;
+ int nr;
+ u32 mask;
+
+ struct nvkm_event event;
+
+ void **data;
+
+ spinlock_t lock;
+ unsigned long used[];
+};
+
+int nvkm_chid_new(const struct nvkm_event_func *, struct nvkm_subdev *,
+ int nr, int first, int count, struct nvkm_chid **pchid);
+struct nvkm_chid *nvkm_chid_ref(struct nvkm_chid *);
+void nvkm_chid_unref(struct nvkm_chid **);
+#endif
.dtor = nv50_fifo_dtor,
.oneinit = nv50_fifo_oneinit,
.chid_nr = nv50_fifo_chid_nr,
+ .chid_ctor = nv50_fifo_chid_ctor,
.init = nv50_fifo_init,
.intr = nv04_fifo_intr,
.engine_id = g84_fifo_engine_id,
* Authors: Ben Skeggs
*/
#include "chan.h"
+#include "chid.h"
#include "gf100.h"
#include "changf100.h"
nvkm_wr32(device, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
}
+int
+gf100_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr)
+{
+ return nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 0, nr, &fifo->chid);
+}
+
static int
gf100_fifo_oneinit(struct nvkm_fifo *base)
{
.dtor = gf100_fifo_dtor,
.oneinit = gf100_fifo_oneinit,
.chid_nr = nv50_fifo_chid_nr,
+ .chid_ctor = gf100_fifo_chid_ctor,
.init = gf100_fifo_init,
.fini = gf100_fifo_fini,
.intr = gf100_fifo_intr,
* Authors: Ben Skeggs
*/
#include "chan.h"
+#include "chid.h"
#include "gk104.h"
#include "cgrp.h"
.dtor = gk104_fifo_dtor,
.oneinit = gk104_fifo_oneinit,
.chid_nr = gk104_fifo_chid_nr,
+ .chid_ctor = gf100_fifo_chid_ctor,
.info = gk104_fifo_info,
.init = gk104_fifo_init,
.fini = gk104_fifo_fini,
void gk104_fifo_intr_runlist(struct gk104_fifo *fifo);
void gk104_fifo_intr_engine(struct gk104_fifo *fifo);
void *gk104_fifo_dtor(struct nvkm_fifo *base);
-int gk104_fifo_oneinit(struct nvkm_fifo *base);
+int gk104_fifo_oneinit(struct nvkm_fifo *);
int gk104_fifo_info(struct nvkm_fifo *base, u64 mthd, u64 *data);
void gk104_fifo_init(struct nvkm_fifo *base);
void gk104_fifo_fini(struct nvkm_fifo *base);
*/
#include "cgrp.h"
#include "chan.h"
+#include "chid.h"
#include "gk104.h"
#include "changk104.h"
.commit = gk104_fifo_runlist_commit,
};
+int
+gk110_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr)
+{
+ int ret;
+
+ ret = nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 0, nr, &fifo->cgid);
+ if (ret)
+ return ret;
+
+ return gf100_fifo_chid_ctor(fifo, nr);
+}
+
static const struct nvkm_fifo_func
gk110_fifo = {
.dtor = gk104_fifo_dtor,
.oneinit = gk104_fifo_oneinit,
.chid_nr = gk104_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
.info = gk104_fifo_info,
.init = gk104_fifo_init,
.fini = gk104_fifo_fini,
.dtor = gk104_fifo_dtor,
.oneinit = gk104_fifo_oneinit,
.chid_nr = gk208_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
.info = gk104_fifo_info,
.init = gk104_fifo_init,
.fini = gk104_fifo_fini,
.dtor = gk104_fifo_dtor,
.oneinit = gk104_fifo_oneinit,
.chid_nr = nv50_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
.info = gk104_fifo_info,
.init = gk104_fifo_init,
.fini = gk104_fifo_fini,
.dtor = gk104_fifo_dtor,
.oneinit = gk104_fifo_oneinit,
.chid_nr = gm107_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
.info = gk104_fifo_info,
.init = gk104_fifo_init,
.fini = gk104_fifo_fini,
.dtor = gk104_fifo_dtor,
.oneinit = gk104_fifo_oneinit,
.chid_nr = gm200_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
.info = gk104_fifo_info,
.init = gk104_fifo_init,
.fini = gk104_fifo_fini,
.dtor = gk104_fifo_dtor,
.oneinit = gk104_fifo_oneinit,
.chid_nr = gm200_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
.info = gk104_fifo_info,
.init = gk104_fifo_init,
.fini = gk104_fifo_fini,
.dtor = gk104_fifo_dtor,
.oneinit = gk104_fifo_oneinit,
.chid_nr = gm200_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
.info = gk104_fifo_info,
.init = gk104_fifo_init,
.fini = gk104_fifo_fini,
*/
#include "cgrp.h"
#include "chan.h"
+#include "chid.h"
#include "nv04.h"
#include "channv04.h"
struct nvkm_memory *fctx = device->imem->ramfc;
const struct nv04_fifo_ramfc *c;
unsigned long flags;
- u32 mask = fifo->base.nr - 1;
u32 data = chan->ramfc;
u32 chid;
nvkm_wr32(device, NV03_PFIFO_CACHES, 0);
/* if this channel is active, replace it with a null context */
- chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & mask;
+ chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.chid->mask;
if (chid == chan->base.chid) {
nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0);
nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0);
nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0);
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, mask);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.chid->mask);
nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1);
nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1);
}
reassign = nvkm_rd32(device, NV03_PFIFO_CACHES) & 1;
nvkm_wr32(device, NV03_PFIFO_CACHES, 0);
- chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & (fifo->base.nr - 1);
+ chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.chid->mask;
get = nvkm_rd32(device, NV03_PFIFO_CACHE1_GET);
if (stat & NV_PFIFO_INTR_CACHE_ERROR) {
}
void
-nv04_fifo_init(struct nvkm_fifo *base)
+nv04_fifo_init(struct nvkm_fifo *fifo)
{
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_device *device = fifo->engine.subdev.device;
struct nvkm_instmem *imem = device->imem;
struct nvkm_ramht *ramht = imem->ramht;
struct nvkm_memory *ramro = imem->ramro;
nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8);
nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8);
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask);
nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff);
nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff);
nvkm_wr32(device, NV03_PFIFO_CACHES, 1);
}
+int
+nv04_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr)
+{
+ /* The last CHID is reserved by HW as a "channel invalid" marker. */
+ return nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 0, nr - 1, &fifo->chid);
+}
+
static int
nv04_fifo_chid_nr(struct nvkm_fifo *fifo)
{
static const struct nvkm_fifo_func
nv04_fifo = {
.chid_nr = nv04_fifo_chid_nr,
+ .chid_ctor = nv04_fifo_chid_ctor,
.init = nv04_fifo_init,
.intr = nv04_fifo_intr,
.engine_id = nv04_fifo_engine_id,
int nv04_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
int nr, const struct nv04_fifo_ramfc *, struct nvkm_fifo **);
-void nv04_fifo_init(struct nvkm_fifo *);
#endif
static const struct nvkm_fifo_func
nv10_fifo = {
.chid_nr = nv10_fifo_chid_nr,
+ .chid_ctor = nv04_fifo_chid_ctor,
.init = nv04_fifo_init,
.intr = nv04_fifo_intr,
.engine_id = nv04_fifo_engine_id,
* Authors: Ben Skeggs
*/
#include "chan.h"
+#include "chid.h"
#include "nv04.h"
#include "channv04.h"
};
static void
-nv17_fifo_init(struct nvkm_fifo *base)
+nv17_fifo_init(struct nvkm_fifo *fifo)
{
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_device *device = fifo->engine.subdev.device;
struct nvkm_instmem *imem = device->imem;
struct nvkm_ramht *ramht = imem->ramht;
struct nvkm_memory *ramro = imem->ramro;
nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8 |
0x00010000);
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask);
nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff);
nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff);
static const struct nvkm_fifo_func
nv17_fifo = {
.chid_nr = nv10_fifo_chid_nr,
+ .chid_ctor = nv04_fifo_chid_ctor,
.init = nv17_fifo_init,
.intr = nv04_fifo_intr,
.engine_id = nv04_fifo_engine_id,
* Authors: Ben Skeggs
*/
#include "chan.h"
+#include "chid.h"
#include "nv04.h"
#include "channv04.h"
};
static void
-nv40_fifo_init(struct nvkm_fifo *base)
+nv40_fifo_init(struct nvkm_fifo *fifo)
{
- struct nv04_fifo *fifo = nv04_fifo(base);
- struct nvkm_device *device = fifo->base.engine.subdev.device;
+ struct nvkm_device *device = fifo->engine.subdev.device;
struct nvkm_fb *fb = device->fb;
struct nvkm_instmem *imem = device->imem;
struct nvkm_ramht *ramht = imem->ramht;
break;
}
- nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1);
+ nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->chid->mask);
nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff);
nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff);
static const struct nvkm_fifo_func
nv40_fifo = {
.chid_nr = nv10_fifo_chid_nr,
+ .chid_ctor = nv04_fifo_chid_ctor,
.init = nv40_fifo_init,
.intr = nv04_fifo_intr,
.engine_id = nv04_fifo_engine_id,
* Authors: Ben Skeggs
*/
#include "chan.h"
+#include "chid.h"
#include "nv50.h"
#include "channv50.h"
nvkm_wr32(device, 0x002500, 0x00000001);
}
+int
+nv50_fifo_chid_ctor(struct nvkm_fifo *fifo, int nr)
+{
+ /* CHID 0 is unusable (some kind of PIO channel?), 127 is "channel invalid". */
+ return nvkm_chid_new(&nvkm_chan_event, &fifo->engine.subdev, nr, 1, nr - 2, &fifo->chid);
+}
+
int
nv50_fifo_chid_nr(struct nvkm_fifo *fifo)
{
.dtor = nv50_fifo_dtor,
.oneinit = nv50_fifo_oneinit,
.chid_nr = nv50_fifo_chid_nr,
+ .chid_ctor = nv50_fifo_chid_ctor,
.init = nv50_fifo_init,
.intr = nv04_fifo_intr,
.engine_id = nv04_fifo_engine_id,
int (*oneinit)(struct nvkm_fifo *);
int (*chid_nr)(struct nvkm_fifo *);
+ int (*chid_ctor)(struct nvkm_fifo *, int nr);
int (*info)(struct nvkm_fifo *, u64 mthd, u64 *data);
void (*init)(struct nvkm_fifo *);
int nvkm_fifo_ctor(const struct nvkm_fifo_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_fifo *);
+int nv04_fifo_chid_ctor(struct nvkm_fifo *, int);
+void nv04_fifo_init(struct nvkm_fifo *);
void nv04_fifo_intr(struct nvkm_fifo *);
int nv04_fifo_engine_id(struct nvkm_fifo *, struct nvkm_engine *);
struct nvkm_engine *nv04_fifo_id_engine(struct nvkm_fifo *, int);
int nv10_fifo_chid_nr(struct nvkm_fifo *);
int nv50_fifo_chid_nr(struct nvkm_fifo *);
+int nv50_fifo_chid_ctor(struct nvkm_fifo *, int);
extern const struct nvkm_chan_func g84_chan;
+int gf100_fifo_chid_ctor(struct nvkm_fifo *, int);
void gf100_fifo_intr_mmu_fault_unit(struct nvkm_fifo *, int);
int gk104_fifo_chid_nr(struct nvkm_fifo *);
int gk104_fifo_engine_id(struct nvkm_fifo *, struct nvkm_engine *);
struct nvkm_engine *gk104_fifo_id_engine(struct nvkm_fifo *, int);
+int gk110_fifo_chid_ctor(struct nvkm_fifo *, int);
extern const struct nvkm_cgrp_func gk110_cgrp;
extern const struct nvkm_chan_func gk110_chan;
.dtor = gk104_fifo_dtor,
.oneinit = gk104_fifo_oneinit,
.chid_nr = gm200_fifo_chid_nr,
+ .chid_ctor = gk110_fifo_chid_ctor,
.info = gk104_fifo_info,
.init = gk104_fifo_init,
.fini = gk104_fifo_fini,