From 95983aea80038539ebc70e41e73e9bb4eabd1a92 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 1 Jun 2022 20:46:30 +1000 Subject: drm/nouveau/disp: add connector class Will be used to provide more solid driver interfaces in general, but the immediate motivation is work towards fixing issues with handling hotplug/DP IRQ events. Its use is currently limited to where we support non-polled hotplug already (ie. any GPU since NV40ish era, where our DCB handling works well enough), until that gets cleaned up someday. v2: - use ?: (lyude) Signed-off-by: Ben Skeggs Reviewed-by: Lyude Paul Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/include/nvif/class.h | 1 + drivers/gpu/drm/nouveau/include/nvif/conn.h | 13 +++++ drivers/gpu/drm/nouveau/include/nvif/disp.h | 1 + drivers/gpu/drm/nouveau/include/nvif/if0010.h | 3 +- drivers/gpu/drm/nouveau/include/nvif/if0011.h | 12 ++++ drivers/gpu/drm/nouveau/nouveau_connector.c | 10 ++++ drivers/gpu/drm/nouveau/nouveau_connector.h | 3 +- drivers/gpu/drm/nouveau/nvif/Kbuild | 1 + drivers/gpu/drm/nouveau/nvif/conn.c | 48 +++++++++++++++ drivers/gpu/drm/nouveau/nvif/disp.c | 7 ++- drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c | 74 ++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c | 14 +++++ 15 files changed, 189 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/include/nvif/conn.h create mode 100644 drivers/gpu/drm/nouveau/include/nvif/if0011.h create mode 100644 drivers/gpu/drm/nouveau/nvif/conn.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 1c185433b39e..c7dab84e0a30 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -33,6 +33,7 @@ #define NVIF_CLASS_VMM_GP100 /* ifc00d.h */ 0x8000c00d #define NVIF_CLASS_DISP /* if0010.h */ 0x80000010 +#define NVIF_CLASS_CONN /* if0011.h */ 0x80000011 #define NVIF_CLASS_DISP_CHAN /* if0014.h */ 0x80000014 /* the below match nvidia-assigned (either in hw, or sw) class numbers */ diff --git a/drivers/gpu/drm/nouveau/include/nvif/conn.h b/drivers/gpu/drm/nouveau/include/nvif/conn.h new file mode 100644 index 000000000000..ad52cdafef18 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvif/conn.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVIF_CONN_H__ +#define __NVIF_CONN_H__ +#include +struct nvif_disp; + +struct nvif_conn { + struct nvif_object object; +}; + +int nvif_conn_ctor(struct nvif_disp *, const char *name, int id, struct nvif_conn *); +void nvif_conn_dtor(struct nvif_conn *); +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/disp.h b/drivers/gpu/drm/nouveau/include/nvif/disp.h index 07ac544f282f..a93055b781f2 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/disp.h @@ -5,6 +5,7 @@ struct nvif_device; struct nvif_disp { struct nvif_object object; + unsigned long conn_mask; }; int nvif_disp_ctor(struct nvif_device *, const char *name, s32 oclass, diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0010.h b/drivers/gpu/drm/nouveau/include/nvif/if0010.h index fc22191868d8..3af495dbd4c6 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0010.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0010.h @@ -5,7 +5,8 @@ union nvif_disp_args { struct nvif_disp_v0 { __u8 version; - __u8 pad01[7]; + __u8 pad01[3]; + __u32 conn_mask; } v0; }; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0011.h b/drivers/gpu/drm/nouveau/include/nvif/if0011.h new file mode 100644 index 000000000000..9c910b29a730 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvif/if0011.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVIF_IF0011_H__ +#define __NVIF_IF0011_H__ + +union nvif_conn_args { + struct nvif_conn_v0 { + __u8 version; + __u8 id; /* DCB connector table index. */ + __u8 pad02[6]; + } v0; +}; +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 22b83a6577eb..254996845575 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -404,6 +404,7 @@ nouveau_connector_destroy(struct drm_connector *connector) drm_dp_cec_unregister_connector(&nv_connector->aux); kfree(nv_connector->aux.name); } + nvif_conn_dtor(&nv_connector->conn); kfree(connector); } @@ -1388,6 +1389,15 @@ nouveau_connector_create(struct drm_device *dev, drm_connector_init(dev, connector, funcs, type); drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); + if (nv_connector->dcb && (disp->disp.conn_mask & BIT(nv_connector->index))) { + ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index, + &nv_connector->conn); + if (ret) { + kfree(nv_connector); + return ERR_PTR(ret); + } + } + connector->funcs->reset(connector); nouveau_conn_attach_properties(connector); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index b0773af5a98f..4bf0c703eee7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -26,7 +26,7 @@ #ifndef __NOUVEAU_CONNECTOR_H__ #define __NOUVEAU_CONNECTOR_H__ - +#include #include #include @@ -123,6 +123,7 @@ struct nouveau_connector { u8 index; u8 *dcb; + struct nvif_conn conn; struct nvif_notify hpd; struct drm_dp_aux aux; diff --git a/drivers/gpu/drm/nouveau/nvif/Kbuild b/drivers/gpu/drm/nouveau/nvif/Kbuild index f194d354c1f5..576237f47d8d 100644 --- a/drivers/gpu/drm/nouveau/nvif/Kbuild +++ b/drivers/gpu/drm/nouveau/nvif/Kbuild @@ -1,6 +1,7 @@ # SPDX-License-Identifier: MIT nvif-y := nvif/object.o nvif-y += nvif/client.o +nvif-y += nvif/conn.o nvif-y += nvif/device.o nvif-y += nvif/disp.o nvif-y += nvif/driver.o diff --git a/drivers/gpu/drm/nouveau/nvif/conn.c b/drivers/gpu/drm/nouveau/nvif/conn.c new file mode 100644 index 000000000000..a83b8a4a57e6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvif/conn.c @@ -0,0 +1,48 @@ +/* + * 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 +#include +#include + +#include +#include + +void +nvif_conn_dtor(struct nvif_conn *conn) +{ + nvif_object_dtor(&conn->object); +} + +int +nvif_conn_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_conn *conn) +{ + struct nvif_conn_v0 args; + int ret; + + args.version = 0; + args.id = id; + + ret = nvif_object_ctor(&disp->object, name ?: "nvifConn", id, NVIF_CLASS_CONN, + &args, sizeof(args), &conn->object); + NVIF_ERRON(ret, &disp->object, "[NEW conn id:%d]", id); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvif/disp.c b/drivers/gpu/drm/nouveau/nvif/disp.c index 3a6b7ffeb97a..b8e98070c77e 100644 --- a/drivers/gpu/drm/nouveau/nvif/disp.c +++ b/drivers/gpu/drm/nouveau/nvif/disp.c @@ -69,5 +69,10 @@ nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct ret = nvif_object_ctor(&device->object, name ?: "nvifDisp", 0, disps[cid].oclass, &args, sizeof(args), &disp->object); NVIF_ERRON(ret, &device->object, "[NEW disp%04x]", disps[cid].oclass); - return ret; + if (ret) + return ret; + + NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x", args.conn_mask); + disp->conn_mask = args.conn_mask; + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 4b24c1eade5f..a5accccf88ea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -32,3 +32,4 @@ nvkm-y += nvkm/engine/disp/rootnv04.o nvkm-y += nvkm/engine/disp/rootnv50.o nvkm-y += nvkm/engine/disp/udisp.o +nvkm-y += nvkm/engine/disp/uconn.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h index dcbe60a4b911..f109634ce5ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: MIT */ #ifndef __NVKM_DISP_CONN_H__ #define __NVKM_DISP_CONN_H__ -#include +#include "priv.h" #include #include @@ -15,6 +15,8 @@ struct nvkm_conn { struct nvkm_notify hpd; struct list_head head; + + struct nvkm_object object; }; int nvkm_conn_new(struct nvkm_disp *, int index, struct nvbios_connE *, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index 5bd0e0e84c3f..d023ca634c83 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -84,4 +84,5 @@ extern const struct nvkm_event_func gf119_disp_chan_uevent; extern const struct nvkm_event_func gv100_disp_chan_uevent; int nvkm_udisp_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **); +int nvkm_uconn_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c new file mode 100644 index 000000000000..3fbbb6e6a66b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c @@ -0,0 +1,74 @@ +/* + * 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. + */ +#define nvkm_uconn(p) container_of((p), struct nvkm_conn, object) +#include "conn.h" + +#include + +static void * +nvkm_uconn_dtor(struct nvkm_object *object) +{ + struct nvkm_conn *conn = nvkm_uconn(object); + struct nvkm_disp *disp = conn->disp; + + spin_lock(&disp->client.lock); + conn->object.func = NULL; + spin_unlock(&disp->client.lock); + return NULL; +} + +static const struct nvkm_object_func +nvkm_uconn = { + .dtor = nvkm_uconn_dtor, +}; + +int +nvkm_uconn_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject) +{ + struct nvkm_disp *disp = nvkm_udisp(oclass->parent); + struct nvkm_conn *cont, *conn = NULL; + union nvif_conn_args *args = argv; + int ret; + + if (argc != sizeof(args->v0) || args->v0.version != 0) + return -ENOSYS; + + list_for_each_entry(cont, &disp->conns, head) { + if (cont->index == args->v0.id) { + conn = cont; + break; + } + } + + if (!conn) + return -EINVAL; + + ret = -EBUSY; + spin_lock(&disp->client.lock); + if (!conn->object.func) { + nvkm_object_ctor(&nvkm_uconn, oclass, &conn->object); + *pobject = &conn->object; + ret = 0; + } + spin_unlock(&disp->client.lock); + return ret; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c index f756208d4a14..82e052950a32 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c @@ -20,7 +20,9 @@ * OTHER DEALINGS IN THE SOFTWARE. */ #include "priv.h" +#include "conn.h" +#include #include static int @@ -28,6 +30,12 @@ nvkm_udisp_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *scl { struct nvkm_disp *disp = nvkm_udisp(object); + if (index-- == 0) { + sclass->base = (struct nvkm_sclass) { 0, 0, NVIF_CLASS_CONN }; + sclass->ctor = nvkm_uconn_new; + return 0; + } + if (disp->func->user[index].ctor) { sclass->base = disp->func->user[index].base; sclass->ctor = disp->func->user[index].ctor; @@ -72,6 +80,7 @@ int nvkm_udisp_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject) { struct nvkm_disp *disp = nvkm_disp(oclass->engine); + struct nvkm_conn *conn; union nvif_disp_args *args = argv; if (argc != sizeof(args->v0) || args->v0.version != 0) @@ -85,5 +94,10 @@ nvkm_udisp_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nv nvkm_object_ctor(&nvkm_udisp, oclass, &disp->client.object); *pobject = &disp->client.object; spin_unlock(&disp->client.lock); + + args->v0.conn_mask = 0; + list_for_each_entry(conn, &disp->conns, head) + args->v0.conn_mask |= BIT(conn->index); + return 0; } -- cgit v1.2.3