drm/nouveau/device: implement a generic method to query device-specific properties
authorBen Skeggs <bskeggs@redhat.com>
Tue, 8 May 2018 10:39:46 +0000 (20:39 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 18 May 2018 05:01:21 +0000 (15:01 +1000)
We have a need to fetch data from GPU-specific sub-devices that is not
tied to any particular engine object.

This commit provides the framework to support such queries.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvif/cl0080.h
drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
drivers/gpu/drm/nouveau/nvkm/core/engine.c
drivers/gpu/drm/nouveau/nvkm/core/subdev.c
drivers/gpu/drm/nouveau/nvkm/engine/device/user.c

index 2740278d226b96c230d306197646c4559271b04b..51a4af6a77eba8f32af8d7bfb2ed413886e8d73d 100644 (file)
@@ -39,9 +39,25 @@ struct nv_device_info_v0 {
        char  name[64];
 };
 
+struct nv_device_info_v1 {
+       __u8  version;
+       __u8  count;
+       __u8  pad02[6];
+       struct nv_device_info_v1_data {
+               __u64 mthd; /* NV_DEVICE_INFO_* (see below). */
+               __u64 data;
+       } data[];
+};
+
 struct nv_device_time_v0 {
        __u8  version;
        __u8  pad01[7];
        __u64 time;
 };
+
+#define NV_DEVICE_INFO_UNIT                               (0xffffffffULL << 32)
+#define NV_DEVICE_INFO(n)                          ((n) | (0x00000000ULL << 32))
+
+/* This will be returned for unsupported queries. */
+#define NV_DEVICE_INFO_INVALID                                           ~0ULL
 #endif
index ebf8473a39fe87e2dc7b748aa97d77979ec8ace4..8a2be5b635e22a3dbb38b5dd06695764161eda6a 100644 (file)
@@ -18,6 +18,7 @@ struct nvkm_engine_func {
        void *(*dtor)(struct nvkm_engine *);
        void (*preinit)(struct nvkm_engine *);
        int (*oneinit)(struct nvkm_engine *);
+       int (*info)(struct nvkm_engine *, u64 mthd, u64 *data);
        int (*init)(struct nvkm_engine *);
        int (*fini)(struct nvkm_engine *, bool suspend);
        void (*intr)(struct nvkm_engine *);
index 63df2290177f3b038a50da1566c617fc26ebe232..85a0777c2ce444c85f9411ae52afe5ac98341dbe 100644 (file)
@@ -17,6 +17,7 @@ struct nvkm_subdev_func {
        void *(*dtor)(struct nvkm_subdev *);
        int (*preinit)(struct nvkm_subdev *);
        int (*oneinit)(struct nvkm_subdev *);
+       int (*info)(struct nvkm_subdev *, u64 mthd, u64 *data);
        int (*init)(struct nvkm_subdev *);
        int (*fini)(struct nvkm_subdev *, bool suspend);
        void (*intr)(struct nvkm_subdev *);
@@ -29,6 +30,7 @@ void nvkm_subdev_del(struct nvkm_subdev **);
 int  nvkm_subdev_preinit(struct nvkm_subdev *);
 int  nvkm_subdev_init(struct nvkm_subdev *);
 int  nvkm_subdev_fini(struct nvkm_subdev *, bool suspend);
+int  nvkm_subdev_info(struct nvkm_subdev *, u64, u64 *);
 void nvkm_subdev_intr(struct nvkm_subdev *);
 
 /* subdev logging */
index 657231c3c098a667eecddac29146ced58feea7c7..d0322ce85172a3f20748a074b9d90f854ae37a03 100644 (file)
@@ -82,6 +82,20 @@ nvkm_engine_intr(struct nvkm_subdev *subdev)
                engine->func->intr(engine);
 }
 
+static int
+nvkm_engine_info(struct nvkm_subdev *subdev, u64 mthd, u64 *data)
+{
+       struct nvkm_engine *engine = nvkm_engine(subdev);
+       if (engine->func->info) {
+               if ((engine = nvkm_engine_ref(engine))) {
+                       int ret = engine->func->info(engine, mthd, data);
+                       nvkm_engine_unref(&engine);
+                       return ret;
+               }
+       }
+       return -ENOSYS;
+}
+
 static int
 nvkm_engine_fini(struct nvkm_subdev *subdev, bool suspend)
 {
@@ -150,6 +164,7 @@ nvkm_engine_func = {
        .preinit = nvkm_engine_preinit,
        .init = nvkm_engine_init,
        .fini = nvkm_engine_fini,
+       .info = nvkm_engine_info,
        .intr = nvkm_engine_intr,
 };
 
index c707306ac286f26ea7561cc5c04382f977d843b1..b96f9e2f237a2cab0e60ffe2ebab0e8f2d12bb51 100644 (file)
@@ -92,6 +92,14 @@ nvkm_subdev_intr(struct nvkm_subdev *subdev)
                subdev->func->intr(subdev);
 }
 
+int
+nvkm_subdev_info(struct nvkm_subdev *subdev, u64 mthd, u64 *data)
+{
+       if (subdev->func->info)
+               return subdev->func->info(subdev, mthd, data);
+       return -ENOSYS;
+}
+
 int
 nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend)
 {
index 17adcb4e8854ac24860d4eee5086b60fa9c36dd6..3526516765f8de1dceb9f56c881004e880f49061 100644 (file)
@@ -39,6 +39,40 @@ struct nvkm_udevice {
        struct nvkm_device *device;
 };
 
+static int
+nvkm_udevice_info_subdev(struct nvkm_device *device, u64 mthd, u64 *data)
+{
+       struct nvkm_subdev *subdev;
+       enum nvkm_devidx subidx;
+
+       switch (mthd & NV_DEVICE_INFO_UNIT) {
+       default:
+               return -EINVAL;
+       }
+
+       subdev = nvkm_device_subdev(device, subidx);
+       if (subdev)
+               return nvkm_subdev_info(subdev, mthd, data);
+       return -ENODEV;
+}
+
+static void
+nvkm_udevice_info_v1(struct nvkm_device *device,
+                    struct nv_device_info_v1_data *args)
+{
+       if (args->mthd & NV_DEVICE_INFO_UNIT) {
+               if (nvkm_udevice_info_subdev(device, args->mthd, &args->data))
+                       args->mthd = NV_DEVICE_INFO_INVALID;
+               return;
+       }
+
+       switch (args->mthd) {
+       default:
+               args->mthd = NV_DEVICE_INFO_INVALID;
+               break;
+       }
+}
+
 static int
 nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
 {
@@ -48,10 +82,21 @@ nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
        struct nvkm_instmem *imem = device->imem;
        union {
                struct nv_device_info_v0 v0;
+               struct nv_device_info_v1 v1;
        } *args = data;
-       int ret = -ENOSYS;
+       int ret = -ENOSYS, i;
 
        nvif_ioctl(object, "device info size %d\n", size);
+       if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) {
+               nvif_ioctl(object, "device info vers %d count %d\n",
+                          args->v1.version, args->v1.count);
+               if (args->v1.count * sizeof(args->v1.data[0]) == size) {
+                       for (i = 0; i < args->v1.count; i++)
+                               nvkm_udevice_info_v1(device, &args->v1.data[i]);
+                       return 0;
+               }
+               return -EINVAL;
+       } else
        if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
                nvif_ioctl(object, "device info vers %d\n", args->v0.version);
        } else