Commit 9a65a38c authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/fifo: split user classes out from engine implementations



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 0ce41e3c
Loading
Loading
Loading
Loading
+0 −24
Original line number Diff line number Diff line
@@ -18,30 +18,6 @@ nvkm_fifo_chan(void *obj)
	return (void *)nv_namedb(obj);
}

#define nvkm_fifo_channel_create(p,e,c,b,a,s,n,m,d)                         \
	nvkm_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n),        \
				     (m), sizeof(**d), (void **)d)
#define nvkm_fifo_channel_init(p)                                           \
	nvkm_namedb_init(&(p)->namedb)
#define nvkm_fifo_channel_fini(p,s)                                         \
	nvkm_namedb_fini(&(p)->namedb, (s))

int  nvkm_fifo_channel_create_(struct nvkm_object *,
				  struct nvkm_object *,
				  struct nvkm_oclass *,
				  int bar, u32 addr, u32 size, u64 push,
				  u64 engmask, int len, void **);
void nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *);

#define _nvkm_fifo_channel_init _nvkm_namedb_init
#define _nvkm_fifo_channel_fini _nvkm_namedb_fini

void _nvkm_fifo_channel_dtor(struct nvkm_object *);
int  _nvkm_fifo_channel_map(struct nvkm_object *, u64 *, u32 *);
u32  _nvkm_fifo_channel_rd32(struct nvkm_object *, u64);
void _nvkm_fifo_channel_wr32(struct nvkm_object *, u64, u32);
int  _nvkm_fifo_channel_ntfy(struct nvkm_object *, u32, struct nvkm_event **);

#include <core/gpuobj.h>

struct nvkm_fifo_base {
+17 −0
Original line number Diff line number Diff line
@@ -11,3 +11,20 @@ nvkm-y += nvkm/engine/fifo/gk20a.o
nvkm-y += nvkm/engine/fifo/gk208.o
nvkm-y += nvkm/engine/fifo/gm204.o
nvkm-y += nvkm/engine/fifo/gm20b.o

nvkm-y += nvkm/engine/fifo/chan.o
nvkm-y += nvkm/engine/fifo/channv50.o
nvkm-y += nvkm/engine/fifo/chang84.o

nvkm-y += nvkm/engine/fifo/dmanv04.o
nvkm-y += nvkm/engine/fifo/dmanv10.o
nvkm-y += nvkm/engine/fifo/dmanv17.o
nvkm-y += nvkm/engine/fifo/dmanv40.o
nvkm-y += nvkm/engine/fifo/dmanv50.o
nvkm-y += nvkm/engine/fifo/dmag84.o

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
+29 −165
Original line number Diff line number Diff line
@@ -21,14 +21,12 @@
 *
 * Authors: Ben Skeggs
 */
#include <engine/fifo.h>
#include "priv.h"
#include "chan.h"

#include <core/client.h>
#include <core/handle.h>
#include <core/notify.h>
#include <engine/dma.h>

#include <nvif/class.h>
#include <nvif/event.h>
#include <nvif/unpack.h>

@@ -74,138 +72,51 @@ nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags)
}

static int
nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size,
		     struct nvkm_notify *notify)
{
	if (size == 0) {
		notify->size  = 0;
		notify->types = 1;
		notify->index = 0;
		return 0;
	}
	return -ENOSYS;
}

static const struct nvkm_event_func
nvkm_fifo_event_func = {
	.ctor = nvkm_fifo_event_ctor,
};

int
nvkm_fifo_channel_create_(struct nvkm_object *parent,
			  struct nvkm_object *engine,
			  struct nvkm_oclass *oclass,
			  int bar, u32 addr, u32 size, u64 pushbuf,
			  u64 engmask, int len, void **ptr)
