diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index b4c373bc3ca8..66743f2e329c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -3,6 +3,7 @@ #define __NVKM_DEVICE_H__ #include #include +enum nvkm_subdev_type; #define nvkm_devidx nvkm_subdev_type @@ -108,6 +109,11 @@ struct nvkm_device { struct nvkm_engine *vic; struct nvkm_engine *vp; +#define NVKM_LAYOUT_ONCE(type,data,ptr) data *ptr; +#define NVKM_LAYOUT_INST(type,data,ptr,cnt) data *ptr[cnt]; +#include +#undef NVKM_LAYOUT_INST +#undef NVKM_LAYOUT_ONCE struct list_head subdev; }; @@ -133,7 +139,15 @@ struct nvkm_device_quirk { struct nvkm_device_chip { const char *name; - +#define NVKM_LAYOUT_ONCE(type,data,ptr,...) \ + struct { \ + u32 inst; \ + int (*ctor)(struct nvkm_device *, enum nvkm_subdev_type, int inst, data **); \ + } ptr; +#define NVKM_LAYOUT_INST(A...) NVKM_LAYOUT_ONCE(A) +#include +#undef NVKM_LAYOUT_INST +#undef NVKM_LAYOUT_ONCE int (*acr )(struct nvkm_device *, int idx, struct nvkm_acr **); int (*bar )(struct nvkm_device *, int idx, struct nvkm_bar **); int (*bios )(struct nvkm_device *, int idx, struct nvkm_bios **); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h b/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h new file mode 100644 index 000000000000..7812f3568059 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/layout.h @@ -0,0 +1 @@ +/* SPDX-License-Identifier: MIT */ diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index a37f7112de33..8f41393467ce 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -89,6 +89,7 @@ struct nvkm_subdev { u32 debug; struct list_head head; + void **pself; bool oneinit; }; @@ -111,6 +112,7 @@ void nvkm_subdev_ctor_(const struct nvkm_subdev_func *, bool old, struct nvkm_de #define nvkm_subdev_ctor_n(f,d,t,i,s) nvkm_subdev_ctor_((f), false, (d), (t), (i), (s)) #define nvkm_subdev_ctor__(_1,_2,_3,_4,_5,IMPL,...) IMPL #define nvkm_subdev_ctor(A...) nvkm_subdev_ctor__(A, nvkm_subdev_ctor_n, nvkm_subdev_ctor_o)(A) +void nvkm_subdev_disable(struct nvkm_device *, enum nvkm_subdev_type, int inst); void nvkm_subdev_del(struct nvkm_subdev **); int nvkm_subdev_preinit(struct nvkm_subdev *); int nvkm_subdev_init(struct nvkm_subdev *); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index 12a13d634a70..acfa3ba5880d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -28,6 +28,11 @@ const char * nvkm_subdev_type[NVKM_SUBDEV_NR] = { +#define NVKM_LAYOUT_ONCE(type,data,ptr,...) [type] = #ptr, +#define NVKM_LAYOUT_INST(A...) NVKM_LAYOUT_ONCE(A) +#include +#undef NVKM_LAYOUT_ONCE +#undef NVKM_LAYOUT_INST [NVKM_SUBDEV_ACR ] = "acr", [NVKM_SUBDEV_BAR ] = "bar", [NVKM_SUBDEV_VBIOS ] = "bios", @@ -207,6 +212,19 @@ nvkm_subdev_del(struct nvkm_subdev **psubdev) } } +void +nvkm_subdev_disable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst) +{ + struct nvkm_subdev *subdev; + list_for_each_entry(subdev, &device->subdev, head) { + if (subdev->type == type && subdev->inst == inst) { + *subdev->pself = NULL; + nvkm_subdev_del(&subdev); + break; + } + } +} + void nvkm_subdev_ctor_(const struct nvkm_subdev_func *func, bool old, struct nvkm_device *device, enum nvkm_subdev_type type, int inst, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index a4d7d6cffaee..de9f1d356012 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -3206,6 +3206,48 @@ nvkm_device_ctor(const struct nvkm_device_func *func, } \ break switch (i) { +#define NVKM_LAYOUT_ONCE(type,data,ptr) case type: \ + if (device->chip->ptr.inst && (subdev_mask & (BIT_ULL(type)))) { \ + WARN_ON(device->chip->ptr.inst != 0x00000001); \ + ret = device->chip->ptr.ctor(device, (type), -1, &device->ptr); \ + subdev = nvkm_device_subdev(device, (type), 0); \ + if (ret) { \ + nvkm_subdev_del(&subdev); \ + device->ptr = NULL; \ + if (ret != -ENODEV) { \ + nvdev_error(device, "%s ctor failed: %d\n", \ + nvkm_subdev_type[(type)], ret); \ + goto done; \ + } \ + } else { \ + subdev->pself = (void **)&device->ptr; \ + } \ + } \ + break; +#define NVKM_LAYOUT_INST(type,data,ptr,cnt) case type: \ + WARN_ON(device->chip->ptr.inst & ~((1 << ARRAY_SIZE(device->ptr)) - 1)); \ + for (j = 0; device->chip->ptr.inst && j < ARRAY_SIZE(device->ptr); j++) { \ + if ((device->chip->ptr.inst & BIT(j)) && (subdev_mask & BIT_ULL(type))) { \ + int inst = (device->chip->ptr.inst == 1) ? -1 : (j); \ + ret = device->chip->ptr.ctor(device, (type), inst, &device->ptr[j]); \ + subdev = nvkm_device_subdev(device, (type), (j)); \ + if (ret) { \ + nvkm_subdev_del(&subdev); \ + device->ptr[j] = NULL; \ + if (ret != -ENODEV) { \ + nvdev_error(device, "%s%d ctor failed: %d\n", \ + nvkm_subdev_type[(type)], (j), ret); \ + goto done; \ + } \ + } else { \ + subdev->pself = (void **)&device->ptr[j]; \ + } \ + } \ + } \ + break; +#include +#undef NVKM_LAYOUT_INST +#undef NVKM_LAYOUT_ONCE _(NVKM_SUBDEV_ACR , acr); _(NVKM_SUBDEV_BAR , bar); _(NVKM_SUBDEV_VBIOS , bios);