Discussion:
[PATCH 00/10] nouveau fixes for 3.16-stable
Ben Skeggs
2014-10-21 21:08:50 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

Hey,

The majority of these are regression fixes
- The first 4 patches together fix regressions in runtime pm support.
- The ioremap fix is a long-time regression on some x86 systems with
limited vmalloc space.
- The next three (fb/ltc) are pure fixes, but important ones to the
memory controller setup on Fermi and up.
- The last two are fixes for serious regressions from the display
rework that happened in 3.16

Thanks,
Ben.

Ben Skeggs (10):
drm/nouveau/kms: take more care when pulling down accelerated fbcon
drm/nouveau/kms: restore acceleration before fb_set_suspend() resumes
drm/nouveau: punt fbcon resume out to a workqueue
drm/nouveau: make sure display hardware is reinitialised on runtime
resume
drm/nouveau/bar: behave better if ioremap failed
drm/nvc0-/fb/ram: fix use of non-existant ram if partitions aren't
uniform
drm/nouveau/ltc: fix tag base address getting truncated if above 4GiB
drm/nouveau/ltc: fix cbc issues on certain boards
drm/nv50/disp: fix dpms regression on certain boards
drm/nouveau/bios: memset dcb struct to zero before parsing

drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | 3 +-
drivers/gpu/drm/nouveau/core/subdev/bar/base.c | 14 ++-
drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c | 1 -
drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c | 1 +
drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c | 1 +
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c | 4 +-
drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c | 4 +-
drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c | 2 +
drivers/gpu/drm/nouveau/dispnv04/crtc.c | 4 +-
drivers/gpu/drm/nouveau/nouveau_display.c | 23 +++--
drivers/gpu/drm/nouveau/nouveau_display.h | 5 +-
drivers/gpu/drm/nouveau/nouveau_drm.c | 51 +++--------
drivers/gpu/drm/nouveau/nouveau_fbcon.c | 111 +++++++++++++++--------
drivers/gpu/drm/nouveau/nouveau_fbcon.h | 5 +-
14 files changed, 125 insertions(+), 104 deletions(-)
--
2.1.2
Ben Skeggs
2014-10-21 21:08:51 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

commit 4b5098f3597195e9faf17e5a0cfca905d9a04d9f upstream

Signed-off-by: Ben Skeggs <***@redhat.com>
---
drivers/gpu/drm/nouveau/dispnv04/crtc.c | 4 +-
drivers/gpu/drm/nouveau/nouveau_fbcon.c | 92 ++++++++++++++++++++-------------
drivers/gpu/drm/nouveau/nouveau_fbcon.h | 4 +-
3 files changed, 61 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 41be342..8b17d7d 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -915,9 +915,9 @@ nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
struct drm_device *dev = drm->dev;

if (state == ENTER_ATOMIC_MODE_SET)
- nouveau_fbcon_save_disable_accel(dev);
+ nouveau_fbcon_accel_save_disable(dev);
else
- nouveau_fbcon_restore_accel(dev);
+ nouveau_fbcon_accel_restore(dev);

return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 191665e..02dc2a1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -212,6 +212,58 @@ static struct fb_ops nouveau_fbcon_sw_ops = {
.fb_debug_leave = drm_fb_helper_debug_leave,
};

