Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 51cb4b39 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/core: convert event handler apis to split create/enable semantics



This is a necessary step towards being able to work with the insane locking
requirements of the DRM core's vblank routines, and a nice cleanup as a
side-effect.

This is similar in spirit to the interfaces that Peter Hurley arrived at
with his nouveau_event rcu conversion series.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 7589563e
Loading
Loading
Loading
Loading
+59 −16
Original line number Diff line number Diff line
@@ -37,39 +37,82 @@ nouveau_event_put_locked(struct nouveau_event *event, int index,
}

void
nouveau_event_put(struct nouveau_event *event, int index,
		  struct nouveau_eventh *handler)
nouveau_event_put(struct nouveau_eventh *handler)
{
	struct nouveau_event *event = handler->event;
	unsigned long flags;

	if (index >= event->index_nr)
		return;

	spin_lock_irqsave(&event->lock, flags);
	nouveau_event_put_locked(event, index, handler);
	nouveau_event_put_locked(handler->event, handler->index, handler);
	spin_unlock_irqrestore(&event->lock, flags);
}

void
nouveau_event_get(struct nouveau_event *event, int index,
		  struct nouveau_eventh *handler)
nouveau_event_get(struct nouveau_eventh *handler)
{
	struct nouveau_event *event = handler->event;
	unsigned long flags;

	if (index >= event->index_nr)
		return;

	spin_lock_irqsave(&event->lock, flags);
	if (!__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) {
		list_add(&handler->head, &event->index[index].list);
		if (!event->index[index].refs++) {
		list_add(&handler->head, &event->index[handler->index].list);
		if (!event->index[handler->index].refs++) {
			if (event->enable)
				event->enable(event, index);
				event->enable(event, handler->index);
		}
	}
	spin_unlock_irqrestore(&event->lock, flags);
}

static void
nouveau_event_fini(struct nouveau_eventh *handler)
{
	nouveau_event_put(handler);
}

static int
nouveau_event_init(struct nouveau_event *event, int index,
		   int (*func)(void *, int), void *priv,
		   struct nouveau_eventh *handler)
{
	if (index >= event->index_nr)
		return -EINVAL;
	handler->event = event;
	handler->flags = 0;
	handler->index = index;
	handler->func = func;
	handler->priv = priv;
	return 0;
}

int
nouveau_event_new(struct nouveau_event *event, int index,
		  int (*func)(void *, int), void *priv,
		  struct nouveau_eventh **phandler)
{
	struct nouveau_eventh *handler;
	int ret = -ENOMEM;

	handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL);
	if (handler) {
		ret = nouveau_event_init(event, index, func, priv, handler);
		if (ret)
			kfree(handler);
	}

	return ret;
}

void
nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref)
{
	BUG_ON(handler != NULL);
	if (*ref) {
		nouveau_event_fini(*ref);
		kfree(*ref);
	}
	*ref = handler;
}

void
nouveau_event_trigger(struct nouveau_event *event, int index)
{
@@ -81,7 +124,7 @@ nouveau_event_trigger(struct nouveau_event *event, int index)

	spin_lock_irqsave(&event->lock, flags);
	list_for_each_entry_safe(handler, temp, &event->index[index].list, head) {
		if (handler->func(handler, index) == NVKM_EVENT_DROP) {
		if (handler->func(handler->priv, index) == NVKM_EVENT_DROP) {
			nouveau_event_put_locked(event, index, handler);
		}
	}
+38 −12
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
	return 0;
}

static int
int
nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
				void *args, u32 size)
{
@@ -80,21 +80,20 @@ nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
	return 0;
}

static int
int
nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
				  void *args, u32 size)
{
	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
	struct nouveau_disp *disp = nouveau_disp(object);
	u32 crtc = *(u32 *)args;
	if (crtc > 1)
	u32 head = *(u32 *)args;
	if (head >= chan->vblank.nr_event)
		return -EINVAL;

	nouveau_event_get(disp->vblank, crtc, &chan->vblank.event);
	nouveau_event_get(chan->vblank.event[head]);
	return 0;
}

