drm/i915: restore only the mode of this driver on lastclose (v2)
[linux-flexiantxendom0-natty.git] / drivers / gpu / drm / i915 / i915_dma.c
index 7960fd6..8159020 100644 (file)
@@ -34,6 +34,7 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 #include "i915_trace.h"
+#include "../../../platform/x86/intel_ips.h"
 #include <linux/pci.h>
 #include <linux/vgaarb.h>
 #include <linux/acpi.h>
@@ -49,6 +50,8 @@
 static int i915_init_phys_hws(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring = LP_RING(dev_priv);
+
        /* Program Hardware Status Page */
        dev_priv->status_page_dmah =
                drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE);
@@ -57,11 +60,10 @@ static int i915_init_phys_hws(struct drm_device *dev)
                DRM_ERROR("Can not allocate hardware status page\n");
                return -ENOMEM;
        }
-       dev_priv->render_ring.status_page.page_addr
-               = dev_priv->status_page_dmah->vaddr;
+       ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
        dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
 
-       memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE);
+       memset(ring->status_page.page_addr, 0, PAGE_SIZE);
 
        if (INTEL_INFO(dev)->gen >= 4)
                dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
@@ -79,13 +81,15 @@ static int i915_init_phys_hws(struct drm_device *dev)
 static void i915_free_hws(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring = LP_RING(dev_priv);
+
        if (dev_priv->status_page_dmah) {
                drm_pci_free(dev, dev_priv->status_page_dmah);
                dev_priv->status_page_dmah = NULL;
        }
 
-       if (dev_priv->render_ring.status_page.gfx_addr) {
-               dev_priv->render_ring.status_page.gfx_addr = 0;
+       if (ring->status_page.gfx_addr) {
+               ring->status_page.gfx_addr = 0;
                drm_core_ioremapfree(&dev_priv->hws_map, dev);
        }
 
@@ -97,7 +101,7 @@ void i915_kernel_lost_context(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv;
-       struct intel_ring_buffer *ring = &dev_priv->render_ring;
+       struct intel_ring_buffer *ring = LP_RING(dev_priv);
 
        /*
         * We should never lose context on the ring with modesetting
@@ -123,6 +127,8 @@ void i915_kernel_lost_context(struct drm_device * dev)
 static int i915_dma_cleanup(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       int i;
+
        /* Make sure interrupts are disabled here because the uninstall ioctl
         * may not have been called from userspace and after dev_private
         * is freed, it's too late.
@@ -131,9 +137,8 @@ static int i915_dma_cleanup(struct drm_device * dev)
                drm_irq_uninstall(dev);
 
        mutex_lock(&dev->struct_mutex);
-       intel_cleanup_ring_buffer(&dev_priv->render_ring);
-       intel_cleanup_ring_buffer(&dev_priv->bsd_ring);
-       intel_cleanup_ring_buffer(&dev_priv->blt_ring);
+       for (i = 0; i < I915_NUM_RINGS; i++)
+               intel_cleanup_ring_buffer(&dev_priv->ring[i]);
        mutex_unlock(&dev->struct_mutex);
 
        /* Clear the HWS virtual address at teardown */
@@ -147,6 +152,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+       int ret;
 
        master_priv->sarea = drm_getsarea(dev);
        if (master_priv->sarea) {
@@ -157,33 +163,22 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
        }
 
        if (init->ring_size != 0) {
-               if (dev_priv->render_ring.obj != NULL) {
+               if (LP_RING(dev_priv)->obj != NULL) {
                        i915_dma_cleanup(dev);
                        DRM_ERROR("Client tried to initialize ringbuffer in "
                                  "GEM mode\n");
                        return -EINVAL;
                }
 
-               dev_priv->render_ring.size = init->ring_size;
-
-               dev_priv->render_ring.map.offset = init->ring_start;
-               dev_priv->render_ring.map.size = init->ring_size;
-               dev_priv->render_ring.map.type = 0;
-               dev_priv->render_ring.map.flags = 0;
-               dev_priv->render_ring.map.mtrr = 0;
-
-               drm_core_ioremap_wc(&dev_priv->render_ring.map, dev);
-
-               if (dev_priv->render_ring.map.handle == NULL) {
+               ret = intel_render_ring_init_dri(dev,
+                                                init->ring_start,
+                                                init->ring_size);
+               if (ret) {
                        i915_dma_cleanup(dev);
-                       DRM_ERROR("can not ioremap virtual address for"
-                                 " ring buffer\n");
-                       return -ENOMEM;
+                       return ret;
                }
        }
 
-       dev_priv->render_ring.virtual_start = dev_priv->render_ring.map.handle;
-
        dev_priv->cpp = init->cpp;
        dev_priv->back_offset = init->back_offset;
        dev_priv->front_offset = init->front_offset;
@@ -201,12 +196,10 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
 static int i915_dma_resume(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct intel_ring_buffer *ring = LP_RING(dev_priv);
 
-       struct intel_ring_buffer *ring;
        DRM_DEBUG_DRIVER("%s\n", __func__);
 
-       ring = &dev_priv->render_ring;
-
        if (ring->map.handle == NULL) {
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
@@ -326,7 +319,7 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
        drm_i915_private_t *dev_priv = dev->dev_private;
        int i, ret;
 
-       if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8)
+       if ((dwords+1) * sizeof(int) >= LP_RING(dev_priv)->size - 8)
                return -EINVAL;
 
        for (i = 0; i < dwords;) {
@@ -352,16 +345,16 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
 
 int
 i915_emit_box(struct drm_device *dev,
-             struct drm_clip_rect *boxes,
-             int i, int DR1, int DR4)
+             struct drm_clip_rect *box,
+             int DR1, int DR4)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_clip_rect box = boxes[i];
        int ret;
 
-       if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
+       if (box->y2 <= box->y1 || box->x2 <= box->x1 ||
+           box->y2 <= 0 || box->x2 <= 0) {
                DRM_ERROR("Bad box %d,%d..%d,%d\n",
-                         box.x1, box.y1, box.x2, box.y2);
+                         box->x1, box->y1, box->x2, box->y2);
                return -EINVAL;
        }
 
@@ -371,8 +364,8 @@ i915_emit_box(struct drm_device *dev,
                        return ret;
 
                OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
-               OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
-               OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+               OUT_RING((box->x1 & 0xffff) | (box->y1 << 16));
+               OUT_RING(((box->x2 - 1) & 0xffff) | ((box->y2 - 1) << 16));
                OUT_RING(DR4);
        } else {
                ret = BEGIN_LP_RING(6);
@@ -381,8 +374,8 @@ i915_emit_box(struct drm_device *dev,
 
                OUT_RING(GFX_OP_DRAWRECT_INFO);
                OUT_RING(DR1);
-               OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
-               OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+               OUT_RING((box->x1 & 0xffff) | (box->y1 << 16));
+               OUT_RING(((box->x2 - 1) & 0xffff) | ((box->y2 - 1) << 16));
                OUT_RING(DR4);
                OUT_RING(0);
        }
@@ -434,7 +427,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
 
        for (i = 0; i < count; i++) {
                if (i < nbox) {
-                       ret = i915_emit_box(dev, cliprects, i,
+                       ret = i915_emit_box(dev, &cliprects[i],
                                            cmd->DR1, cmd->DR4);
                        if (ret)
                                return ret;
@@ -467,7 +460,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
        count = nbox ? nbox : 1;
        for (i = 0; i < count; i++) {
                if (i < nbox) {
-                       ret = i915_emit_box(dev, cliprects, i,
+                       ret = i915_emit_box(dev, &cliprects[i],
                                            batch->DR1, batch->DR4);
                        if (ret)
                                return ret;
@@ -565,13 +558,12 @@ static int i915_dispatch_flip(struct drm_device * dev)
        return 0;
 }
 
-static int i915_quiescent(struct drm_device * dev)
+static int i915_quiescent(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring = LP_RING(dev->dev_private);
 
        i915_kernel_lost_context(dev);
-       return intel_wait_ring_buffer(&dev_priv->render_ring,
-                                     dev_priv->render_ring.size - 8);
+       return intel_wait_ring_buffer(ring, ring->size - 8);
 }
 
 static int i915_flush_ioctl(struct drm_device *dev, void *data,
@@ -773,6 +765,12 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_HAS_RELAXED_FENCING:
                value = 1;
                break;
+       case I915_PARAM_HAS_COHERENT_RINGS:
+               value = 1;
+               break;
+       case I915_PARAM_HAS_EXEC_CONSTANTS:
+               value = INTEL_INFO(dev)->gen >= 4;
+               break;
        default:
                DRM_DEBUG_DRIVER("Unknown parameter %d\n",
                                 param->param);
@@ -828,7 +826,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        drm_i915_hws_addr_t *hws = data;
-       struct intel_ring_buffer *ring = &dev_priv->render_ring;
+       struct intel_ring_buffer *ring = LP_RING(dev_priv);
 
        if (!I915_NEED_GFX_HWS(dev))
                return -EINVAL;
@@ -1073,7 +1071,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
        if (!cfb_base)
                goto err_fb;
 
-       if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) {
+       if (!(IS_GM45(dev) || HAS_PCH_SPLIT(dev))) {
                compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen,
                                                    4096, 4096, 0);
                if (compressed_llb)
@@ -1091,7 +1089,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
 
        intel_disable_fbc(dev);
        dev_priv->compressed_fb = compressed_fb;
-       if (IS_IRONLAKE_M(dev))
+       if (HAS_PCH_SPLIT(dev))
                I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
        else if (IS_GM45(dev)) {
                I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
@@ -1142,12 +1140,16 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
        pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
        if (state == VGA_SWITCHEROO_ON) {
                printk(KERN_INFO "i915: switched on\n");
+               dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
                /* i915 resume handler doesn't set to D0 */
                pci_set_power_state(dev->pdev, PCI_D0);
                i915_resume(dev);
+               dev->switch_power_state = DRM_SWITCH_POWER_ON;
        } else {
                printk(KERN_ERR "i915: switched off\n");
+               dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
                i915_suspend(dev, pmm);
+               dev->switch_power_state = DRM_SWITCH_POWER_OFF;
        }
 }
 
@@ -1213,15 +1215,22 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                DRM_INFO("failed to find VBIOS tables\n");
 
-       /* if we have > 1 VGA cards, then disable the radeon VGA resources */
+       /* If we have > 1 VGA cards, then we need to arbitrate access
+        * to the common VGA resources.
+        *
+        * If we are a secondary display controller (!PCI_DISPLAY_CLASS_VGA),
+        * then we do not take part in VGA arbitration and the
+        * vga_client_register() fails with -ENODEV.
+        */
        ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
-       if (ret)
+       if (ret && ret != -ENODEV)
                goto cleanup_ringbuffer;
 
        intel_register_dsm_handler();
 
        ret = vga_switcheroo_register_client(dev->pdev,
                                             i915_switcheroo_set_state,
+                                            NULL,
                                             i915_switcheroo_can_switch);
        if (ret)
                goto cleanup_vga_client;
@@ -1826,6 +1835,26 @@ out_unlock:
 EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
 
 /**
+ * Tells the intel_ips driver that the i915 driver is now loaded, if
+ * IPS got loaded first.
+ *
+ * This awkward dance is so that neither module has to depend on the
+ * other in order for IPS to do the appropriate communication of
+ * GPU turbo limits to i915.
+ */
+static void
+ips_ping_for_i915_load(void)
+{
+       void (*link)(void);
+
+       link = symbol_get(ips_link_to_i915_driver);
+       if (link) {
+               link();
+               symbol_put(ips_link_to_i915_driver);
+       }
+}
+
+/**
  * i915_driver_load - setup chip and create an initial config
  * @dev: DRM device
  * @flags: startup flags
@@ -1866,6 +1895,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (IS_GEN2(dev))
                dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
 
+       /* 965GM sometimes incorrectly writes to hardware status page (HWS)
+        * using 32bit addressing, overwriting memory if HWS is located
+        * above 4GB.
+        *
+        * The documentation also mentions an issue with undefined
+        * behaviour if any general state is accessed within a page above 4GB,
+        * which also needs to be handled carefully.
+        */
+       if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
+               dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
+
        mmio_bar = IS_GEN2(dev) ? 1 : 0;
        dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, 0);
        if (!dev_priv->regs) {
@@ -1928,13 +1968,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        /* enable GEM by default */
        dev_priv->has_gem = 1;
 
-       if (dev_priv->has_gem == 0 &&
-           drm_core_check_feature(dev, DRIVER_MODESET)) {
-               DRM_ERROR("kernel modesetting requires GEM, disabling driver.\n");
-               ret = -ENODEV;
-               goto out_workqueue_free;
-       }
-
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
        if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
@@ -1978,7 +2011,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (!IS_I945G(dev) && !IS_I945GM(dev))
                pci_enable_msi(dev->pdev);
 
-       spin_lock_init(&dev_priv->user_irq_lock);
+       spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->error_lock);
        dev_priv->trace_irq_seqno = 0;
 
@@ -2011,6 +2044,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev_priv->mchdev_lock = &mchdev_lock;
        spin_unlock(&mchdev_lock);
 
+       ips_ping_for_i915_load();
+
        return 0;
 
 out_gem_unload:
@@ -2019,7 +2054,6 @@ out_gem_unload:
 
        intel_teardown_gmbus(dev);
        intel_teardown_mchbar(dev);
-out_workqueue_free:
        destroy_workqueue(dev_priv->wq);
 out_iomapfree:
        io_mapping_free(dev_priv->mm.gtt_mapping);
@@ -2157,7 +2191,7 @@ void i915_driver_lastclose(struct drm_device * dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
-               drm_fb_helper_restore();
+               intel_fb_restore_mode(dev);
                vga_switcheroo_process_delayed_switch();
                return;
        }