+void
+nouveau_fbcon_accel_save_disable(struct drm_device *dev)
+{
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ if (drm->fbcon) {
+ drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
+ drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+ }
+}
+
+void
+nouveau_fbcon_accel_restore(struct drm_device *dev)
+{
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ if (drm->fbcon) {
+ drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
+ }
+}
+
+void
+nouveau_fbcon_accel_fini(struct drm_device *dev)
+{
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_fbdev *fbcon = drm->fbcon;
+ if (fbcon && drm->channel) {
+ console_lock();
+ fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
+ console_unlock();
+ nouveau_channel_idle(drm->channel);
+ }
+}
+
+void
+nouveau_fbcon_accel_init(struct drm_device *dev)
+{
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nouveau_fbdev *fbcon = drm->fbcon;
+ struct fb_info *info = fbcon->helper.fbdev;
+ int ret;
+
+ if (nv_device(drm->device)->card_type < NV_50)
+ ret = nv04_fbcon_accel_init(info);
+ else
+ if (nv_device(drm->device)->card_type < NV_C0)
+ ret = nv50_fbcon_accel_init(info);
+ else
+ ret = nvc0_fbcon_accel_init(info);
+
+ if (ret == 0)
+ info->fbops = &nouveau_fbcon_ops;
+}
+
static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno)
{
@@ -357,20 +409,8 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,

mutex_unlock(&dev->struct_mutex);

- if (chan) {
- ret = -ENODEV;
- if (device->card_type < NV_50)
- ret = nv04_fbcon_accel_init(info);
- else
- if (device->card_type < NV_C0)
- ret = nv50_fbcon_accel_init(info);
- else
- ret = nvc0_fbcon_accel_init(info);
-
- if (ret == 0)
- info->fbops = &nouveau_fbcon_ops;
- }
-
+ if (chan)
+ nouveau_fbcon_accel_init(dev);
nouveau_fbcon_zfill(dev, fbcon);

/* To allow resizeing without swapping buffers */
@@ -498,41 +538,23 @@ nouveau_fbcon_fini(struct drm_device *dev)
if (!drm->fbcon)
return;

+ nouveau_fbcon_accel_fini(dev);
nouveau_fbcon_destroy(dev, drm->fbcon);
kfree(drm->fbcon);
drm->fbcon = NULL;
}

void
-nouveau_fbcon_save_disable_accel(struct drm_device *dev)
-{
- struct nouveau_drm *drm = nouveau_drm(dev);
- if (drm->fbcon) {
- drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags;
- drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
- }
-}
-
-void
-nouveau_fbcon_restore_accel(struct drm_device *dev)
-{
- struct nouveau_drm *drm = nouveau_drm(dev);
- if (drm->fbcon) {
- drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags;
- }
-}
-
-void
nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
{
struct nouveau_drm *drm = nouveau_drm(dev);
if (drm->fbcon) {
console_lock();
if (state == 1)
- nouveau_fbcon_save_disable_accel(dev);
+ nouveau_fbcon_accel_save_disable(dev);
fb_set_suspend(drm->fbcon->helper.fbdev, state);
if (state == 0) {
- nouveau_fbcon_restore_accel(dev);
+ nouveau_fbcon_accel_restore(dev);
nouveau_fbcon_zfill(dev, drm->fbcon);
}
console_unlock();
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index fcff797..6d857e2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -61,8 +61,8 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info);
int nouveau_fbcon_init(struct drm_device *dev);
void nouveau_fbcon_fini(struct drm_device *dev);
void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
-void nouveau_fbcon_save_disable_accel(struct drm_device *dev);
-void nouveau_fbcon_restore_accel(struct drm_device *dev);
+void nouveau_fbcon_accel_save_disable(struct drm_device *dev);
+void nouveau_fbcon_accel_restore(struct drm_device *dev);

void nouveau_fbcon_output_poll_changed(struct drm_device *dev);
#endif /* __NV50_FBCON_H__ */
--
2.1.2
Ben Skeggs
2014-10-21 21:08:52 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

commit 04384435fbcd2c5cb70b2e58c8b643822d7e337f upstream.

This *should* be safe these days.

Signed-off-by: Ben Skeggs <***@redhat.com>
---
drivers/gpu/drm/nouveau/nouveau_fbcon.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 02dc2a1..2ef2842 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -550,13 +550,13 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
struct nouveau_drm *drm = nouveau_drm(dev);
if (drm->fbcon) {
console_lock();
- if (state == 1)
- nouveau_fbcon_accel_save_disable(dev);
- fb_set_suspend(drm->fbcon->helper.fbdev, state);
if (state == 0) {
nouveau_fbcon_accel_restore(dev);
nouveau_fbcon_zfill(dev, drm->fbcon);
}
+ fb_set_suspend(drm->fbcon->helper.fbdev, state);
+ if (state == 1)
+ nouveau_fbcon_accel_save_disable(dev);
console_unlock();
}
}
--
2.1.2
Ben Skeggs
2014-10-21 21:08:53 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