nvkm_fifo_chid(struct nvkm_fifo *fifo, struct nvkm_object *object)
{
	struct nvkm_client *client = nvkm_client(parent);
	struct nvkm_dmaobj *dmaobj;
	struct nvkm_fifo *fifo = (void *)engine;
	struct nvkm_fifo_base *base = (void *)parent;
	struct nvkm_fifo_chan *chan;
	struct nvkm_subdev *subdev = &fifo->engine.subdev;
	struct nvkm_device *device = subdev->device;
	struct nvkm_dma *dma = device->dma;
	unsigned long flags;
	int ret;

	/* create base object class */
	ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL,
				  engmask, len, ptr);
	chan = *ptr;
	if (ret)
		return ret;

	/* validate dma object representing push buffer */
	if (pushbuf) {
		dmaobj = nvkm_dma_search(dma, client, pushbuf);
		if (!dmaobj)
			return -ENOENT;

		ret = dmaobj->func->bind(dmaobj, &base->gpuobj, 16,
					 &chan->pushgpu);
		if (ret)
			return ret;
	}

	/* find a free fifo channel */
	spin_lock_irqsave(&fifo->lock, flags);
	for (chan->chid = fifo->min; chan->chid < fifo->max; chan->chid++) {
		if (!fifo->channel[chan->chid]) {
			fifo->channel[chan->chid] = nv_object(chan);
			break;
		}
	}
	spin_unlock_irqrestore(&fifo->lock, flags);
	int engidx = nv_hclass(fifo) & 0xff;

	if (chan->chid == fifo->max) {
		nvkm_error(subdev, "no free channels\n");
		return -ENOSPC;
	while (object && object->parent) {
		if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) &&
		    (nv_hclass(object->parent) & 0xff) == engidx)
			return nvkm_fifo_chan(object)->chid;
		object = object->parent;
	}

	chan->addr = nv_device_resource_start(device, bar) +
		     addr + size * chan->chid;
	chan->size = size;
	nvkm_event_send(&fifo->cevent, 1, 0, NULL, 0);
	return 0;
	return -1;
}

void
nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan)
const char *
nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid)
{
	struct nvkm_fifo *fifo = (void *)nv_object(chan)->engine;
	struct nvkm_fifo_chan *chan = NULL;
	unsigned long flags;

	if (chan->user)
		iounmap(chan->user);

	spin_lock_irqsave(&fifo->lock, flags);
	fifo->channel[chan->chid] = NULL;
	if (chid >= fifo->min && chid <= fifo->max)
		chan = (void *)fifo->channel[chid];
	spin_unlock_irqrestore(&fifo->lock, flags);

	nvkm_gpuobj_del(&chan->pushgpu);
	nvkm_namedb_destroy(&chan->namedb);
}

void
_nvkm_fifo_channel_dtor(struct nvkm_object *object)
{
	struct nvkm_fifo_chan *chan = (void *)object;
	nvkm_fifo_channel_destroy(chan);
}

int
_nvkm_fifo_channel_map(struct nvkm_object *object, u64 *addr, u32 *size)
{
	struct nvkm_fifo_chan *chan = (void *)object;
	*addr = chan->addr;
	*size = chan->size;
	return 0;
	return nvkm_client_name(chan);
}

u32
_nvkm_fifo_channel_rd32(struct nvkm_object *object, u64 addr)
static int
nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size,
		     struct nvkm_notify *notify)
{
	struct nvkm_fifo_chan *chan = (void *)object;
	if (unlikely(!chan->user)) {
		chan->user = ioremap(chan->addr, chan->size);
		if (WARN_ON_ONCE(chan->user == NULL))
	if (size == 0) {
		notify->size  = 0;
		notify->types = 1;
		notify->index = 0;
		return 0;
	}
	return ioread32_native(chan->user + addr);
	return -ENOSYS;
}

void
_nvkm_fifo_channel_wr32(struct nvkm_object *object, u64 addr, u32 data)
{
	struct nvkm_fifo_chan *chan = (void *)object;
	if (unlikely(!chan->user)) {
		chan->user = ioremap(chan->addr, chan->size);
		if (WARN_ON_ONCE(chan->user == NULL))
			return;
	}
	iowrite32_native(data, chan->user + addr);
}
static const struct nvkm_event_func
nvkm_fifo_event_func = {
	.ctor = nvkm_fifo_event_ctor,
};

int
nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
@@ -233,53 +144,6 @@ nvkm_fifo_uevent(struct nvkm_fifo *fifo)
	nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep));
}

