drm/nv50: fix iommu errors caused by device reading from address 0
[safe/jmp/linux-2.6] / drivers / gpu / drm / nouveau / nouveau_drv.c
index 30cc09e..2737704 100644 (file)
@@ -83,6 +83,14 @@ MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
 int nouveau_nofbaccel = 0;
 module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
 
+MODULE_PARM_DESC(override_conntype, "Ignore DCB connector type");
+int nouveau_override_conntype = 0;
+module_param_named(override_conntype, nouveau_override_conntype, int, 0400);
+
+MODULE_PARM_DESC(tv_disable, "Disable TV-out detection\n");
+int nouveau_tv_disable = 0;
+module_param_named(tv_disable, nouveau_tv_disable, int, 0400);
+
 MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
                 "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n"
                 "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n"
@@ -145,7 +153,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_channel *chan;
        struct drm_crtc *crtc;
-       uint32_t fbdev_flags;
        int ret, i;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -154,9 +161,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
        if (pm_state.event == PM_EVENT_PRETHAW)
                return 0;
 
-       fbdev_flags = dev_priv->fbdev_info->flags;
-       dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
+       NV_INFO(dev, "Disabling fbcon acceleration...\n");
+       nouveau_fbcon_save_disable_accel(dev);
 
+       NV_INFO(dev, "Unpinning framebuffer(s)...\n");
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_framebuffer *nouveau_fb;
 
@@ -167,6 +175,13 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
                nouveau_bo_unpin(nouveau_fb->nvbo);
        }
 
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+
+               nouveau_bo_unmap(nv_crtc->cursor.nvbo);
+               nouveau_bo_unpin(nv_crtc->cursor.nvbo);
+       }
+
        NV_INFO(dev, "Evicting buffers...\n");
        ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
 
@@ -220,9 +235,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
        }
 
        acquire_console_sem();
-       fb_set_suspend(dev_priv->fbdev_info, 1);
+       nouveau_fbcon_set_suspend(dev, 1);
        release_console_sem();
-       dev_priv->fbdev_info->flags = fbdev_flags;
+       nouveau_fbcon_restore_accel(dev);
        return 0;
 
 out_abort:
@@ -240,14 +255,12 @@ nouveau_pci_resume(struct pci_dev *pdev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->engine;
        struct drm_crtc *crtc;
-       uint32_t fbdev_flags;
        int ret, i;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -ENODEV;
 
-       fbdev_flags = dev_priv->fbdev_info->flags;
-       dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
+       nouveau_fbcon_save_disable_accel(dev);
 
        NV_INFO(dev, "We're back, enabling device...\n");
        pci_set_power_state(pdev, PCI_D0);
@@ -308,12 +321,34 @@ nouveau_pci_resume(struct pci_dev *pdev)
                nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
        }
 
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+               int ret;
+
+               ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
+               if (!ret)
+                       ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
+               if (ret)
+                       NV_ERROR(dev, "Could not pin/map cursor.\n");
+       }
+
        if (dev_priv->card_type < NV_50) {
                nv04_display_restore(dev);
                NVLockVgaCrtcs(dev, false);
        } else
                nv50_display_init(dev);
 
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+
+               nv_crtc->cursor.set_offset(nv_crtc,
+                                       nv_crtc->cursor.nvbo->bo.offset -
+                                       dev_priv->vm_vram_base);
+
+               nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
+                       nv_crtc->cursor_saved_y);
+       }
+
        /* Force CLUT to get re-loaded during modeset */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
@@ -322,13 +357,14 @@ nouveau_pci_resume(struct pci_dev *pdev)
        }
 
        acquire_console_sem();
-       fb_set_suspend(dev_priv->fbdev_info, 0);
+       nouveau_fbcon_set_suspend(dev, 0);
        release_console_sem();
 
-       nouveau_fbcon_zfill(dev);
+       nouveau_fbcon_zfill_all(dev);
 
        drm_helper_resume_force_mode(dev);
-       dev_priv->fbdev_info->flags = fbdev_flags;
+
+       nouveau_fbcon_restore_accel(dev);
        return 0;
 }