commit 634ffcccfbe59d77652804e1beb415d3329b1bc6 upstream

Preparation for some runtime pm fixes. Currently we skip over fbcon
suspend/resume in the runtime path, which causes issues on resume if
fbcon tries to write to the framebuffer before the BAR subdev has
been resumed to restore the BAR1 VM setup.

As we might be woken up via a sysfs connector, we are unable to call
fb_set_suspend() in the resume path as it could make its way down to
a modeset and cause all sorts of locking hilarity.

To solve this, we'll just delay the fbcon resume to a workqueue.

Signed-off-by: Ben Skeggs <***@redhat.com>
---
drivers/gpu/drm/nouveau/nouveau_fbcon.c | 23 +++++++++++++++++------
drivers/gpu/drm/nouveau/nouveau_fbcon.h | 1 +
2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 2ef2842..f636139 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -484,6 +484,16 @@ static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
.fb_probe = nouveau_fbcon_create,
};

+static void
+nouveau_fbcon_set_suspend_work(struct work_struct *work)
+{
+ struct nouveau_fbdev *fbcon = container_of(work, typeof(*fbcon), work);
+ console_lock();
+ nouveau_fbcon_accel_restore(fbcon->dev);
+ nouveau_fbcon_zfill(fbcon->dev, fbcon);
+ fb_set_suspend(fbcon->helper.fbdev, FBINFO_STATE_RUNNING);
+ console_unlock();
+}

int
nouveau_fbcon_init(struct drm_device *dev)
@@ -502,6 +512,7 @@ nouveau_fbcon_init(struct drm_device *dev)
if (!fbcon)
return -ENOMEM;