int
_nvkm_fifo_channel_ntfy(struct nvkm_object *object, u32 type,
			struct nvkm_event **event)
{
	struct nvkm_fifo *fifo = (void *)object->engine;
	switch (type) {
	case G82_CHANNEL_DMA_V0_NTFY_UEVENT:
		if (nv_mclass(object) >= G82_CHANNEL_DMA) {
			*event = &fifo->uevent;
			return 0;
		}
		break;
	default:
		break;
	}
	return -EINVAL;
}

static int
nvkm_fifo_chid(struct nvkm_fifo *fifo, struct nvkm_object *object)
{
	int engidx = nv_hclass(fifo) & 0xff;

	while (object && object->parent) {
		if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) &&
		    (nv_hclass(object->parent) & 0xff) == engidx)
			return nvkm_fifo_chan(object)->chid;
		object = object->parent;
	}

	return -1;
}

const char *
nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid)
{
	struct nvkm_fifo_chan *chan = NULL;
	unsigned long flags;

	spin_lock_irqsave(&fifo->lock, flags);
	if (chid >= fifo->min && chid <= fifo->max)
		chan = (void *)fifo->channel[chid];
	spin_unlock_irqrestore(&fifo->lock, flags);

	return nvkm_client_name(chan);
}

void
nvkm_fifo_destroy(struct nvkm_fifo *fifo)
{
+162 −0
Original line number Diff line number Diff line
/*
 * Copyright 2012 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 "chan.h"

#include <core/client.h>
#include <engine/dma.h>

#include <nvif/class.h>

int
_nvkm_fifo_channel_ntfy(struct nvkm_object *object, u32 type,
			struct nvkm_event **event)
{
	struct nvkm_fifo *fifo = (void *)object->engine;
	switch (type) {
	case G82_CHANNEL_DMA_V0_NTFY_UEVENT:
		if (nv_mclass(object) >= G82_CHANNEL_DMA) {
			*event = &fifo->uevent;
			return 0;
		}
		break;
	default:
		break;
	}
	return -EINVAL;
}

int
_nvkm_fifo_channel_map(struct nvkm_object *object, u64 *addr, u32 *size)
{
	struct nvkm_fifo_chan *chan = (void *)object;
	*addr = chan->addr;
	*size = chan->size;
	return 0;
}

u32
_nvkm_fifo_channel_rd32(struct nvkm_object *object, u64 addr)
{
	struct nvkm_fifo_chan *chan = (void *)object;
	if (unlikely(!chan->user)) {
		chan->user = ioremap(chan->addr, chan->size);
		if (WARN_ON_ONCE(chan->user == NULL))
			return 0;
	}
	return ioread32_native(chan->user + addr);
}

void
_nvkm_fifo_channel_wr32(struct nvkm_object *object, u64 addr, u32 data)
{
	struct nvkm_fifo_chan *chan = (void *)object;
	if (unlikely(!chan->user)) {
		chan->user = ioremap(chan->addr, chan->size);
		if (WARN_ON_ONCE(chan->user == NULL))
			return;
	}
	iowrite32_native(data, chan->user + addr);
}

void
nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan)
{
	struct nvkm_fifo *fifo = (void *)nv_object(chan)->engine;
	unsigned long flags;

	if (chan->user)
		iounmap(chan->user);

	spin_lock_irqsave(&fifo->lock, flags);
	fifo->channel[chan->chid] = NULL;
	spin_unlock_irqrestore(&fifo->lock, flags);

	nvkm_gpuobj_del(&chan->pushgpu);
	nvkm_namedb_destroy(&chan->namedb);
}

void
_nvkm_fifo_channel_dtor(struct nvkm_object *object)
{
	struct nvkm_fifo_chan *chan = (void *)object;
	nvkm_fifo_channel_destroy(chan);
}

int
nvkm_fifo_channel_create_(struct nvkm_object *parent,
			  struct nvkm_object *engine,
			  struct nvkm_oclass *oclass,
			  int bar, u32 addr, u32 size, u64 pushbuf,
			  u64 engmask, int len, void **ptr)
{
	struct nvkm_client *client = nvkm_client(parent);
	struct nvkm_fifo *fifo = (void *)engine;
	struct nvkm_fifo_base *base = (void *)parent;
	struct nvkm_fifo_chan *chan;
	struct nvkm_subdev *subdev = &fifo->engine.subdev;
	struct nvkm_device *device = subdev->device;
	struct nvkm_dmaobj *dmaobj;
	unsigned long flags;
	int ret;

	/* create base object class */
	ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL,
				  engmask, len, ptr);
	chan = *ptr;
	if (ret)
		return ret;

	/* validate dma object representing push buffer */
	if (pushbuf) {
		dmaobj = nvkm_dma_search(device->dma, client, pushbuf);
		if (!dmaobj)
			return -ENOENT;

		ret = nvkm_object_bind(&dmaobj->object, &base->gpuobj, 16,
				       &chan->pushgpu);
		if (ret)
			return ret;
	}

	/* find a free fifo channel */
	spin_lock_irqsave(&fifo->lock, flags);
	for (chan->chid = fifo->min; chan->chid < fifo->max; chan->chid++) {
		if (!fifo->channel[chan->chid]) {
			fifo->channel[chan->chid] = nv_object(chan);
			break;
		}
	}
	spin_unlock_irqrestore(&fifo->lock, flags);

	if (chan->chid == fifo->max) {
		nvkm_error(subdev, "no free channels\n");
		return -ENOSPC;
	}

	chan->addr = nv_device_resource_start(device, bar) +
		     addr + size * chan->chid;
	chan->size = size;
	nvkm_event_send(&fifo->cevent, 1, 0, NULL, 0);
	return 0;
}
+28 −0
Original line number Diff line number Diff line
#ifndef __NVKM_FIFO_CHAN_H__
#define __NVKM_FIFO_CHAN_H__
#include "priv.h"

