From cfa736f5a6f31ca8a05459b5720aac030247ad1b Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Mon, 31 Aug 2020 13:31:11 -0700 Subject: drm/nouveau/nouveau: fix the start/end range for migration The user level OpenCL code shouldn't have to align start and end addresses to a page boundary. That is better handled in the nouveau driver. The npages field is also redundant since it can be computed from the start and end addresses. Signed-off-by: Ralph Campbell Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_svm.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c index 2df1c0460559..4f69e4c3dafd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_svm.c +++ b/drivers/gpu/drm/nouveau/nouveau_svm.c @@ -105,11 +105,11 @@ nouveau_svmm_bind(struct drm_device *dev, void *data, struct nouveau_cli *cli = nouveau_cli(file_priv); struct drm_nouveau_svm_bind *args = data; unsigned target, cmd, priority; - unsigned long addr, end, size; + unsigned long addr, end; struct mm_struct *mm; args->va_start &= PAGE_MASK; - args->va_end &= PAGE_MASK; + args->va_end = ALIGN(args->va_end, PAGE_SIZE); /* Sanity check arguments */ if (args->reserved0 || args->reserved1) @@ -118,8 +118,6 @@ nouveau_svmm_bind(struct drm_device *dev, void *data, return -EINVAL; if (args->va_start >= args->va_end) return -EINVAL; - if (!args->npages) - return -EINVAL; cmd = args->header >> NOUVEAU_SVM_BIND_COMMAND_SHIFT; cmd &= NOUVEAU_SVM_BIND_COMMAND_MASK; @@ -151,12 +149,6 @@ nouveau_svmm_bind(struct drm_device *dev, void *data, if (args->stride) return -EINVAL; - size = ((unsigned long)args->npages) << PAGE_SHIFT; - if ((args->va_start + size) <= args->va_start) - return -EINVAL; - if ((args->va_start + size) > args->va_end) - return -EINVAL; - /* * Ok we are ask to do something sane, for now we only support migrate * commands but we will add things like memory policy (what to do on @@ -171,7 +163,7 @@ nouveau_svmm_bind(struct drm_device *dev, void *data, return -EINVAL; } - for (addr = args->va_start, end = args->va_start + size; addr < end;) { + for (addr = args->va_start, end = args->va_end; addr < end;) { struct vm_area_struct *vma; unsigned long next; -- cgit v1.2.3 From 24d9422e26ea75118acf00172f83417c296f5b5f Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 4 Sep 2020 16:27:58 -0400 Subject: drm/nouveau/kms/nv50-: Program notifier offset before requesting disp caps Not entirely sure why this never came up when I originally tested this (maybe some BIOSes already have this setup?) but the ->caps_init vfunc appears to cause the display engine to throw an exception on driver init, at least on my ThinkPad P72: nouveau 0000:01:00.0: disp: chid 0 mthd 008c data 00000000 0000508c 0000102b This is magic nvidia speak for "You need to have the DMA notifier offset programmed before you can call NV507D_GET_CAPABILITIES." So, let's fix this by doing that, and also perform an update afterwards to prevent racing with the GPU when reading capabilities. v2: * Don't just program the DMA notifier offset, make sure to actually perform an update v3: * Don't call UPDATE() * Actually read the correct notifier fields, as apparently the CAPABILITIES_DONE field lives in a different location than the main NV_DISP_CORE_NOTIFIER_1 field. As well, 907d+ use a different CAPABILITIES_DONE field then pre-907d cards. v4: * Don't forget to check the return value of core507d_read_caps() v5: * Get rid of NV50_DISP_CAPS_NTFY[14], use NV50_DISP_CORE_NTFY * Disable notifier after calling GetCapabilities() Signed-off-by: Lyude Paul Fixes: 4a2cb4181b07 ("drm/nouveau/kms/nv50-: Probe SOR and PIOR caps for DP interlacing support") Cc: # v5.8+ Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv50/core.h | 2 ++ drivers/gpu/drm/nouveau/dispnv50/core507d.c | 41 ++++++++++++++++++++-- drivers/gpu/drm/nouveau/dispnv50/core907d.c | 36 ++++++++++++++++++- drivers/gpu/drm/nouveau/dispnv50/core917d.c | 2 +- .../gpu/drm/nouveau/include/nvhw/class/cl507d.h | 5 ++- .../gpu/drm/nouveau/include/nvhw/class/cl907d.h | 4 +++ 6 files changed, 85 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/dispnv50/core.h b/drivers/gpu/drm/nouveau/dispnv50/core.h index 498622c0c670..f75088186fba 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core.h +++ b/drivers/gpu/drm/nouveau/dispnv50/core.h @@ -44,6 +44,7 @@ int core507d_new_(const struct nv50_core_func *, struct nouveau_drm *, s32, struct nv50_core **); int core507d_init(struct nv50_core *); void core507d_ntfy_init(struct nouveau_bo *, u32); +int core507d_read_caps(struct nv50_disp *disp); int core507d_caps_init(struct nouveau_drm *, struct nv50_disp *); int core507d_ntfy_wait_done(struct nouveau_bo *, u32, struct nvif_device *); int core507d_update(struct nv50_core *, u32 *, bool); @@ -55,6 +56,7 @@ extern const struct nv50_outp_func pior507d; int core827d_new(struct nouveau_drm *, s32, struct nv50_core **); int core907d_new(struct nouveau_drm *, s32, struct nv50_core **); +int core907d_caps_init(struct nouveau_drm *drm, struct nv50_disp *disp); extern const struct nv50_outp_func dac907d; extern const struct nv50_outp_func sor907d; diff --git a/drivers/gpu/drm/nouveau/dispnv50/core507d.c b/drivers/gpu/drm/nouveau/dispnv50/core507d.c index 248edf69e168..e6f16a7750f0 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core507d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/core507d.c @@ -78,18 +78,55 @@ core507d_ntfy_init(struct nouveau_bo *bo, u32 offset) } int -core507d_caps_init(struct nouveau_drm *drm, struct nv50_disp *disp) +core507d_read_caps(struct nv50_disp *disp) { struct nvif_push *push = disp->core->chan.push; int ret; - if ((ret = PUSH_WAIT(push, 2))) + ret = PUSH_WAIT(push, 6); + if (ret) return ret; + PUSH_MTHD(push, NV507D, SET_NOTIFIER_CONTROL, + NVDEF(NV507D, SET_NOTIFIER_CONTROL, MODE, WRITE) | + NVVAL(NV507D, SET_NOTIFIER_CONTROL, OFFSET, NV50_DISP_CORE_NTFY >> 2) | + NVDEF(NV507D, SET_NOTIFIER_CONTROL, NOTIFY, ENABLE)); + PUSH_MTHD(push, NV507D, GET_CAPABILITIES, 0x00000000); + + PUSH_MTHD(push, NV507D, SET_NOTIFIER_CONTROL, + NVDEF(NV507D, SET_NOTIFIER_CONTROL, NOTIFY, DISABLE)); + return PUSH_KICK(push); } +int +core507d_caps_init(struct nouveau_drm *drm, struct nv50_disp *disp) +{ + struct nv50_core *core = disp->core; + struct nouveau_bo *bo = disp->sync; + s64 time; + int ret; + + NVBO_WR32(bo, NV50_DISP_CORE_NTFY, NV_DISP_CORE_NOTIFIER_1, CAPABILITIES_1, + NVDEF(NV_DISP_CORE_NOTIFIER_1, CAPABILITIES_1, DONE, FALSE)); + + ret = core507d_read_caps(disp); + if (ret < 0) + return ret; + + time = nvif_msec(core->chan.base.device, 2000ULL, + if (NVBO_TD32(bo, NV50_DISP_CORE_NTFY, + NV_DISP_CORE_NOTIFIER_1, CAPABILITIES_1, DONE, ==, TRUE)) + break; + usleep_range(1, 2); + ); + if (time < 0) + NV_ERROR(drm, "core caps notifier timeout\n"); + + return 0; +} + int core507d_init(struct nv50_core *core) { diff --git a/drivers/gpu/drm/nouveau/dispnv50/core907d.c b/drivers/gpu/drm/nouveau/dispnv50/core907d.c index b17c03529c78..8564d4dffaff 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core907d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/core907d.c @@ -22,11 +22,45 @@ #include "core.h" #include "head.h" +#include +#include + +#include + +#include "nouveau_bo.h" + +int +core907d_caps_init(struct nouveau_drm *drm, struct nv50_disp *disp) +{ + struct nv50_core *core = disp->core; + struct nouveau_bo *bo = disp->sync; + s64 time; + int ret; + + NVBO_WR32(bo, NV50_DISP_CORE_NTFY, NV907D_CORE_NOTIFIER_3, CAPABILITIES_4, + NVDEF(NV907D_CORE_NOTIFIER_3, CAPABILITIES_4, DONE, FALSE)); + + ret = core507d_read_caps(disp); + if (ret < 0) + return ret; + + time = nvif_msec(core->chan.base.device, 2000ULL, + if (NVBO_TD32(bo, NV50_DISP_CORE_NTFY, + NV907D_CORE_NOTIFIER_3, CAPABILITIES_4, DONE, ==, TRUE)) + break; + usleep_range(1, 2); + ); + if (time < 0) + NV_ERROR(drm, "core caps notifier timeout\n"); + + return 0; +} + static const struct nv50_core_func core907d = { .init = core507d_init, .ntfy_init = core507d_ntfy_init, - .caps_init = core507d_caps_init, + .caps_init = core907d_caps_init, .ntfy_wait_done = core507d_ntfy_wait_done, .update = core507d_update, .head = &head907d, diff --git a/drivers/gpu/drm/nouveau/dispnv50/core917d.c b/drivers/gpu/drm/nouveau/dispnv50/core917d.c index 66846f372080..1cd3a2a35dfb 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/core917d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/core917d.c @@ -26,7 +26,7 @@ static const struct nv50_core_func core917d = { .init = core507d_init, .ntfy_init = core507d_ntfy_init, - .caps_init = core507d_caps_init, + .caps_init = core907d_caps_init, .ntfy_wait_done = core507d_ntfy_wait_done, .update = core507d_update, .head = &head917d, diff --git a/drivers/gpu/drm/nouveau/include/nvhw/class/cl507d.h b/drivers/gpu/drm/nouveau/include/nvhw/class/cl507d.h index 2e444bac701d..6a463f308b64 100644 --- a/drivers/gpu/drm/nouveau/include/nvhw/class/cl507d.h +++ b/drivers/gpu/drm/nouveau/include/nvhw/class/cl507d.h @@ -32,7 +32,10 @@ #define NV_DISP_CORE_NOTIFIER_1_COMPLETION_0_DONE_TRUE 0x00000001 #define NV_DISP_CORE_NOTIFIER_1_COMPLETION_0_R0 15:1 #define NV_DISP_CORE_NOTIFIER_1_COMPLETION_0_TIMESTAMP 29:16 - +#define NV_DISP_CORE_NOTIFIER_1_CAPABILITIES_1 0x00000001 +#define NV_DISP_CORE_NOTIFIER_1_CAPABILITIES_1_DONE 0:0 +#define NV_DISP_CORE_NOTIFIER_1_CAPABILITIES_1_DONE_FALSE 0x00000000 +#define NV_DISP_CORE_NOTIFIER_1_CAPABILITIES_1_DONE_TRUE 0x00000001 // class methods #define NV507D_UPDATE (0x00000080) diff --git a/drivers/gpu/drm/nouveau/include/nvhw/class/cl907d.h b/drivers/gpu/drm/nouveau/include/nvhw/class/cl907d.h index 34bc3eafac7d..79aff6ff3138 100644 --- a/drivers/gpu/drm/nouveau/include/nvhw/class/cl907d.h +++ b/drivers/gpu/drm/nouveau/include/nvhw/class/cl907d.h @@ -24,6 +24,10 @@ #ifndef _cl907d_h_ #define _cl907d_h_ +#define NV907D_CORE_NOTIFIER_3_CAPABILITIES_4 0x00000004 +#define NV907D_CORE_NOTIFIER_3_CAPABILITIES_4_DONE 0:0 +#define NV907D_CORE_NOTIFIER_3_CAPABILITIES_4_DONE_FALSE 0x00000000 +#define NV907D_CORE_NOTIFIER_3_CAPABILITIES_4_DONE_TRUE 0x00000001 #define NV907D_CORE_NOTIFIER_3_CAPABILITIES_CAP_SOR0_20 0x00000014 #define NV907D_CORE_NOTIFIER_3_CAPABILITIES_CAP_SOR0_20_SINGLE_LVDS18 0:0 #define NV907D_CORE_NOTIFIER_3_CAPABILITIES_CAP_SOR0_20_SINGLE_LVDS18_FALSE 0x00000000 -- cgit v1.2.3 From 925681454d7b557d404b5d28ef4469fac1b2e105 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Wed, 7 Oct 2020 00:08:09 +0200 Subject: drm/nouveau/gem: fix "refcount_t: underflow; use-after-free" we can't use nouveau_bo_ref here as no ttm object was allocated and nouveau_bo_ref mainly deals with that. Simply deallocate the object. Signed-off-by: Karol Herbst Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 89adadf4706b..549bc67feabb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -190,7 +190,8 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain, * to the caller, instead of a normal nouveau_bo ttm reference. */ ret = drm_gem_object_init(drm->dev, &nvbo->bo.base, size); if (ret) { - nouveau_bo_ref(NULL, &nvbo); + drm_gem_object_release(&nvbo->bo.base); + kfree(nvbo); return ret; } -- cgit v1.2.3 From dcd292c172493067a72672b245a3dd1bcf7268dd Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Tue, 13 Oct 2020 14:01:26 +0200 Subject: drm/nouveau/device: fix changing endianess code to work on older GPUs With this we try to detect if the endianess switch works and assume LE if not. Suggested by Ben. Fixes: 51c05340e407 ("drm/nouveau/device: detect if changing endianness failed") Signed-off-by: Karol Herbst Cc: # v5.8+ Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 39 +++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index dcb70677d0ac..7851bec5f0e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2924,17 +2924,34 @@ nvkm_device_del(struct nvkm_device **pdevice) } } +/* returns true if the GPU is in the CPU native byte order */ static inline bool nvkm_device_endianness(struct nvkm_device *device) { - u32 boot1 = nvkm_rd32(device, 0x000004) & 0x01000001; #ifdef __BIG_ENDIAN - if (!boot1) - return false; + const bool big_endian = true; #else - if (boot1) - return false; + const bool big_endian = false; #endif + + /* Read NV_PMC_BOOT_1, and assume non-functional endian switch if it + * doesn't contain the expected values. + */ + u32 pmc_boot_1 = nvkm_rd32(device, 0x000004); + if (pmc_boot_1 && pmc_boot_1 != 0x01000001) + return !big_endian; /* Assume GPU is LE in this case. */ + + /* 0 means LE and 0x01000001 means BE GPU. Condition is true when + * GPU/CPU endianness don't match. + */ + if (big_endian == !pmc_boot_1) { + nvkm_wr32(device, 0x000004, 0x01000001); + nvkm_rd32(device, 0x000000); + if (nvkm_rd32(device, 0x000004) != (big_endian ? 0x01000001 : 0x00000000)) + return !big_endian; /* Assume GPU is LE on any unexpected read-back. */ + } + + /* CPU/GPU endianness should (hopefully) match. */ return true; } @@ -2987,14 +3004,10 @@ nvkm_device_ctor(const struct nvkm_device_func *func, if (detect) { /* switch mmio to cpu's native endianness */ if (!nvkm_device_endianness(device)) { - nvkm_wr32(device, 0x000004, 0x01000001); - nvkm_rd32(device, 0x000000); - if (!nvkm_device_endianness(device)) { - nvdev_error(device, - "GPU not supported on big-endian\n"); - ret = -ENOSYS; - goto done; - } + nvdev_error(device, + "Couldn't switch GPU to CPUs endianess\n"); + ret = -ENOSYS; + goto done; } boot0 = nvkm_rd32(device, 0x000000); -- cgit v1.2.3 From 2d831155cf0607566e43d8465da33774b2dc7221 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 29 Sep 2020 18:31:31 -0400 Subject: drm/nouveau/kms/nv50-: Get rid of bogus nouveau_conn_mode_valid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville also pointed out that I got a lot of the logic here wrong as well, whoops. While I don't think anyone's likely using 3D output with nouveau, the next patch will make nouveau_conn_mode_valid() make a lot less sense. So, let's just get rid of it and open-code it like before, while taking care to move the 3D frame packing calculations on the dot clock into the right place. Signed-off-by: Lyude Paul Fixes: d6a9efece724 ("drm/nouveau/kms/nv50-: Share DP SST mode_valid() handling with MST") Cc: Ville Syrjälä Cc: # v5.8+ Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 36 ++++++++--------------------- drivers/gpu/drm/nouveau/nouveau_dp.c | 16 +++++++++---- 2 files changed, 21 insertions(+), 31 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 49dd0cbc332f..6f21f36719fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1023,29 +1023,6 @@ get_tmds_link_bandwidth(struct drm_connector *connector) return 112000 * duallink_scale; } -enum drm_mode_status -nouveau_conn_mode_clock_valid(const struct drm_display_mode *mode, - const unsigned min_clock, - const unsigned max_clock, - unsigned int *clock_out) -{ - unsigned int clock = mode->clock; - - if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == - DRM_MODE_FLAG_3D_FRAME_PACKING) - clock *= 2; - - if (clock < min_clock) - return MODE_CLOCK_LOW; - if (clock > max_clock) - return MODE_CLOCK_HIGH; - - if (clock_out) - *clock_out = clock; - - return MODE_OK; -} - static enum drm_mode_status nouveau_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) @@ -1053,7 +1030,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct drm_encoder *encoder = to_drm_encoder(nv_encoder); - unsigned min_clock = 25000, max_clock = min_clock; + unsigned int min_clock = 25000, max_clock = min_clock, clock = mode->clock; switch (nv_encoder->dcb->type) { case DCB_OUTPUT_LVDS: @@ -1082,8 +1059,15 @@ nouveau_connector_mode_valid(struct drm_connector *connector, return MODE_BAD; } - return nouveau_conn_mode_clock_valid(mode, min_clock, max_clock, - NULL); + if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) + clock *= 2; + + if (clock < min_clock) + return MODE_CLOCK_LOW; + if (clock > max_clock) + return MODE_CLOCK_HIGH; + + return MODE_OK; } static struct drm_encoder * diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 7b640e05bd4c..93e3751ad7f1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -232,12 +232,14 @@ nv50_dp_mode_valid(struct drm_connector *connector, unsigned *out_clock) { const unsigned min_clock = 25000; - unsigned max_clock, ds_clock, clock; - enum drm_mode_status ret; + unsigned max_clock, ds_clock, clock = mode->clock; if (mode->flags & DRM_MODE_FLAG_INTERLACE && !outp->caps.dp_interlace) return MODE_NO_INTERLACE; + if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) + clock *= 2; + max_clock = outp->dp.link_nr * outp->dp.link_bw; ds_clock = drm_dp_downstream_max_dotclock(outp->dp.dpcd, outp->dp.downstream_ports); @@ -245,9 +247,13 @@ nv50_dp_mode_valid(struct drm_connector *connector, max_clock = min(max_clock, ds_clock); clock = mode->clock * (connector->display_info.bpc * 3) / 10; - ret = nouveau_conn_mode_clock_valid(mode, min_clock, max_clock, - &clock); + if (clock < min_clock) + return MODE_CLOCK_LOW; + if (clock > max_clock) + return MODE_CLOCK_HIGH; + if (out_clock) *out_clock = clock; - return ret; + + return MODE_OK; } -- cgit v1.2.3 From d7787cc04e0a1f2043264d1550465081096bd065 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 29 Sep 2020 18:31:32 -0400 Subject: drm/nouveau/kms/nv50-: Fix clock checking algorithm in nv50_dp_mode_valid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While I thought I had this correct (since it actually did reject modes like I expected during testing), Ville Syrjala from Intel pointed out that the logic here isn't correct. max_clock refers to the max data rate supported by the DP encoder. So, limiting it to the output of ds_clock (which refers to the maximum dotclock of the downstream DP device) doesn't make any sense. Additionally, since we're using the connector's bpc as the canonical BPC we should use this in mode_valid until we support dynamically setting the bpp based on bandwidth constraints. https://lists.freedesktop.org/archives/dri-devel/2020-September/280276.html For more info. So, let's rewrite this using Ville's advice. v2: * Ville pointed out I mixed up the dotclock and the link rate. So fix that... * ...and also rename all the variables in this function to be more appropriately labeled so I stop mixing them up. * Reuse the bpp from the connector for now until we have dynamic bpp selection. * Use use DIV_ROUND_UP for calculating the mode rate like i915 does, which we should also have been doing from the start Signed-off-by: Lyude Paul Fixes: 409d38139b42 ("drm/nouveau/kms/nv50-: Use downstream DP clock limits for mode validation") Cc: Ville Syrjälä Cc: Lyude Paul Cc: Ben Skeggs Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_dp.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 93e3751ad7f1..040ed88d362d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -231,8 +231,9 @@ nv50_dp_mode_valid(struct drm_connector *connector, const struct drm_display_mode *mode, unsigned *out_clock) { - const unsigned min_clock = 25000; - unsigned max_clock, ds_clock, clock = mode->clock; + const unsigned int min_clock = 25000; + unsigned int max_rate, mode_rate, ds_max_dotclock, clock = mode->clock; + const u8 bpp = connector->display_info.bpc * 3; if (mode->flags & DRM_MODE_FLAG_INTERLACE && !outp->caps.dp_interlace) return MODE_NO_INTERLACE; @@ -240,17 +241,17 @@ nv50_dp_mode_valid(struct drm_connector *connector, if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) clock *= 2; - max_clock = outp->dp.link_nr * outp->dp.link_bw; - ds_clock = drm_dp_downstream_max_dotclock(outp->dp.dpcd, - outp->dp.downstream_ports); - if (ds_clock) - max_clock = min(max_clock, ds_clock); + max_rate = outp->dp.link_nr * outp->dp.link_bw; + mode_rate = DIV_ROUND_UP(clock * bpp, 8); + if (mode_rate > max_rate) + return MODE_CLOCK_HIGH; + + ds_max_dotclock = drm_dp_downstream_max_dotclock(outp->dp.dpcd, outp->dp.downstream_ports); + if (ds_max_dotclock && clock > ds_max_dotclock) + return MODE_CLOCK_HIGH; - clock = mode->clock * (connector->display_info.bpc * 3) / 10; if (clock < min_clock) return MODE_CLOCK_LOW; - if (clock > max_clock) - return MODE_CLOCK_HIGH; if (out_clock) *out_clock = clock; -- cgit v1.2.3