+ INIT_WORK(&fbcon->work, nouveau_fbcon_set_suspend_work);
fbcon->dev = dev;
drm->fbcon = fbcon;
fbcon->helper.funcs = &nouveau_fbcon_helper_funcs;
@@ -549,14 +560,14 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
{
struct nouveau_drm *drm = nouveau_drm(dev);
if (drm->fbcon) {
- console_lock();
- if (state == 0) {
- nouveau_fbcon_accel_restore(dev);
- nouveau_fbcon_zfill(dev, drm->fbcon);
+ if (state == FBINFO_STATE_RUNNING) {
+ schedule_work(&drm->fbcon->work);
+ return;
}
+ flush_work(&drm->fbcon->work);
+ console_lock();
fb_set_suspend(drm->fbcon->helper.fbdev, state);
- if (state == 1)
- nouveau_fbcon_accel_save_disable(dev);
+ nouveau_fbcon_accel_save_disable(dev);
console_unlock();
}
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index 6d857e2..2c8e846 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -36,6 +36,7 @@ struct nouveau_fbdev {
struct nouveau_framebuffer nouveau_fb;
struct list_head fbdev_list;
struct drm_device *dev;
+ struct work_struct work;
unsigned int saved_flags;
};
--
2.1.2
Ben Skeggs
2014-10-21 21:08:54 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

commit 6fbb702e27d78ad2458df048b58cca3454bc0965 upstream

Linus commit 05c63c2ff23a80b654d6c088ac3ba21628db0173 modified the
runtime suspend/resume paths to skip over display-related tasks to
avoid locking issues on resume.

Unfortunately, this resulted in the display hardware being left in
a partially initialised state, preventing subsequent modesets from
completing.

This commit unifies the (many) suspend/resume paths, bringing back
display (and fbcon) handling in the runtime paths.

Signed-off-by: Ben Skeggs <***@redhat.com>
---
drivers/gpu/drm/nouveau/nouveau_display.c | 23 +++++++-------
drivers/gpu/drm/nouveau/nouveau_display.h | 5 ++-
drivers/gpu/drm/nouveau/nouveau_drm.c | 51 ++++++++-----------------------
3 files changed, 26 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index dd469db..9d44068 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -565,14 +565,12 @@ nouveau_display_destroy(struct drm_device *dev)
}

int
-nouveau_display_suspend(struct drm_device *dev)
+nouveau_display_suspend(struct drm_device *dev, bool runtime)
{
- struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_crtc *crtc;

nouveau_display_fini(dev);

- NV_INFO(drm, "unpinning framebuffer(s)...\n");
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_framebuffer *nouveau_fb;

@@ -594,12 +592,13 @@ nouveau_display_suspend(struct drm_device *dev)
}

void
-nouveau_display_repin(struct drm_device *dev)
+nouveau_display_resume(struct drm_device *dev, bool runtime)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_crtc *crtc;
- int ret;
+ int ret, head;

+ /* re-pin fb/cursors */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_framebuffer *nouveau_fb;

@@ -619,13 +618,6 @@ nouveau_display_repin(struct drm_device *dev)
if (ret)
NV_ERROR(drm, "Could not pin/map cursor.\n");
}
-}
-
-void
-nouveau_display_resume(struct drm_device *dev)
-{
- struct drm_crtc *crtc;
- int head;

nouveau_display_init(dev);

@@ -640,6 +632,13 @@ nouveau_display_resume(struct drm_device *dev)
for (head = 0; head < dev->mode_config.num_crtc; head++)
drm_vblank_on(dev, head);

+ /* This should ensure we don't hit a locking problem when someone
+ * wakes us up via a connector. We should never go into suspend
+ * while the display is on anyways.
+ */
+ if (runtime)
+ return;
+
drm_helper_resume_force_mode(dev);

list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h
index a71cf77..a5195a6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.h
+++ b/drivers/gpu/drm/nouveau/nouveau_display.h
@@ -59,9 +59,8 @@ int nouveau_display_create(struct drm_device *dev);
void nouveau_display_destroy(struct drm_device *dev);
int nouveau_display_init(struct drm_device *dev);
void nouveau_display_fini(struct drm_device *dev);
-int nouveau_display_suspend(struct drm_device *dev);
-void nouveau_display_repin(struct drm_device *dev);
-void nouveau_display_resume(struct drm_device *dev);
+int nouveau_display_suspend(struct drm_device *dev, bool runtime);
+void nouveau_display_resume(struct drm_device *dev, bool runtime);
int nouveau_display_vblank_enable(struct drm_device *, int);
void nouveau_display_vblank_disable(struct drm_device *, int);
int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 594c3f5..0f7adda 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -516,9 +516,11 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
struct nouveau_cli *cli;
int ret;

- if (dev->mode_config.num_crtc && !runtime) {
+ if (dev->mode_config.num_crtc) {
+ NV_INFO(drm, "suspending console...\n");
+ nouveau_fbcon_set_suspend(dev, 1);
NV_INFO(drm, "suspending display...\n");
- ret = nouveau_display_suspend(dev);
+ ret = nouveau_display_suspend(dev, runtime);
if (ret)
return ret;
}
@@ -572,7 +574,7 @@ fail_client:
fail_display:
if (dev->mode_config.num_crtc) {
NV_INFO(drm, "resuming display...\n");
- nouveau_display_resume(dev);
+ nouveau_display_resume(dev, runtime);
}
return ret;
}
@@ -587,9 +589,6 @@ int nouveau_pmops_suspend(struct device *dev)
drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF)
return 0;

- if (drm_dev->mode_config.num_crtc)
- nouveau_fbcon_set_suspend(drm_dev, 1);
-
ret = nouveau_do_suspend(drm_dev, false);
if (ret)
return ret;
@@ -602,7 +601,7 @@ int nouveau_pmops_suspend(struct device *dev)
}

static int
-nouveau_do_resume(struct drm_device *dev)
+nouveau_do_resume(struct drm_device *dev, bool runtime)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_cli *cli;
@@ -627,7 +626,9 @@ nouveau_do_resume(struct drm_device *dev)

if (dev->mode_config.num_crtc) {
NV_INFO(drm, "resuming display...\n");
- nouveau_display_repin(dev);
+ nouveau_display_resume(dev, runtime);
+ NV_INFO(drm, "resuming console...\n");
+ nouveau_fbcon_set_suspend(dev, 0);
}

