From 4a84a6fd9a50e4a10dccaaff9cf9e12d04f2c83f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 27 Jun 2017 09:08:58 +0100 Subject: [PATCH 01/20] drm/nouveau/therm: fix spelling mistake on array thresolds Array thresolds should be named thresholds, rename it. Also make it static static const char * const Signed-off-by: Colin Ian King Reviewed-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c index e93b2410c38b..ddb2b2c600ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c @@ -83,7 +83,7 @@ nvkm_therm_sensor_event(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs, { struct nvkm_subdev *subdev = &therm->subdev; bool active; - const char *thresolds[] = { + static const char * const thresholds[] = { "fanboost", "downclock", "critical", "shutdown" }; int temperature = therm->func->temp_get(therm); @@ -94,10 +94,10 @@ nvkm_therm_sensor_event(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs, if (dir == NVKM_THERM_THRS_FALLING) nvkm_info(subdev, "temperature (%i C) went below the '%s' threshold\n", - temperature, thresolds[thrs]); + temperature, thresholds[thrs]); else nvkm_info(subdev, "temperature (%i C) hit the '%s' threshold\n", - temperature, thresolds[thrs]); + temperature, thresholds[thrs]); active = (dir == NVKM_THERM_THRS_RISING); switch (thrs) { From 9d60b9c9d0b6bacee794db9cd18671296b7db072 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Mon, 3 Jul 2017 20:02:51 +0200 Subject: [PATCH 02/20] drm/nouveau/therm/gm200: Added This allows temperature readouts on maxwell2 GPUs. Signed-off-by: Karol Herbst Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/therm.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 3 ++ .../gpu/drm/nouveau/nvkm/subdev/therm/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/subdev/therm/g84.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/therm/gm200.c | 39 +++++++++++++++++++ .../gpu/drm/nouveau/nvkm/subdev/therm/priv.h | 1 + 6 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm200.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h index b268b96faece..1bfd93b85575 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h @@ -96,4 +96,5 @@ int g84_therm_new(struct nvkm_device *, int, struct nvkm_therm **); int gt215_therm_new(struct nvkm_device *, int, struct nvkm_therm **); int gf119_therm_new(struct nvkm_device *, int, struct nvkm_therm **); int gm107_therm_new(struct nvkm_device *, int, struct nvkm_therm **); +int gm200_therm_new(struct nvkm_device *, int, struct nvkm_therm **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 7bdc7a5ae723..39fdafed7b4e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2043,6 +2043,7 @@ nv120_chipset = { .mxm = nv50_mxm_new, .pci = gk104_pci_new, .pmu = gm107_pmu_new, + .therm = gm200_therm_new, .secboot = gm200_secboot_new, .timer = gk20a_timer_new, .top = gk104_top_new, @@ -2077,6 +2078,7 @@ nv124_chipset = { .mxm = nv50_mxm_new, .pci = gk104_pci_new, .pmu = gm107_pmu_new, + .therm = gm200_therm_new, .secboot = gm200_secboot_new, .timer = gk20a_timer_new, .top = gk104_top_new, @@ -2111,6 +2113,7 @@ nv126_chipset = { .mxm = nv50_mxm_new, .pci = gk104_pci_new, .pmu = gm107_pmu_new, + .therm = gm200_therm_new, .secboot = gm200_secboot_new, .timer = gk20a_timer_new, .top = gk104_top_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild index 135758ba3e28..2bafcc1d1818 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild @@ -11,3 +11,4 @@ nvkm-y += nvkm/subdev/therm/g84.o nvkm-y += nvkm/subdev/therm/gt215.o nvkm-y += nvkm/subdev/therm/gf119.o nvkm-y += nvkm/subdev/therm/gm107.o +nvkm-y += nvkm/subdev/therm/gm200.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c index 86e81930d8ee..96f8da40ac82 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c @@ -203,7 +203,7 @@ g84_therm_fini(struct nvkm_therm *therm) nvkm_wr32(device, 0x1100, 0x10000); /* PBUS */ } -static void +void g84_therm_init(struct nvkm_therm *therm) { g84_sensor_setup(therm); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm200.c new file mode 100644 index 000000000000..73dc78093d5d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm200.c @@ -0,0 +1,39 @@ +/* + * Copyright 2017 Karol Herbst + * + * 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. + * + * Authors: Karol Herbst + */ +#include "priv.h" + +static const struct nvkm_therm_func +gm200_therm = { + .init = g84_therm_init, + .fini = g84_therm_fini, + .temp_get = g84_temp_get, + .program_alarms = nvkm_therm_program_alarms_polling, +}; + +int +gm200_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(&gm200_therm, device, index, ptherm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h index 235a5d8daff6..1f46e371d7c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h @@ -111,6 +111,7 @@ void g84_therm_fini(struct nvkm_therm *); int gt215_therm_fan_sense(struct nvkm_therm *); +void g84_therm_init(struct nvkm_therm *); void gf119_therm_init(struct nvkm_therm *); int nvkm_fanpwm_create(struct nvkm_therm *, struct dcb_gpio_func *); From eba5e56db65b7a44d57a98f5f382b2a2b9991321 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Mon, 3 Jul 2017 13:06:26 -0400 Subject: [PATCH 03/20] drm/nouveau/disp/gf119-: avoid creating non-existent heads We assume that each board has 4 heads for GF119+. However this is not necessarily true - in the case of a GP108 board, the register indicated that there were only 2. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101601 Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 8 +++++--- drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index f7b4326a4641..1449a2c8a1e9 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -4451,11 +4451,13 @@ nv50_display_create(struct drm_device *dev) /* create crtc objects to represent the hw heads */ if (disp->disp->oclass >= GF110_DISP) - crtcs = nvif_rd32(&device->object, 0x022448); + crtcs = nvif_rd32(&device->object, 0x612004) & 0xf; else - crtcs = 2; + crtcs = 0x3; - for (i = 0; i < crtcs; i++) { + for (i = 0; i < fls(crtcs); i++) { + if (!(crtcs & (1 << i))) + continue; ret = nv50_head_create(dev, i); if (ret) goto out; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c index b33552757647..9fd7ae331308 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c @@ -92,5 +92,8 @@ gf119_head = { int gf119_head_new(struct nvkm_disp *disp, int id) { + struct nvkm_device *device = disp->engine.subdev.device; + if (!(nvkm_rd32(device, 0x612004) & (0x00000001 << id))) + return 0; return nvkm_head_new_(&gf119_head, disp, id); } From 1ccd7d52b16e74366d9f401927c85fb285803fff Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Jul 2017 14:04:42 +1000 Subject: [PATCH 04/20] drm/nouveau/mc/gf100: add pmu to reset mask An upcoming commit will replace direct NV_PMC register bashing from PMU with a call to the proper function. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index d2c4d6033abb..f93766418056 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -27,6 +27,7 @@ static const struct nvkm_mc_map gf100_mc_reset[] = { { 0x00020000, NVKM_ENGINE_MSPDEC }, { 0x00008000, NVKM_ENGINE_MSVLD }, + { 0x00002000, NVKM_SUBDEV_PMU, true }, { 0x00001000, NVKM_ENGINE_GR }, { 0x00000100, NVKM_ENGINE_FIFO }, { 0x00000080, NVKM_ENGINE_CE1 }, From 715e7d261dea75911c4dad468a1103168933d913 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 21 Jul 2017 10:33:52 +1000 Subject: [PATCH 05/20] drm/nouveau/pmu/gt215: fix reset The NV_PMC_ENABLE bit for PMU did not appear until GF100, and some other unknown register needs to be poked instead. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c | 12 +++++++++++- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp100.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h | 3 ++- 10 files changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c index 0e36d4cb7201..976a08205441 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c @@ -24,13 +24,23 @@ #include "priv.h" #include "fuc/gf100.fuc3.h" +#include + +void +gf100_pmu_reset(struct nvkm_pmu *pmu) +{ + struct nvkm_device *device = pmu->subdev.device; + nvkm_mc_disable(device, NVKM_SUBDEV_PMU); + nvkm_mc_enable(device, NVKM_SUBDEV_PMU); +} + static const struct nvkm_pmu_func gf100_pmu = { .code.data = gf100_pmu_code, .code.size = sizeof(gf100_pmu_code), .data.data = gf100_pmu_data, .data.size = sizeof(gf100_pmu_data), - .reset = gt215_pmu_reset, + .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, .intr = gt215_pmu_intr, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c index 0e4ba4248b15..ca3b4dfe18e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c @@ -30,7 +30,7 @@ gf119_pmu = { .code.size = sizeof(gf119_pmu_code), .data.data = gf119_pmu_data, .data.size = sizeof(gf119_pmu_data), - .reset = gt215_pmu_reset, + .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, .intr = gt215_pmu_intr, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index 2ad858d825ac..c26195d5fc32 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -109,7 +109,7 @@ gk104_pmu = { .code.size = sizeof(gk104_pmu_code), .data.data = gk104_pmu_data, .data.size = sizeof(gk104_pmu_data), - .reset = gt215_pmu_reset, + .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, .intr = gt215_pmu_intr, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c index fc4b8ecfdaeb..aac0258a1bab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c @@ -88,7 +88,7 @@ gk110_pmu = { .code.size = sizeof(gk110_pmu_code), .data.data = gk110_pmu_data, .data.size = sizeof(gk110_pmu_data), - .reset = gt215_pmu_reset, + .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, .intr = gt215_pmu_intr, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c index e9a91277683a..0efbc0f9fffb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c @@ -30,7 +30,7 @@ gk208_pmu = { .code.size = sizeof(gk208_pmu_code), .data.data = gk208_pmu_data, .data.size = sizeof(gk208_pmu_data), - .reset = gt215_pmu_reset, + .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, .intr = gt215_pmu_intr, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 978aae3c1001..14862452a597 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -198,7 +198,7 @@ static const struct nvkm_pmu_func gk20a_pmu = { .init = gk20a_pmu_init, .fini = gk20a_pmu_fini, - .reset = gt215_pmu_reset, + .reset = gf100_pmu_reset, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c index 9a248ed75f09..25e18f2ea081 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c @@ -32,7 +32,7 @@ gm107_pmu = { .code.size = sizeof(gm107_pmu_code), .data.data = gm107_pmu_data, .data.size = sizeof(gm107_pmu_data), - .reset = gt215_pmu_reset, + .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, .intr = gt215_pmu_intr, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp100.c index 6c41c20c85a7..0e23d5d4bb34 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp100.c @@ -25,7 +25,7 @@ static const struct nvkm_pmu_func gp100_pmu = { - .reset = gt215_pmu_reset, + .reset = gf100_pmu_reset, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c index 90d428b3be97..9b5d97dac550 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c @@ -180,13 +180,13 @@ gt215_pmu_fini(struct nvkm_pmu *pmu) nvkm_wr32(pmu->subdev.device, 0x10a014, 0x00000060); } -void +static void gt215_pmu_reset(struct nvkm_pmu *pmu) { struct nvkm_device *device = pmu->subdev.device; - nvkm_mask(device, 0x000200, 0x00002000, 0x00000000); - nvkm_mask(device, 0x000200, 0x00002000, 0x00002000); - nvkm_rd32(device, 0x000200); + nvkm_mask(device, 0x022210, 0x00000001, 0x00000000); + nvkm_mask(device, 0x022210, 0x00000001, 0x00000001); + nvkm_rd32(device, 0x022210); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h index 096cba069f72..616641d543a8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h @@ -30,12 +30,13 @@ struct nvkm_pmu_func { void (*pgob)(struct nvkm_pmu *, bool); }; -void gt215_pmu_reset(struct nvkm_pmu *); int gt215_pmu_init(struct nvkm_pmu *); void gt215_pmu_fini(struct nvkm_pmu *); void gt215_pmu_intr(struct nvkm_pmu *); void gt215_pmu_recv(struct nvkm_pmu *); int gt215_pmu_send(struct nvkm_pmu *, u32[2], u32, u32, u32, u32); +void gf100_pmu_reset(struct nvkm_pmu *); + void gk110_pmu_pgob(struct nvkm_pmu *, bool); #endif From 6b1277c837630749b55f743dd62023d9dd7a510a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 21 Jul 2017 10:45:32 +1000 Subject: [PATCH 06/20] drm/nouveau/pmu/gt215-: abstract detection of whether reset is needed GT215, GF100-GP100, and GP10x are all different. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c | 7 +++++++ drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp100.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c | 7 +++++++ drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c | 7 +++++++ drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h | 2 ++ 13 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index 3306f9fe7140..ce70a193caa7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -75,7 +75,7 @@ nvkm_pmu_reset(struct nvkm_pmu *pmu) { struct nvkm_device *device = pmu->subdev.device; - if (!(nvkm_rd32(device, 0x000200) & 0x00002000)) + if (!pmu->func->enabled(pmu)) return 0; /* Inhibit interrupts, and wait for idle. */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c index 976a08205441..0b458656e870 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c @@ -34,12 +34,19 @@ gf100_pmu_reset(struct nvkm_pmu *pmu) nvkm_mc_enable(device, NVKM_SUBDEV_PMU); } +bool +gf100_pmu_enabled(struct nvkm_pmu *pmu) +{ + return nvkm_mc_enabled(pmu->subdev.device, NVKM_SUBDEV_PMU); +} + static const struct nvkm_pmu_func gf100_pmu = { .code.data = gf100_pmu_code, .code.size = sizeof(gf100_pmu_code), .data.data = gf100_pmu_data, .data.size = sizeof(gf100_pmu_data), + .enabled = gf100_pmu_enabled, .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c index ca3b4dfe18e3..3dfa79d4fb13 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c @@ -30,6 +30,7 @@ gf119_pmu = { .code.size = sizeof(gf119_pmu_code), .data.data = gf119_pmu_data, .data.size = sizeof(gf119_pmu_data), + .enabled = gf100_pmu_enabled, .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index c26195d5fc32..8f7ec10fd2a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -109,6 +109,7 @@ gk104_pmu = { .code.size = sizeof(gk104_pmu_code), .data.data = gk104_pmu_data, .data.size = sizeof(gk104_pmu_data), + .enabled = gf100_pmu_enabled, .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c index aac0258a1bab..345741d55a56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c @@ -88,6 +88,7 @@ gk110_pmu = { .code.size = sizeof(gk110_pmu_code), .data.data = gk110_pmu_data, .data.size = sizeof(gk110_pmu_data), + .enabled = gf100_pmu_enabled, .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c index 0efbc0f9fffb..e4acf7876ea1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c @@ -30,6 +30,7 @@ gk208_pmu = { .code.size = sizeof(gk208_pmu_code), .data.data = gk208_pmu_data, .data.size = sizeof(gk208_pmu_data), + .enabled = gf100_pmu_enabled, .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 14862452a597..05e81855c367 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -196,6 +196,7 @@ gk20a_dvfs_data= { static const struct nvkm_pmu_func gk20a_pmu = { + .enabled = gf100_pmu_enabled, .init = gk20a_pmu_init, .fini = gk20a_pmu_fini, .reset = gf100_pmu_reset, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c index 25e18f2ea081..459df1ef9e70 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c @@ -32,6 +32,7 @@ gm107_pmu = { .code.size = sizeof(gm107_pmu_code), .data.data = gm107_pmu_data, .data.size = sizeof(gm107_pmu_data), + .enabled = gf100_pmu_enabled, .reset = gf100_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c index 44bef22bce52..31c843145c7a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c @@ -38,6 +38,7 @@ gm20b_pmu_recv(struct nvkm_pmu *pmu) static const struct nvkm_pmu_func gm20b_pmu = { + .enabled = gf100_pmu_enabled, .intr = gt215_pmu_intr, .recv = gm20b_pmu_recv, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp100.c index 0e23d5d4bb34..e210cd6af816 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp100.c @@ -25,6 +25,7 @@ static const struct nvkm_pmu_func gp100_pmu = { + .enabled = gf100_pmu_enabled, .reset = gf100_pmu_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c index f017352206c9..98c7a2a8afc4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c @@ -31,8 +31,15 @@ gp102_pmu_reset(struct nvkm_pmu *pmu) nvkm_mask(device, 0x10a3c0, 0x00000001, 0x00000000); } +static bool +gp102_pmu_enabled(struct nvkm_pmu *pmu) +{ + return !(nvkm_rd32(pmu->subdev.device, 0x10a3c0) & 0x00000001); +} + static const struct nvkm_pmu_func gp102_pmu = { + .enabled = gp102_pmu_enabled, .reset = gp102_pmu_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c index 9b5d97dac550..e04216daea58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c @@ -189,6 +189,12 @@ gt215_pmu_reset(struct nvkm_pmu *pmu) nvkm_rd32(device, 0x022210); } +static bool +gt215_pmu_enabled(struct nvkm_pmu *pmu) +{ + return nvkm_rd32(pmu->subdev.device, 0x022210) & 0x00000001; +} + int gt215_pmu_init(struct nvkm_pmu *pmu) { @@ -241,6 +247,7 @@ gt215_pmu = { .code.size = sizeof(gt215_pmu_code), .data.data = gt215_pmu_data, .data.size = sizeof(gt215_pmu_data), + .enabled = gt215_pmu_enabled, .reset = gt215_pmu_reset, .init = gt215_pmu_init, .fini = gt215_pmu_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h index 616641d543a8..a4c48a10cd47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h @@ -20,6 +20,7 @@ struct nvkm_pmu_func { u32 size; } data; + bool (*enabled)(struct nvkm_pmu *); void (*reset)(struct nvkm_pmu *); int (*init)(struct nvkm_pmu *); void (*fini)(struct nvkm_pmu *); @@ -36,6 +37,7 @@ void gt215_pmu_intr(struct nvkm_pmu *); void gt215_pmu_recv(struct nvkm_pmu *); int gt215_pmu_send(struct nvkm_pmu *, u32[2], u32, u32, u32, u32); +bool gf100_pmu_enabled(struct nvkm_pmu *); void gf100_pmu_reset(struct nvkm_pmu *); void gk110_pmu_pgob(struct nvkm_pmu *, bool); From 81904932449cf832ab1982d302dc6c8f8b24b289 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 25 Jul 2017 14:08:56 -0700 Subject: [PATCH 07/20] drm/nouveau/bios: Demote missing fp table message to NV_DEBUG. This warning seems to pop up mainly in laptop cards. Silence it as it is expected behavior. Signed-off by: Rosen Penev Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index b998c33af18a..dd6fba55ad5d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -351,11 +351,8 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios) struct lvdstableheader lth; if (bios->fp.fptablepointer == 0x0) { - /* Apple cards don't have the fp table; the laptops use DDC */ - /* The table is also missing on some x86 IGPs */ -#ifndef __powerpc__ - NV_ERROR(drm, "Pointer to flat panel table invalid\n"); -#endif + /* Most laptop cards lack an fp table. They use DDC. */ + NV_DEBUG(drm, "Pointer to flat panel table invalid\n"); bios->digital_min_front_porch = 0x4b; return 0; } From df00d5da609f59022ee9aafdb4e2313aefeb6bda Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 25 Jul 2017 17:21:43 -0700 Subject: [PATCH 08/20] drm/nouveau/disp: Silence DCB warnings. Most of these errors seem to be WFD related. Official documentation says dcb type 8 is reserved. It's probably used for WFD. Silence the warning in either case. Connector type 70 is stated to be a virtual connector for WiFi display. Since we know this, don't warn that we don't. Signed-off by: Rosen Penev Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h | 1 + drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h | 1 + drivers/gpu/drm/nouveau/nouveau_connector.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c | 4 ++++ 4 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h index e8e77ee24776..deb477282dde 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h @@ -18,6 +18,7 @@ enum dcb_connector_type { DCB_CONNECTOR_HDMI_C = 0x63, DCB_CONNECTOR_DMS59_DP0 = 0x64, DCB_CONNECTOR_DMS59_DP1 = 0x65, + DCB_CONNECTOR_WFD = 0x70, DCB_CONNECTOR_NONE = 0xff }; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h index 4892a65ddd48..903d117603d8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h @@ -6,6 +6,7 @@ enum dcb_output_type { DCB_OUTPUT_TMDS = 0x2, DCB_OUTPUT_LVDS = 0x3, DCB_OUTPUT_DP = 0x6, + DCB_OUTPUT_WFD = 0x8, DCB_OUTPUT_EOL = 0xe, DCB_OUTPUT_UNUSED = 0xf, DCB_OUTPUT_ANY = -1, diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 5137155bf3c0..70d8e0d69ad5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1184,6 +1184,7 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb) case DCB_CONNECTOR_HDMI_0 : case DCB_CONNECTOR_HDMI_1 : case DCB_CONNECTOR_HDMI_C : return DRM_MODE_CONNECTOR_HDMIA; + case DCB_CONNECTOR_WFD : return DRM_MODE_CONNECTOR_VIRTUAL; default: break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 88582af8bd89..93a75e5b2791 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -285,6 +285,10 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) case DCB_OUTPUT_DP: ret = nvkm_dp_new(disp, i, &dcbE, &outp); break; + case DCB_OUTPUT_WFD: + /* No support for WFD yet. */ + ret = -ENODEV; + continue; default: nvkm_warn(subdev, "dcb %d type %d unknown\n", i, dcbE.type); From e20868b906417db9b44ccca5865efe7411e93fb6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 1 Aug 2017 16:15:46 +1000 Subject: [PATCH 09/20] drm/nouveau/falcon: use a more reasonable msgqueue timeout value Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c index d45d7947a964..77273b53672c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c @@ -251,7 +251,7 @@ cmd_write(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_hdr *cmd, struct nvkm_msgqueue_queue *queue) { const struct nvkm_subdev *subdev = priv->falcon->owner; - static unsigned long timeout = ~0; + static unsigned timeout = 2000; unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout); int ret = -EAGAIN; bool commit = true; From 2659b4ce284be569b06ea2c13e5d30517f8095ed Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Mon, 3 Jul 2017 14:46:21 -0400 Subject: [PATCH 10/20] initial support (display-only) for GP108 Forked from GP107 implementation. Secboot/gr left out as we don't have signed blobs from NVIDIA in linux-firmware. (Ben): Was unable to mmiotrace the binary driver for unknown reasons, so not able to 100% confirm that no other changes from GP107 are needed. Quick testing shows it seems to work well enough for display. Due to NVIDIA dragging their heels on getting signed firmware to us, this is the best we can do for now. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101601 Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 39fdafed7b4e..e096a5d9c292 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2323,6 +2323,35 @@ nv137_chipset = { .sw = gf100_sw_new, }; +static const struct nvkm_device_chip +nv138_chipset = { + .name = "GP108", + .bar = gf100_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .devinit = gm200_devinit_new, + .fb = gp102_fb_new, + .fuse = gm107_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gm200_i2c_new, + .ibus = gm200_ibus_new, + .imem = nv50_instmem_new, + .ltc = gp100_ltc_new, + .mc = gp100_mc_new, + .mmu = gf100_mmu_new, + .pci = gp100_pci_new, + .pmu = gp102_pmu_new, + .timer = gk20a_timer_new, + .top = gk104_top_new, + .ce[0] = gp102_ce_new, + .ce[1] = gp102_ce_new, + .ce[2] = gp102_ce_new, + .ce[3] = gp102_ce_new, + .disp = gp102_disp_new, + .dma = gf119_dma_new, + .fifo = gp100_fifo_new, +}; + static const struct nvkm_device_chip nv13b_chipset = { .name = "GP10B", @@ -2785,6 +2814,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, case 0x134: device->chip = &nv134_chipset; break; case 0x136: device->chip = &nv136_chipset; break; case 0x137: device->chip = &nv137_chipset; break; + case 0x138: device->chip = &nv138_chipset; break; case 0x13b: device->chip = &nv13b_chipset; break; default: nvdev_error(device, "unknown chipset (%08x)\n", boot0); From 485c2c91d403185c126dd18bfc98599be9db3acf Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Aug 2017 10:44:34 +1000 Subject: [PATCH 11/20] drm/nouveau/bar/gf100: add config option to limit BAR2 to 16MiB Useful for testing, and for the userspace build where we can't kick a framebuffer driver off the device. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 6 ++++++ drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 6d8f21290aa2..676c167c95b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -24,6 +24,7 @@ #include "gf100.h" #include +#include #include #include @@ -59,6 +60,8 @@ gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, return ret; bar_len = device->func->resource_size(device, bar_nr); + if (bar_nr == 3 && bar->bar2_halve) + bar_len >>= 1; ret = nvkm_vm_new(device, 0, bar_len, 0, key, &vm); if (ret) @@ -129,6 +132,8 @@ gf100_bar_init(struct nvkm_bar *base) if (bar->bar[0].mem) { addr = nvkm_memory_addr(bar->bar[0].mem) >> 12; + if (bar->bar2_halve) + addr |= 0x40000000; nvkm_wr32(device, 0x001714, 0x80000000 | addr); } @@ -161,6 +166,7 @@ gf100_bar_new_(const struct nvkm_bar_func *func, struct nvkm_device *device, if (!(bar = kzalloc(sizeof(*bar), GFP_KERNEL))) return -ENOMEM; nvkm_bar_ctor(func, device, index, &bar->base); + bar->bar2_halve = nvkm_boolopt(device->cfgopt, "NvBar2Halve", false); *pbar = &bar->base; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h index f7dea69640d8..20a5255362ba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h @@ -11,6 +11,7 @@ struct gf100_bar_vm { struct gf100_bar { struct nvkm_bar base; + bool bar2_halve; struct gf100_bar_vm bar[2]; }; From 7a1af0f8bb0c8ba2a3a97f8a82f782549b3116df Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 7 Aug 2017 13:27:31 +1000 Subject: [PATCH 12/20] drm/nouveau/fb/gf100-: zero mmu debug buffers These are used for accesses to sparse mappings, and we want reads of such mappings to return 0. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index 3841ad6be99e..a239e73562c8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -60,12 +60,12 @@ gf100_fb_oneinit(struct nvkm_fb *base) size = min(size, 0x1000); ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000, - false, &fb->base.mmu_rd); + true, &fb->base.mmu_rd); if (ret) return ret; ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000, - false, &fb->base.mmu_wr); + true, &fb->base.mmu_wr); if (ret) return ret; From d257f9bf06129613de539ea71ecea60848b662cd Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sat, 5 Aug 2017 22:19:53 -0400 Subject: [PATCH 13/20] drm/nouveau/mpeg: print more debug info when rejecting dma objects Signed-off-by: Ilia Mirkin Reviewed-by: Tobias Klausmann Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 7 ++++++- drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 8a8895246d26..7fea7d45202f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -124,6 +124,8 @@ nv31_mpeg_tile(struct nvkm_engine *engine, int i, struct nvkm_fb_tile *tile) static bool nv31_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) { + struct nv31_mpeg *mpeg = nv31_mpeg(device->mpeg); + struct nvkm_subdev *subdev = &mpeg->engine.subdev; u32 inst = data << 4; u32 dma0 = nvkm_rd32(device, 0x700000 + inst); u32 dma1 = nvkm_rd32(device, 0x700004 + inst); @@ -132,8 +134,11 @@ nv31_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) u32 size = dma1 + 1; /* only allow linear DMA objects */ - if (!(dma0 & 0x00002000)) + if (!(dma0 & 0x00002000)) { + nvkm_error(subdev, "inst %08x dma0 %08x dma1 %08x dma2 %08x\n", + inst, dma0, dma1, dma2); return false; + } if (mthd == 0x0190) { /* DMA_CMD */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c index 16de5bd94b14..b5ec7c504dc6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c @@ -31,6 +31,8 @@ bool nv40_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) { struct nvkm_instmem *imem = device->imem; + struct nv31_mpeg *mpeg = nv31_mpeg(device->mpeg); + struct nvkm_subdev *subdev = &mpeg->engine.subdev; u32 inst = data << 4; u32 dma0 = nvkm_instmem_rd32(imem, inst + 0); u32 dma1 = nvkm_instmem_rd32(imem, inst + 4); @@ -39,8 +41,11 @@ nv40_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) u32 size = dma1 + 1; /* only allow linear DMA objects */ - if (!(dma0 & 0x00002000)) + if (!(dma0 & 0x00002000)) { + nvkm_error(subdev, "inst %08x dma0 %08x dma1 %08x dma2 %08x\n", + inst, dma0, dma1, dma2); return false; + } if (mthd == 0x0190) { /* DMA_CMD */ From 3ce72bcf33c200e78b87699d20f8e5a564e29a98 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sat, 5 Aug 2017 22:25:02 -0400 Subject: [PATCH 14/20] drm/nouveau/kms/nv04-nv40: prevent undisplayable framebuffers from creation Pre-nv50 YUV overlays have stringent requirements for working with the internal machinery. Instead of rejecting these at update_plane time, we should instead prevent the framebuffers from being created in the first place. Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index d66640047913..2e7785f49e6d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -231,9 +231,30 @@ nouveau_framebuffer_new(struct drm_device *dev, struct nouveau_bo *nvbo, struct nouveau_framebuffer **pfb) { + struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_framebuffer *fb; int ret; + /* YUV overlays have special requirements pre-NV50 */ + if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA && + + (mode_cmd->pixel_format == DRM_FORMAT_YUYV || + mode_cmd->pixel_format == DRM_FORMAT_UYVY || + mode_cmd->pixel_format == DRM_FORMAT_NV12 || + mode_cmd->pixel_format == DRM_FORMAT_NV21) && + (mode_cmd->pitches[0] & 0x3f || /* align 64 */ + mode_cmd->pitches[0] >= 0x10000 || /* at most 64k pitch */ + (mode_cmd->pitches[1] && /* pitches for planes must match */ + mode_cmd->pitches[0] != mode_cmd->pitches[1]))) { + struct drm_format_name_buf format_name; + DRM_DEBUG_KMS("Unsuitable framebuffer: format: %s; pitches: 0x%x\n 0x%x\n", + drm_get_format_name(mode_cmd->pixel_format, + &format_name), + mode_cmd->pitches[0], + mode_cmd->pitches[1]); + return -EINVAL; + } + if (!(fb = *pfb = kzalloc(sizeof(*fb), GFP_KERNEL))) return -ENOMEM; From 9a6edc3ac968aca9ce51d16917705a857285286b Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sat, 5 Aug 2017 22:25:03 -0400 Subject: [PATCH 15/20] drm/nouveau/kms/nv04-nv40: improve overlay error detection, fix pitch setting We were previously setting the pitch based on a perfectly packed buffer. This does not necessarily happen. Either modetest started generating such buffers recently, or earlier testing only happened with well-picked overlay sizes. While we're at it, beef up and refactor the error state detection. Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/overlay.c | 62 ++++++++++++---------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index e54944d23268..5bd63c2f14a6 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -89,6 +89,26 @@ cos_mul(int degrees, int factor) return sin_mul((degrees + 90) % 360, factor); } +static int +verify_scaling(const struct drm_framebuffer *fb, uint8_t shift, + uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, + uint32_t crtc_w, uint32_t crtc_h) +{ + if (crtc_w < (src_w >> shift) || crtc_h < (src_h >> shift)) { + DRM_DEBUG_KMS("Unsuitable framebuffer scaling: %dx%d -> %dx%d\n", + src_w, src_h, crtc_w, crtc_h); + return -ERANGE; + } + + if (src_x != 0 || src_y != 0) { + DRM_DEBUG_KMS("Unsuitable framebuffer offset: %d,%d\n", + src_x, src_y); + return -ERANGE; + } + + return 0; +} + static int nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -107,7 +127,9 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, bool flip = nv_plane->flip; int soff = NV_PCRTC0_SIZE * nv_crtc->index; int soff2 = NV_PCRTC0_SIZE * !nv_crtc->index; - int format, ret; + unsigned shift = drm->client.device.info.chipset >= 0x30 ? 1 : 3; + unsigned format = 0; + int ret; /* Source parameters given in 16.16 fixed point, ignore fractional. */ src_x >>= 16; @@ -115,18 +137,9 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, src_w >>= 16; src_h >>= 16; - format = ALIGN(src_w * 4, 0x100); - - if (format > 0xffff) - return -ERANGE; - - if (drm->client.device.info.chipset >= 0x30) { - if (crtc_w < (src_w >> 1) || crtc_h < (src_h >> 1)) - return -ERANGE; - } else { - if (crtc_w < (src_w >> 3) || crtc_h < (src_h >> 3)) - return -ERANGE; - } + ret = verify_scaling(fb, shift, 0, 0, src_w, src_h, crtc_w, crtc_h); + if (ret) + return ret; ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM, false); if (ret) @@ -160,7 +173,7 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, nvif_wr32(dev, NV_PVIDEO_UVPLANE_OFFSET_BUFF(flip), nv_fb->nvbo->bo.offset + fb->offsets[1]); } - nvif_wr32(dev, NV_PVIDEO_FORMAT(flip), format); + nvif_wr32(dev, NV_PVIDEO_FORMAT(flip), format | fb->pitches[0]); nvif_wr32(dev, NV_PVIDEO_STOP, 0); /* TODO: wait for vblank? */ nvif_wr32(dev, NV_PVIDEO_BUFFER, flip ? 0x10 : 0x1); @@ -357,7 +370,7 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct nouveau_bo *cur = nv_plane->cur; uint32_t overlay = 1; int brightness = (nv_plane->brightness - 512) * 62 / 512; - int pitch, ret, i; + int ret, i; /* Source parameters given in 16.16 fixed point, ignore fractional. */ src_x >>= 16; @@ -365,17 +378,9 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, src_w >>= 16; src_h >>= 16; - pitch = ALIGN(src_w * 4, 0x100); - - if (pitch > 0xffff) - return -ERANGE; - - /* TODO: Compute an offset? Not sure how to do this for YUYV. */ - if (src_x != 0 || src_y != 0) - return -ERANGE; - - if (crtc_w < src_w || crtc_h < src_h) - return -ERANGE; + ret = verify_scaling(fb, 0, src_x, src_y, src_w, src_h, crtc_w, crtc_h); + if (ret) + return ret; ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM, false); if (ret) @@ -389,8 +394,9 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, for (i = 0; i < 2; i++) { nvif_wr32(dev, NV_PVIDEO_BUFF0_START_ADDRESS + 4 * i, - nv_fb->nvbo->bo.offset); - nvif_wr32(dev, NV_PVIDEO_BUFF0_PITCH_LENGTH + 4 * i, pitch); + nv_fb->nvbo->bo.offset); + nvif_wr32(dev, NV_PVIDEO_BUFF0_PITCH_LENGTH + 4 * i, + fb->pitches[0]); nvif_wr32(dev, NV_PVIDEO_BUFF0_OFFSET + 4 * i, 0); } nvif_wr32(dev, NV_PVIDEO_WINDOW_START, crtc_y << 16 | crtc_x); From 7fa620d577502670741925198b1ee5c55d3a65cf Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sat, 5 Aug 2017 22:25:04 -0400 Subject: [PATCH 16/20] drm/nouveau/kms/nv10-nv40: add NV21 support to overlay Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/overlay.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index 5bd63c2f14a6..c8c2333f24ee 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -63,6 +63,7 @@ static uint32_t formats[] = { DRM_FORMAT_YUYV, DRM_FORMAT_UYVY, DRM_FORMAT_NV12, + DRM_FORMAT_NV21, }; /* Sine can be approximated with @@ -159,16 +160,18 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, nvif_wr32(dev, NV_PVIDEO_POINT_OUT(flip), crtc_y << 16 | crtc_x); nvif_wr32(dev, NV_PVIDEO_SIZE_OUT(flip), crtc_h << 16 | crtc_w); - if (fb->format->format != DRM_FORMAT_UYVY) + if (fb->format->format == DRM_FORMAT_YUYV || + fb->format->format == DRM_FORMAT_NV12) format |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8; - if (fb->format->format == DRM_FORMAT_NV12) + if (fb->format->format == DRM_FORMAT_NV12 || + fb->format->format == DRM_FORMAT_NV21) format |= NV_PVIDEO_FORMAT_PLANAR; if (nv_plane->iturbt_709) format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709; if (nv_plane->colorkey & (1 << 24)) format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY; - if (fb->format->format == DRM_FORMAT_NV12) { + if (format & NV_PVIDEO_FORMAT_PLANAR) { nvif_wr32(dev, NV_PVIDEO_UVPLANE_BASE(flip), 0); nvif_wr32(dev, NV_PVIDEO_UVPLANE_OFFSET_BUFF(flip), nv_fb->nvbo->bo.offset + fb->offsets[1]); From 856718054a1b6f38e085021bbd5b0e74817a8fa6 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sat, 5 Aug 2017 22:25:05 -0400 Subject: [PATCH 17/20] drm/nouveau/kms/nv04-nv4x: fix exposed format list drm_crtc_init exposes the XRGB8888 and ARGB8888 formats. In actuality, ARGB8888's 32-bit depth messes up some formulas that weren't meant for it, and the alpha is fairly meaningless for the primary plane. The modesetting logic appears to be fully prepared for RGB565 as well as XRGB1555 however, as tested with modetest. Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/crtc.c | 36 ++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 8f689f1f6122..6aa6ee16dcbd 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -1096,6 +1096,38 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = { .disable = nv_crtc_disable, }; +static const uint32_t modeset_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB1555, +}; + +static struct drm_plane * +create_primary_plane(struct drm_device *dev) +{ + struct drm_plane *primary; + int ret; + + primary = kzalloc(sizeof(*primary), GFP_KERNEL); + if (primary == NULL) { + DRM_DEBUG_KMS("Failed to allocate primary plane\n"); + return NULL; + } + + /* possible_crtc's will be filled in later by crtc_init */ + ret = drm_universal_plane_init(dev, primary, 0, + &drm_primary_helper_funcs, + modeset_formats, + ARRAY_SIZE(modeset_formats), NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + kfree(primary); + primary = NULL; + } + + return primary; +} + int nv04_crtc_create(struct drm_device *dev, int crtc_num) { @@ -1114,7 +1146,9 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num) nv_crtc->save = nv_crtc_save; nv_crtc->restore = nv_crtc_restore; - drm_crtc_init(dev, &nv_crtc->base, &nv04_crtc_funcs); + drm_crtc_init_with_planes(dev, &nv_crtc->base, + create_primary_plane(dev), NULL, + &nv04_crtc_funcs, NULL); drm_crtc_helper_add(&nv_crtc->base, &nv04_crtc_helper_funcs); drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); From 2d38a5359f9070c3acfbc95e0539ff7688a1cd93 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 14 Aug 2017 08:40:55 +1000 Subject: [PATCH 18/20] drm/nouveau: silence suspend/resume debugging messages These are particularly annoying on Optimus systems where these paths can be called regularly. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index df7e2037031a..595630d1fb9e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -585,18 +585,18 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) nouveau_led_suspend(dev); if (dev->mode_config.num_crtc) { - NV_INFO(drm, "suspending console...\n"); + NV_DEBUG(drm, "suspending console...\n"); nouveau_fbcon_set_suspend(dev, 1); - NV_INFO(drm, "suspending display...\n"); + NV_DEBUG(drm, "suspending display...\n"); ret = nouveau_display_suspend(dev, runtime); if (ret) return ret; } - NV_INFO(drm, "evicting buffers...\n"); + NV_DEBUG(drm, "evicting buffers...\n"); ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM); - NV_INFO(drm, "waiting for kernel channels to go idle...\n"); + NV_DEBUG(drm, "waiting for kernel channels to go idle...\n"); if (drm->cechan) { ret = nouveau_channel_idle(drm->cechan); if (ret) @@ -609,7 +609,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) goto fail_display; } - NV_INFO(drm, "suspending fence...\n"); + NV_DEBUG(drm, "suspending fence...\n"); if (drm->fence && nouveau_fence(drm)->suspend) { if (!nouveau_fence(drm)->suspend(drm)) { ret = -ENOMEM; @@ -617,7 +617,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) } } - NV_INFO(drm, "suspending object tree...\n"); + NV_DEBUG(drm, "suspending object tree...\n"); ret = nvif_client_suspend(&drm->client.base); if (ret) goto fail_client; @@ -630,7 +630,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) fail_display: if (dev->mode_config.num_crtc) { - NV_INFO(drm, "resuming display...\n"); + NV_DEBUG(drm, "resuming display...\n"); nouveau_display_resume(dev, runtime); } return ret; @@ -641,19 +641,19 @@ nouveau_do_resume(struct drm_device *dev, bool runtime) { struct nouveau_drm *drm = nouveau_drm(dev); - NV_INFO(drm, "resuming object tree...\n"); + NV_DEBUG(drm, "resuming object tree...\n"); nvif_client_resume(&drm->client.base); - NV_INFO(drm, "resuming fence...\n"); + NV_DEBUG(drm, "resuming fence...\n"); if (drm->fence && nouveau_fence(drm)->resume) nouveau_fence(drm)->resume(drm); nouveau_run_vbios_init(dev); if (dev->mode_config.num_crtc) { - NV_INFO(drm, "resuming display...\n"); + NV_DEBUG(drm, "resuming display...\n"); nouveau_display_resume(dev, runtime); - NV_INFO(drm, "resuming console...\n"); + NV_DEBUG(drm, "resuming console...\n"); nouveau_fbcon_set_suspend(dev, 0); } From bc60c90f472b6e762ea96ef384072145adc8d4af Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Thu, 10 Aug 2017 12:13:40 -0400 Subject: [PATCH 19/20] drm/nouveau/pci/msi: disable MSI on big-endian platforms by default It appears that MSI does not work on either G5 PPC nor on a E5500-based platform, where other hardware is reported to work fine with MSI. Both tests were conducted with NV4x hardware, so perhaps other (or even this) hardware can be made to work. It's still possible to force-enable with config=NvMSI=1 on load. Signed-off-by: Ilia Mirkin Cc: stable@vger.kernel.org Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c index eb9b278198b2..a4cb82495cee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c @@ -192,6 +192,10 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device, } } +#ifdef __BIG_ENDIAN + pci->msi = false; +#endif + pci->msi = nvkm_boolopt(device->cfgopt, "NvMSI", pci->msi); if (pci->msi && func->msi_rearm) { pci->msi = pci_enable_msi(pci->pdev) == 0; From 27a451e83e78e1167f58cddba189fae4b4fa0d5b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 17 Aug 2017 23:03:23 +0100 Subject: [PATCH 20/20] drm/nouveau/kms/nv50: perform null check on msto[i] rathern than msto The null check on the array msto is incorrect since msto is never null. The null check should be instead on msto[i] since this is being dereferenced in the call to drm_mode_connector_attach_encoder. Thanks to Emil Velikov for pointing out the mistake in my original fix and for suggesting the correct fix. Detected by CoverityScan, CID#1375915 ("Array compared against 0") Fixes: f479c0ba4a17 ("drm/nouveau/kms/nv50: initial support for DP 1.2 multi-stream") Signed-off-by: Colin Ian King Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 1449a2c8a1e9..2dbf62a2ac41 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -3141,7 +3141,7 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, mstc->connector.funcs->reset(&mstc->connector); nouveau_conn_attach_properties(&mstc->connector); - for (i = 0; i < ARRAY_SIZE(mstm->msto) && mstm->msto; i++) + for (i = 0; i < ARRAY_SIZE(mstm->msto) && mstm->msto[i]; i++) drm_mode_connector_attach_encoder(&mstc->connector, &mstm->msto[i]->encoder); drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0);