static int
int
nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd,
			void *args, u32 size)
{
@@ -125,10 +124,9 @@ nv50_software_sclass[] = {
 ******************************************************************************/

static int
nv50_software_vblsem_release(struct nouveau_eventh *event, int head)
nv50_software_vblsem_release(void *data, int head)
{
	struct nv50_software_chan *chan =
		container_of(event, typeof(*chan), vblank.event);
	struct nv50_software_chan *chan = data;
	struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
	struct nouveau_bar *bar = nouveau_bar(priv);

@@ -147,23 +145,51 @@ nv50_software_vblsem_release(struct nouveau_eventh *event, int head)
	return NVKM_EVENT_DROP;
}

void
nv50_software_context_dtor(struct nouveau_object *object)
{
	struct nv50_software_chan *chan = (void *)object;
	int i;

	if (chan->vblank.event) {
		for (i = 0; i < chan->vblank.nr_event; i++)
			nouveau_event_ref(NULL, &chan->vblank.event[i]);
		kfree(chan->vblank.event);
	}

	nouveau_software_context_destroy(&chan->base);
}

int
nv50_software_context_ctor(struct nouveau_object *parent,
			   struct nouveau_object *engine,
			   struct nouveau_oclass *oclass, void *data, u32 size,
			   struct nouveau_object **pobject)
{
	struct nouveau_disp *pdisp = nouveau_disp(parent);
	struct nv50_software_cclass *pclass = (void *)oclass;
	struct nv50_software_chan *chan;
	int ret;
	int ret, i;

	ret = nouveau_software_context_create(parent, engine, oclass, &chan);
	*pobject = nv_object(chan);
	if (ret)
		return ret;

	chan->vblank.nr_event = pdisp->vblank->index_nr;
	chan->vblank.event = kzalloc(chan->vblank.nr_event *
				     sizeof(*chan->vblank.event), GFP_KERNEL);
	if (!chan->vblank.event)
		return -ENOMEM;

	for (i = 0; i < chan->vblank.nr_event; i++) {
		ret = nouveau_event_new(pdisp->vblank, i, pclass->vblank,
					chan, &chan->vblank.event[i]);
		if (ret)
			return ret;
	}

	chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
	chan->vblank.event.func = pclass->vblank;
	return 0;
}

+8 −2
Original line number Diff line number Diff line
@@ -19,13 +19,14 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,

struct nv50_software_cclass {
	struct nouveau_oclass base;
	int (*vblank)(struct nouveau_eventh *, int);
	int (*vblank)(void *, int);
};

struct nv50_software_chan {
	struct nouveau_software_chan base;
	struct {
		struct nouveau_eventh event;
		struct nouveau_eventh **event;
		int nr_event;
		u32 channel;
		u32 ctxdma;
		u64 offset;
@@ -37,5 +38,10 @@ int nv50_software_context_ctor(struct nouveau_object *,
				struct nouveau_object *,
				struct nouveau_oclass *, void *, u32,
				struct nouveau_object **);
void nv50_software_context_dtor(struct nouveau_object *);

int nv50_software_mthd_vblsem_value(struct nouveau_object *, u32, void *, u32);
int nv50_software_mthd_vblsem_release(struct nouveau_object *, u32, void *, u32);
int nv50_software_mthd_flip(struct nouveau_object *, u32, void *, u32);

#endif
+5 −40
Original line number Diff line number Diff line
@@ -54,40 +54,6 @@ nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
	return 0;
}

static int
nvc0_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
				void *args, u32 size)
{
	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
	chan->vblank.value = *(u32 *)args;
	return 0;
}

static int
nvc0_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
				  void *args, u32 size)
{
	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
	struct nouveau_disp *disp = nouveau_disp(object);
	u32 crtc = *(u32 *)args;

	if ((nv_device(object)->card_type < NV_E0 && crtc > 1) || crtc > 3)
		return -EINVAL;

	nouveau_event_get(disp->vblank, crtc, &chan->vblank.event);
	return 0;
}

static int
nvc0_software_mthd_flip(struct nouveau_object *object, u32 mthd,
			void *args, u32 size)
{
	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
	if (chan->base.flip)
		return chan->base.flip(chan->base.flip_data);
	return -EINVAL;
}

static int
nvc0_software_mthd_mp_control(struct nouveau_object *object, u32 mthd,
                              void *args, u32 size)
@@ -118,9 +84,9 @@ static struct nouveau_omthds
nvc0_software_omthds[] = {
	{ 0x0400, 0x0400, nvc0_software_mthd_vblsem_offset },
	{ 0x0404, 0x0404, nvc0_software_mthd_vblsem_offset },
	{ 0x0408, 0x0408, nvc0_software_mthd_vblsem_value },
	{ 0x040c, 0x040c, nvc0_software_mthd_vblsem_release },
	{ 0x0500, 0x0500, nvc0_software_mthd_flip },
	{ 0x0408, 0x0408, nv50_software_mthd_vblsem_value },
	{ 0x040c, 0x040c, nv50_software_mthd_vblsem_release },
	{ 0x0500, 0x0500, nv50_software_mthd_flip },
	{ 0x0600, 0x0600, nvc0_software_mthd_mp_control },
	{ 0x0644, 0x0644, nvc0_software_mthd_mp_control },
	{ 0x06ac, 0x06ac, nvc0_software_mthd_mp_control },
@@ -138,10 +104,9 @@ nvc0_software_sclass[] = {
 ******************************************************************************/

static int
nvc0_software_vblsem_release(struct nouveau_eventh *event, int head)
nvc0_software_vblsem_release(void *data, int head)
{
	struct nv50_software_chan *chan =
		container_of(event, typeof(*chan), vblank.event);
	struct nv50_software_chan *chan = data;
	struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
	struct nouveau_bar *bar = nouveau_bar(priv);

+9 −5
Original line number Diff line number Diff line
@@ -9,10 +9,12 @@
#define NVKM_EVENT_ENABLE 0

struct nouveau_eventh {
	struct nouveau_event *event;
	struct list_head head;
	unsigned long flags;
	int index;
	int (*func)(void *, int);
	void *priv;
	int (*func)(struct nouveau_eventh *, int index);
};

struct nouveau_event {
@@ -33,9 +35,11 @@ int nouveau_event_create(int index_nr, struct nouveau_event **);
void nouveau_event_destroy(struct nouveau_event **);
void nouveau_event_trigger(struct nouveau_event *, int index);

void nouveau_event_get(struct nouveau_event *, int index,
		       struct nouveau_eventh *);
void nouveau_event_put(struct nouveau_event *, int index,
		       struct nouveau_eventh *);
int  nouveau_event_new(struct nouveau_event *, int index,
		       int (*func)(void *, int), void *,
		       struct nouveau_eventh **);
void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **);
void nouveau_event_get(struct nouveau_eventh *);
void nouveau_event_put(struct nouveau_eventh *);

#endif
Loading