Skip to content
Permalink
Browse files
drm/nouveau/nvkm: add a replacement for nvkm_notify
This replaces the twisty, confusing, relationship between nvkm_event and
nvkm_notify with something much simpler, and less racey.  It also places
events in the object tree hierachy, which will allow a bunch of the code
tracking events across allocation/teardown/suspend to be removed.

This commit just adds the new interfaces, and passes the owning subdev to
the event constructor to enable debug-tracing in the new code.

v2:
- use ?: (lyude)

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
  • Loading branch information
skeggsb committed Oct 12, 2021
1 parent b109dfb commit ee9e44a497d467c04908c8329a305e8cd0e692e5
Show file tree
Hide file tree
Showing 21 changed files with 535 additions and 29 deletions.
@@ -32,6 +32,8 @@
#define NVIF_CLASS_VMM_GM200 /* ifb00d.h */ 0x8000b00d
#define NVIF_CLASS_VMM_GP100 /* ifc00d.h */ 0x8000c00d

#define NVIF_CLASS_EVENT /* if000e.h */ 0x8000000e

#define NVIF_CLASS_DISP /* if0010.h */ 0x80000010
#define NVIF_CLASS_CONN /* if0011.h */ 0x80000011
#define NVIF_CLASS_OUTP /* if0012.h */ 0x80000012
@@ -1,6 +1,30 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_EVENT_H__
#define __NVIF_EVENT_H__
#include <nvif/object.h>
#include <nvif/if000e.h>
struct nvif_event;

#define NVIF_EVENT_KEEP 0
#define NVIF_EVENT_DROP 1
typedef int (*nvif_event_func)(struct nvif_event *, void *repv, u32 repc);

struct nvif_event {
struct nvif_object object;
nvif_event_func func;
};

static inline bool
nvif_event_constructed(struct nvif_event *event)
{
return nvif_object_constructed(&event->object);
}

int nvif_event_ctor(struct nvif_object *parent, const char *name, u32 handle, nvif_event_func,
bool wait, struct nvif_event_v0 *args, u32 argc, struct nvif_event *);
void nvif_event_dtor(struct nvif_event *);
int nvif_event_allow(struct nvif_event *);
int nvif_event_block(struct nvif_event *);

