summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2020-10-30 02:54:50 +0300
committerDave Airlie <airlied@redhat.com>2020-10-30 03:38:53 +0300
commita7ece18c5d9cf69a6f0b862365c5c9475d87e2b8 (patch)
treeadcdda7967e66683555591e6f099e0755ab2a9b0 /drivers
parent671d27996feef4afdc2ef47b0721f5cdf400c3b4 (diff)
parentd7787cc04e0a1f2043264d1550465081096bd065 (diff)
downloadlinux-a7ece18c5d9cf69a6f0b862365c5c9475d87e2b8.tar.xz
Merge branch 'linux-5.10' of git://github.com/skeggsb/linux into drm-fixes
Fixes an endian regression on older GPUs, a refcount overflow, a migration fix and 3 display fixes. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Ben Skeggs <skeggsb@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/CACAvsv6MOjtgzKchpis1XrZYmu7-6CaxnHVzJKOXPH62_em7tw@mail.gmail.com
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/core.h2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/core507d.c41
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/core907d.c36
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/core917d.c2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvhw/class/cl507d.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvhw/class/cl907d.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c36
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c31
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_svm.c14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c39
11 files changed, 145 insertions, 68 deletions
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,19 +78,56 @@ 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)
{
struct nvif_push *push = core->chan.push;
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 <nvif/push507c.h>
+#include <nvif/timer.h>
+
+#include <nvhw/class/cl907d.h>
+
+#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
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..040ed88d362d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -231,23 +231,30 @@ 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;
- enum drm_mode_status ret;
+ 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;
- 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);
+ if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
+ clock *= 2;
+
+ 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;
+
+ if (clock < min_clock)
+ return MODE_CLOCK_LOW;
- clock = mode->clock * (connector->display_info.bpc * 3) / 10;
- ret = nouveau_conn_mode_clock_valid(mode, min_clock, max_clock,
- &clock);
if (out_clock)
*out_clock = clock;
- return ret;
+
+ return MODE_OK;
}
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;
}
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;
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);