[Nouveau] [PATCH] drm/nouveau: fix early vram corruption originating from vgacon
Marcin Kościelnicki
koriakin at 0x04.net
Thu Oct 4 04:44:13 PDT 2012
On 04.10.2012 13:35, Marcin Slusarz wrote:
> On Thu, Sep 13, 2012 at 12:52:30AM +0200, Marcin Slusarz wrote:
>> There's a short window between module load and fbcon initalization when
>> it's possible for vgacon to write to VGA RAM. Nouveau uses this memory
>> for different purposes, so if we are unlucky, it causes mysterious memory
>> corruptions.
>>
>> For me, booting with nv_printk debug levels set to 5 was enough to trigger it.
>> It manifested as long stream of:
>> "trapped write at ... on channel 0x0001fea0 BAR/PFIFO_WRITE/IN reason:
>> DMAOBJ_LIMIT / PT_NOT_PRESENT / PAGE_SYSTEM_ONLY / PAGE_NOT_PRESENT"
>> which eventually lead to complete hang.
>>
>> Disabling access to VGA memory (through 0x54 PCI config space register) is
>> enough to fix it, but it breaks copying screen data between old and new
>> console (because old data is inaccessible). But blanking console (with
>> entering_gfx==1) is enough to move vgacon screen buffer from VRAM to RAM
>> and let handover to work correctly.
>>
>> Signed-off-by: Marcin Slusarz <marcin.slusarz at gmail.com>
>> ---
>> drivers/gpu/drm/nouveau/nouveau_drm.c | 31 ++++++++++++++++++++++++++++++-
>> 1 file changed, 30 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
>> index 6826525..1641bd9 100644
>> --- a/drivers/gpu/drm/nouveau/nouveau_drm.c
>> +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
>> @@ -25,6 +25,7 @@
>> #include <linux/console.h>
>> #include <linux/module.h>
>> #include <linux/pci.h>
>> +#include <linux/vt_kern.h>
>>
>> #include <core/device.h>
>> #include <core/client.h>
>> @@ -51,6 +52,8 @@
>>
>> #include "nouveau_ttm.h"
>>
>> +#define NV_PCI_VGAMEM_ENABLE 0x54
>> +
>> MODULE_PARM_DESC(config, "option string to pass to driver core");
>> static char *nouveau_config;
>> module_param_named(config, nouveau_config, charp, 0400);
>> @@ -247,9 +250,20 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
>> struct nouveau_drm *drm;
>> int ret;
>>
>> + /* Blank initial console to prevent VRAM corruption while we initialize
>> + * the HW. For vgacon it will move console memory from VGA VRAM to RAM.
>> + */
>> + console_lock();
>> + do_blank_screen(1);
>> + console_unlock();
>> +
>> + /* Completely disable access to VGA IO/memory, just to be sure no one
>> + * will change it. */
>> + pci_write_config_byte(pdev, NV_PCI_VGAMEM_ENABLE, 0);
>> +
>> ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
>> if (ret)
>> - return ret;
>> + goto fail_cli;
>>
>> dev->dev_private = drm;
>> drm->dev = dev;
>> @@ -336,6 +350,11 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
>>
>> nouveau_accel_init(drm);
>> nouveau_fbcon_init(dev);
>> +
>> + console_lock();
>> + do_unblank_screen(1);
>> + console_unlock();
>> +
>> return 0;
>>
>> fail_dispinit:
>> @@ -351,12 +370,20 @@ fail_ttm:
>> nouveau_vga_fini(drm);
>> fail_device:
>> nouveau_cli_destroy(&drm->client);
>> +fail_cli:
>> + pci_write_config_byte(pdev, NV_PCI_VGAMEM_ENABLE, 1);
This (and corresponding unload line) is a bug: you should NOT blindly
set this register to 1 on unload, use its previous value instead.
Otherwise you can get into sticky situations involving two GPUs
responding to VGA address space. Better yet, think up a proper solution
involving vga arb.
>> +
>> + console_lock();
>> + do_unblank_screen(1);
>> + console_unlock();
>> +
>> return ret;
>> }
>>
>> static int
>> nouveau_drm_unload(struct drm_device *dev)
>> {
>> + struct pci_dev *pdev = dev->pdev;
>> struct nouveau_drm *drm = nouveau_drm(dev);
>>
>> nouveau_fbcon_fini(dev);
>> @@ -375,6 +402,8 @@ nouveau_drm_unload(struct drm_device *dev)
>> nouveau_vga_fini(drm);
>>
>> nouveau_cli_destroy(&drm->client);
>> +
>> + pci_write_config_byte(pdev, NV_PCI_VGAMEM_ENABLE, 1);
>> return 0;
>> }
>>
>> --
>
> What's up with this patch?
>
> _______________________________________________
> Nouveau mailing list
> Nouveau at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/nouveau
>
More information about the Nouveau
mailing list