struct nvif_notify_req_v0 {
__u8 version;
@@ -0,0 +1,26 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_IF000E_H__
#define __NVIF_IF000E_H__

union nvif_event_args {
struct nvif_event_v0 {
__u8 version;
__u8 wait;
__u8 pad02[6];
__u8 data[];
} v0;
};

#define NVIF_EVENT_V0_ALLOW 0x00
#define NVIF_EVENT_V0_BLOCK 0x01

union nvif_event_allow_args {
struct nvif_event_allow_vn {
} vn;
};

union nvif_event_block_args {
struct nvif_event_block_vn {
} vn;
};
#endif
@@ -15,6 +15,7 @@ struct nvkm_client {

void *data;
int (*ntfy)(const void *, u32, const void *, u32);
int (*event)(u64 token, void *argv, u32 argc);

struct list_head umem;
spinlock_t lock;
@@ -23,6 +24,7 @@ struct nvkm_client {
int nvkm_client_new(const char *name, u64 device, const char *cfg,
const char *dbg,
int (*)(const void *, u32, const void *, u32),
int (*)(u64, void *, u32),
struct nvkm_client **);
struct nvkm_client *nvkm_client_search(struct nvkm_client *, u64 handle);

@@ -4,9 +4,12 @@
#include <core/os.h>
struct nvkm_notify;
struct nvkm_object;
struct nvkm_oclass;
struct nvkm_uevent;

struct nvkm_event {
const struct nvkm_event_func *func;
struct nvkm_subdev *subdev;

int types_nr;
int index_nr;
@@ -15,6 +18,8 @@ struct nvkm_event {
spinlock_t list_lock;
struct list_head list;
int *refs;

struct list_head ntfy;
};

struct nvkm_event_func {
@@ -25,11 +30,42 @@ struct nvkm_event_func {
void (*fini)(struct nvkm_event *, int type, int index);
};

int nvkm_event_init(const struct nvkm_event_func *func, int types_nr,
int nvkm_event_init(const struct nvkm_event_func *func, struct nvkm_subdev *, int types_nr,
int index_nr, struct nvkm_event *);
void nvkm_event_fini(struct nvkm_event *);
void nvkm_event_get(struct nvkm_event *, u32 types, int index);
void nvkm_event_put(struct nvkm_event *, u32 types, int index);
void nvkm_event_send(struct nvkm_event *, u32 types, int index,
void *data, u32 size);

#define NVKM_EVENT_KEEP 0
#define NVKM_EVENT_DROP 1
struct nvkm_event_ntfy;
typedef int (*nvkm_event_func)(struct nvkm_event_ntfy *, u32 bits);

struct nvkm_event_ntfy {
struct nvkm_event *event;
int id;
u32 bits;
bool wait;
nvkm_event_func func;

atomic_t allowed;
bool running;

struct list_head head;
};

void nvkm_event_ntfy(struct nvkm_event *, int id, u32 bits);
bool nvkm_event_ntfy_valid(struct nvkm_event *, int id, u32 bits);
void nvkm_event_ntfy_add(struct nvkm_event *, int id, u32 bits, bool wait, nvkm_event_func,
struct nvkm_event_ntfy *);
void nvkm_event_ntfy_del(struct nvkm_event_ntfy *);
void nvkm_event_ntfy_allow(struct nvkm_event_ntfy *);
void nvkm_event_ntfy_block(struct nvkm_event_ntfy *);

typedef int (*nvkm_uevent_func)(struct nvkm_object *, u64 token, u32 bits);

int nvkm_uevent_new(const struct nvkm_oclass *, void *argv, u32 argc, struct nvkm_object **);
int nvkm_uevent_add(struct nvkm_uevent *, struct nvkm_event *, int id, u32 bits, nvkm_uevent_func);
#endif
@@ -4,6 +4,7 @@
#include <core/oclass.h>
struct nvkm_event;
struct nvkm_gpuobj;
struct nvkm_uevent;

struct nvkm_object {
const struct nvkm_object_func *func;
@@ -43,6 +44,7 @@ struct nvkm_object_func {
int (*bind)(struct nvkm_object *, struct nvkm_gpuobj *, int align,
struct nvkm_gpuobj **);
int (*sclass)(struct nvkm_object *, int index, struct nvkm_oclass *);
int (*uevent)(struct nvkm_object *, void *argv, u32 argc, struct nvkm_uevent *);
};

void nvkm_object_ctor(const struct nvkm_object_func *,
@@ -71,11 +71,24 @@ nvkm_client_suspend(void *priv)
return nvkm_object_fini(&client->object, true);
}

static int
nvkm_client_event(u64 token, void *repv, u32 repc)
{
struct nvif_object *object = (void *)(unsigned long)token;
struct nvif_event *event = container_of(object, typeof(*event), object);

if (event->func(event, repv, repc) == NVIF_EVENT_KEEP)
return NVKM_EVENT_KEEP;

return NVKM_EVENT_DROP;
}

static int
nvkm_client_driver_init(const char *name, u64 device, const char *cfg,
const char *dbg, void **ppriv)
{
return nvkm_client_new(name, device, cfg, dbg, nvif_notify, (struct nvkm_client **)ppriv);
return nvkm_client_new(name, device, cfg, dbg, nvif_notify, nvkm_client_event,
(struct nvkm_client **)ppriv);
}

const struct nvif_driver
@@ -5,6 +5,7 @@ nvif-y += nvif/conn.o
nvif-y += nvif/device.o
nvif-y += nvif/disp.o
nvif-y += nvif/driver.o
nvif-y += nvif/event.o
nvif-y += nvif/fifo.o
nvif-y += nvif/head.o
nvif-y += nvif/mem.o
@@ -0,0 +1,79 @@
/*
* Copyright 2021 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 <nvif/event.h>
#include <nvif/printf.h>

#include <nvif/class.h>
#include <nvif/if000e.h>

int
nvif_event_block(struct nvif_event *event)
{
if (nvif_event_constructed(event)) {
int ret = nvif_mthd(&event->object, NVIF_EVENT_V0_BLOCK, NULL, 0);
NVIF_ERRON(ret, &event->object, "[BLOCK]");
return ret;
}
return 0;
}

int
nvif_event_allow(struct nvif_event *event)
{
if (nvif_event_constructed(event)) {
int ret = nvif_mthd(&event->object, NVIF_EVENT_V0_ALLOW, NULL, 0);
NVIF_ERRON(ret, &event->object, "[ALLOW]");
return ret;
}
return 0;
}

void
nvif_event_dtor(struct nvif_event *event)
{
nvif_object_dtor(&event->object);
}

int
nvif_event_ctor(struct nvif_object *parent, const char *name, u32 handle, nvif_event_func func,
bool wait, struct nvif_event_v0 *args, u32 argc, struct nvif_event *event)
{
struct nvif_event_v0 _args;
int ret;

if (!args) {
args = &_args;
argc = sizeof(_args);
}

args->version = 0;
args->wait = wait;

ret = nvif_object_ctor(parent, name ?: "nvifEvent", handle,
NVIF_CLASS_EVENT, args, argc, &event->object);
NVIF_ERRON(ret, parent, "[NEW EVENT wait:%d size:%ld]", args->wait, argc - sizeof(*args));
if (ret)
return ret;

event->func = func;
return 0;
}
@@ -14,3 +14,4 @@ nvkm-y += nvkm/core/oproxy.o
nvkm-y += nvkm/core/option.o
nvkm-y += nvkm/core/ramht.o
nvkm-y += nvkm/core/subdev.o
nvkm-y += nvkm/core/uevent.o
@@ -44,7 +44,7 @@ nvkm_uclient_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))){
args->v0.name[sizeof(args->v0.name) - 1] = 0;
ret = nvkm_client_new(args->v0.name, args->v0.device, NULL,
NULL, oclass->client->ntfy, &client);
NULL, oclass->client->ntfy, oclass->client->event, &client);
if (ret)
return ret;
} else
@@ -286,7 +286,7 @@ int
nvkm_client_new(const char *name, u64 device, const char *cfg,
const char *dbg,
int (*ntfy)(const void *, u32, const void *, u32),
struct nvkm_client **pclient)
int (*event)(u64, void *, u32), struct nvkm_client **pclient)
{
struct nvkm_oclass oclass = { .base = nvkm_uclient_sclass };
struct nvkm_client *client;
@@ -301,6 +301,7 @@ nvkm_client_new(const char *name, u64 device, const char *cfg,
client->debug = nvkm_dbgopt(dbg, "CLIENT");
client->objroot = RB_ROOT;
client->ntfy = ntfy;
client->event = event;
INIT_LIST_HEAD(&client->umem);
spin_lock_init(&client->lock);
return 0;

0 comments on commit ee9e44a

Please sign in to comment.