#define nvkm_fifo_channel_create(p,e,c,b,a,s,n,m,d)                         \
	nvkm_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n),        \
				     (m), sizeof(**d), (void **)d)
#define nvkm_fifo_channel_init(p)                                           \
	nvkm_namedb_init(&(p)->namedb)
#define nvkm_fifo_channel_fini(p,s)                                         \
	nvkm_namedb_fini(&(p)->namedb, (s))

int  nvkm_fifo_channel_create_(struct nvkm_object *,
				  struct nvkm_object *,
				  struct nvkm_oclass *,
				  int bar, u32 addr, u32 size, u64 push,
				  u64 engmask, int len, void **);
void nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *);

#define _nvkm_fifo_channel_init _nvkm_namedb_init
#define _nvkm_fifo_channel_fini _nvkm_namedb_fini

void _nvkm_fifo_channel_dtor(struct nvkm_object *);
int  _nvkm_fifo_channel_map(struct nvkm_object *, u64 *, u32 *);
u32  _nvkm_fifo_channel_rd32(struct nvkm_object *, u64);
void _nvkm_fifo_channel_wr32(struct nvkm_object *, u64, u32);
int  _nvkm_fifo_channel_ntfy(struct nvkm_object *, u32, struct nvkm_event **);
#endif
Loading