return 0;
@@ -650,47 +651,21 @@ int nouveau_pmops_resume(struct device *dev)
return ret;
pci_set_master(pdev);

- ret = nouveau_do_resume(drm_dev);
- if (ret)
- return ret;
-
- if (drm_dev->mode_config.num_crtc) {
- nouveau_display_resume(drm_dev);
- nouveau_fbcon_set_suspend(drm_dev, 0);
- }
-
- return 0;
+ return nouveau_do_resume(drm_dev, false);
}

static int nouveau_pmops_freeze(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
- int ret;
-
- if (drm_dev->mode_config.num_crtc)
- nouveau_fbcon_set_suspend(drm_dev, 1);
-
- ret = nouveau_do_suspend(drm_dev, false);
- return ret;
+ return nouveau_do_suspend(drm_dev, false);
}

static int nouveau_pmops_thaw(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
- int ret;
-
- ret = nouveau_do_resume(drm_dev);
- if (ret)
- return ret;
-
- if (drm_dev->mode_config.num_crtc) {
- nouveau_display_resume(drm_dev);
- nouveau_fbcon_set_suspend(drm_dev, 0);
- }
-
- return 0;
+ return nouveau_do_resume(drm_dev, false);
}


@@ -934,7 +909,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev)
return ret;
pci_set_master(pdev);

- ret = nouveau_do_resume(drm_dev);
+ ret = nouveau_do_resume(drm_dev, true);
drm_kms_helper_poll_enable(drm_dev);
/* do magic */
nv_mask(device, 0x88488, (1 << 25), (1 << 25));
--
2.1.2
Ben Skeggs
2014-10-21 21:08:55 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

commit e7d96929a7cd93e146af0d1fd251fa1ec2e3ebf8 upstream

Signed-off-by: Ben Skeggs <***@redhat.com>
---
drivers/gpu/drm/nouveau/core/subdev/bar/base.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c
index 73b1ed2..8bcbdf3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c
@@ -99,8 +99,13 @@ nouveau_bar_alloc(struct nouveau_bar *bar, struct nouveau_object *parent,
struct nouveau_mem *mem, struct nouveau_object **pobject)
{
struct nouveau_object *engine = nv_object(bar);
- return nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass,
- mem, 0, pobject);
+ int ret = -ENOMEM;
+ if (bar->iomem) {
+ ret = nouveau_object_ctor(parent, engine,
+ &nouveau_barobj_oclass,
+ mem, 0, pobject);
+ }
+ return ret;
}

int
@@ -118,9 +123,12 @@ nouveau_bar_create_(struct nouveau_object *parent,
if (ret)
return ret;

- if (nv_device_resource_len(device, 3) != 0)
+ if (nv_device_resource_len(device, 3) != 0) {
bar->iomem = ioremap(nv_device_resource_start(device, 3),
nv_device_resource_len(device, 3));
+ if (!bar->iomem)
+ nv_warn(bar, "PRAMIN ioremap failed\n");
+ }

return 0;
}
--
2.1.2
Ben Skeggs
2014-10-21 21:08:56 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

commit 3d9e3921f4d77bcaeea913c48b894d1208f0cb06 upstream

Likely a large part of the GK106 woes..

Signed-off-by: Ben Skeggs <***@redhat.com>
---
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
index 5a6a502..cd99205 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
@@ -554,13 +554,13 @@ nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
} else {
/* otherwise, address lowest common amount from 0GiB */
ret = nouveau_mm_init(&pfb->vram, rsvd_head,
- (bsize << 8) * parts, 1);
+ (bsize << 8) * parts - rsvd_head, 1);
if (ret)
return ret;

/* and the rest starting from (8GiB + common_size) */
offset = (0x0200000000ULL >> 12) + (bsize << 8);
- length = (ram->size >> 12) - (bsize << 8) - rsvd_tail;
+ length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail;

ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
if (ret)
--
2.1.2
Ben Skeggs
2014-10-21 21:08:57 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

commit 147ed897e807e1a6e2c6fd9dc91830f1d2831d43 upstream

