summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2022-06-01 20:46:53 +1000
committerBen Skeggs <bskeggs@redhat.com>2022-11-09 10:44:35 +1000
commita7ab200aebc23095474e6dc8e335e60473086236 (patch)
tree5ef303be52e2ee70b8a2703d23053acc8d2fb9d7 /drivers/gpu
parent3ebd64aa3c4fe7fa2e73f6fa5f81490721a9c4e1 (diff)
downloadlinux-a7ab200aebc23095474e6dc8e335e60473086236.tar.bz2
drm/nouveau/intr: add nvkm_subdev_intr() compatibility
It's quite a lot of tedious and error-prone work to switch over all the subdevs at once, so allow an nvkm_intr to request new-style handlers to be created that wrap the existing interfaces. This will allow a more gradual transition. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Reviewed-by: Lyude Paul <lyude@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/device.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/intr.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/intr.c61
4 files changed, 65 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
index 555e3fe06341..f65b5009acf7 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
@@ -69,6 +69,7 @@ struct nvkm_device {
int irq;
bool alloc;
bool armed;
+ bool legacy_done;
} intr;
};
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/intr.h b/drivers/gpu/drm/nouveau/include/nvkm/core/intr.h
index ec7db1312277..a003d6a544b0 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/intr.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/intr.h
@@ -30,6 +30,7 @@ struct nvkm_intr {
int inst;
int leaf;
u32 mask; /* 0-terminated. */
+ bool legacy; /* auto-create "legacy" nvkm_subdev_intr() handler */
} *data;
struct nvkm_subdev *subdev;
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
index 96113c8bee8c..20e1fc90c536 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
@@ -21,6 +21,8 @@ struct nvkm_subdev {
u32 debug;
struct list_head head;
+ struct nvkm_inth inth;
+
void **pself;
bool oneinit;
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/intr.c b/drivers/gpu/drm/nouveau/nvkm/core/intr.c
index ff95e018fa78..3f3fe3d416e2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/intr.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/intr.c
@@ -265,12 +265,73 @@ nvkm_intr_add(const struct nvkm_intr_func *func, const struct nvkm_intr_data *da
return 0;
}
+static irqreturn_t
+nvkm_intr_subdev(struct nvkm_inth *inth)
+{
+ struct nvkm_subdev *subdev = container_of(inth, typeof(*subdev), inth);
+
+ nvkm_subdev_intr(subdev);
+ return IRQ_HANDLED;
+}
+
+static void
+nvkm_intr_subdev_add_dev(struct nvkm_intr *intr, enum nvkm_subdev_type type, int inst)
+{
+ struct nvkm_subdev *subdev;
+ enum nvkm_intr_prio prio;
+ int ret;
+
+ subdev = nvkm_device_subdev(intr->subdev->device, type, inst);
+ if (!subdev || !subdev->func->intr)
+ return;
+
+ if (type == NVKM_ENGINE_DISP)
+ prio = NVKM_INTR_PRIO_VBLANK;
+ else
+ prio = NVKM_INTR_PRIO_NORMAL;
+
+ ret = nvkm_inth_add(intr, NVKM_INTR_SUBDEV, prio, subdev, nvkm_intr_subdev, &subdev->inth);
+ if (WARN_ON(ret))
+ return;
+
+ nvkm_inth_allow(&subdev->inth);
+}
+
+static void
+nvkm_intr_subdev_add(struct nvkm_intr *intr)
+{
+ const struct nvkm_intr_data *data;
+ struct nvkm_device *device = intr->subdev->device;
+ struct nvkm_top_device *tdev;
+
+ for (data = intr->data; data && data->mask; data++) {
+ if (data->legacy) {
+ if (data->type == NVKM_SUBDEV_TOP) {
+ list_for_each_entry(tdev, &device->top->device, head) {
+ if (tdev->intr < 0 || !(data->mask & BIT(tdev->intr)))
+ continue;
+
+ nvkm_intr_subdev_add_dev(intr, tdev->type, tdev->inst);
+ }
+ } else {
+ nvkm_intr_subdev_add_dev(intr, data->type, data->inst);
+ }
+ }
+ }
+}
+
void
nvkm_intr_rearm(struct nvkm_device *device)
{
struct nvkm_intr *intr;
int i;
+ if (unlikely(!device->intr.legacy_done)) {
+ list_for_each_entry(intr, &device->intr.intr, head)
+ nvkm_intr_subdev_add(intr);
+ device->intr.legacy_done = true;
+ }
+
spin_lock_irq(&device->intr.lock);
list_for_each_entry(intr, &device->intr.intr, head) {
for (i = 0; intr->func->block && i < intr->leaves; i++) {