Signed-off-by: Ben Skeggs <***@redhat.com>
---
drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c
index f2f3338a..effe888 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c
@@ -135,7 +135,7 @@ gf100_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct gf100_ltcg_priv *priv)
if (ret) {
priv->num_tags = 0;
} else {
- u64 tag_base = (priv->tag_ram->offset << 12) + tag_margin;
+ u64 tag_base = ((u64)priv->tag_ram->offset << 12) + tag_margin;

tag_base += tag_align - 1;
ret = do_div(tag_base, tag_align);
--
2.1.2
Ben Skeggs
2014-10-21 21:08:58 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

commit fe3d9c4b87bb98222a502cc585844a0b950786fb upstream

A mismatch between FB and LTC's idea of how big a large page is causes
issues such as black "holes" in rendering to occur on some boards
(those where LTC is configured for 64KiB large pages) when compression
is used.

Confirmed to fix at least the GK107 MBP.

Signed-off-by: Ben Skeggs <***@redhat.com>
---
drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c | 1 -
drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c | 1 +
drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c | 2 ++
drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c | 2 ++
4 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
index ca8139b..016ac9a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
@@ -200,7 +200,6 @@ nvc0_bar_init(struct nouveau_object *object)

nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
- nv_mask(priv, 0x100c80, 0x00000001, 0x00000000);

nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12);
if (priv->bar[0].mem)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
index 0670ae3..0a6ca9f 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
@@ -60,6 +60,7 @@ nvc0_fb_init(struct nouveau_object *object)

if (priv->r100c10_page)
nv_wr32(priv, 0x100c10, priv->r100c10 >> 8);
+ nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */
return 0;
}

diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c
index effe888..9454647 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c
@@ -200,6 +200,7 @@ gf100_ltcg_init(struct nouveau_object *object)
{
struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg;
+ u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
int ret;

ret = nouveau_ltcg_init(ltcg);
@@ -211,6 +212,7 @@ gf100_ltcg_init(struct nouveau_object *object)
if (nv_device(ltcg)->card_type >= NV_E0)
nv_wr32(priv, 0x17e000, priv->ltc_nr);
nv_wr32(priv, 0x17e8d4, priv->tag_base);
+ nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
return 0;
}

diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c
index e79d0e8..48ca7a4 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c
@@ -119,6 +119,7 @@ gm107_ltcg_init(struct nouveau_object *object)
{
struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg;
+ u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
int ret;

ret = nouveau_ltcg_init(ltcg);
@@ -127,6 +128,7 @@ gm107_ltcg_init(struct nouveau_object *object)

nv_wr32(priv, 0x17e27c, priv->ltc_nr);
nv_wr32(priv, 0x17e278, priv->tag_base);
+ nv_mask(priv, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
return 0;
}
--
2.1.2
Ben Skeggs
2014-10-21 21:08:59 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

commit 5838ae610ff36777b8fce6f353c2417980c1a1fa upstream

Reported in fdo#82527 comment #2.

Signed-off-by: Ben Skeggs <***@redhat.com>
---
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 2283c44..90b0eb1 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -1570,9 +1570,10 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp
const int or = ffs(outp->or) - 1;
const u32 loff = (or * 0x800) + (link * 0x80);
const u16 mask = (outp->sorconf.link << 6) | outp->or;
+ struct dcb_output match;
u8 ver, hdr;

- if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp))
+ if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match))
nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
}
--
2.1.2
Ben Skeggs
2014-10-21 21:09:00 UTC
Permalink
From: Ben Skeggs <***@redhat.com>

commit 595d373f1e9c9ce0fc946457fdb488e8a58972cd upstream

Fixes type/mask calculation being based on uninitialised data for VGA
outputs.

Signed-off-by: Ben Skeggs <***@redhat.com>
---
drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
index 88606bf..bd8d348 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
@@ -124,6 +124,7 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
struct dcb_output *outp)
{
u16 dcb = dcb_outp(bios, idx, ver, len);
+ memset(outp, 0x00, sizeof(*outp));
if (dcb) {
if (*ver >= 0x20) {
u32 conn = nv_ro32(bios, dcb + 0x00);
--
2.1.2
Loading...