Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 3 Jun 2010 14:19:45 +0000 (07:19 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 3 Jun 2010 14:19:45 +0000 (07:19 -0700)
* 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (41 commits)
  drm/radeon/kms: make sure display hw is disabled when suspending
  drm/vmwgfx: Allow userspace to change default layout. Bump minor.
  drm/vmwgfx: Fix framebuffer modesetting
  drm/vmwgfx: Fix vga save / restore with display topology.
  vgaarb: use MIT license
  vgaarb: convert pr_devel() to pr_debug()
  drm: fix typos in Linux DRM Developer's Guide
  drm/radeon/kms/pm: voltage fixes
  drm/radeon/kms/pm: radeon_set_power_state fixes
  drm/radeon/kms/pm: patch default power state with default clocks/voltages on r6xx+
  drm/radeon/kms/pm: enable SetVoltage on r7xx/evergreen
  drm/radeon/kms/pm: add support for SetVoltage cmd table (V2)
  drm/radeon/kms/evergreen: add initial CS parser
  drm/kms: disable/enable poll around switcheroo on/off
  drm/nouveau: fixup confusion over which handle the DSM is hanging off.
  drm/nouveau: attempt to get bios from ACPI v3
  drm/nv50: cast IGP memory location to u64 before shifting
  drm/ttm: Fix ttm_page_alloc.c
  drm/ttm: Fix cached TTM page allocation.
  drm/vmwgfx: Remove some leftover debug messages.
  ...

1  2 
drivers/gpu/drm/i915/i915_dma.c

  #include <linux/vga_switcheroo.h>
  #include <linux/slab.h>
  
 -/* Really want an OS-independent resettable timer.  Would like to have
 - * this loop run for (eg) 3 sec, but have the timer reset every time
 - * the head pointer changes, so that EBUSY only happens if the ring
 - * actually stalls for (eg) 3 seconds.
 - */
 -int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
 -{
 -      drm_i915_private_t *dev_priv = dev->dev_private;
 -      drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
 -      u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
 -      u32 last_acthd = I915_READ(acthd_reg);
 -      u32 acthd;
 -      u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
 -      int i;
 -
 -      trace_i915_ring_wait_begin (dev);
 -
 -      for (i = 0; i < 100000; i++) {
 -              ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
 -              acthd = I915_READ(acthd_reg);
 -              ring->space = ring->head - (ring->tail + 8);
 -              if (ring->space < 0)
 -                      ring->space += ring->Size;
 -              if (ring->space >= n) {
 -                      trace_i915_ring_wait_end (dev);
 -                      return 0;
 -              }
 -
 -              if (dev->primary->master) {
 -                      struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
 -                      if (master_priv->sarea_priv)
 -                              master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
 -              }
 -
 -
 -              if (ring->head != last_head)
 -                      i = 0;
 -              if (acthd != last_acthd)
 -                      i = 0;
 -
 -              last_head = ring->head;
 -              last_acthd = acthd;
 -              msleep_interruptible(10);
 -
 -      }
 -
 -      trace_i915_ring_wait_end (dev);
 -      return -EBUSY;
 -}
 -
 -/* As a ringbuffer is only allowed to wrap between instructions, fill
 - * the tail with NOOPs.
 - */
 -int i915_wrap_ring(struct drm_device *dev)
 -{
 -      drm_i915_private_t *dev_priv = dev->dev_private;
 -      volatile unsigned int *virt;
 -      int rem;
 -
 -      rem = dev_priv->ring.Size - dev_priv->ring.tail;
 -      if (dev_priv->ring.space < rem) {
 -              int ret = i915_wait_ring(dev, rem, __func__);
 -              if (ret)
 -                      return ret;
 -      }
 -      dev_priv->ring.space -= rem;
 -
 -      virt = (unsigned int *)
 -              (dev_priv->ring.virtual_start + dev_priv->ring.tail);
 -      rem /= 4;
 -      while (rem--)
 -              *virt++ = MI_NOOP;
 -
 -      dev_priv->ring.tail = 0;
 -
 -      return 0;
 -}
 -
  /**
   * Sets up the hardware status page for devices that need a physical address
   * in the register.
@@@ -55,11 -133,10 +55,11 @@@ static int i915_init_phys_hws(struct dr
                DRM_ERROR("Can not allocate hardware status page\n");
                return -ENOMEM;
        }
 -      dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
 +      dev_priv->render_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->hw_status_page, 0, PAGE_SIZE);
 +      memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE);
  
        if (IS_I965G(dev))
                dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
@@@ -82,8 -159,8 +82,8 @@@ static void i915_free_hws(struct drm_de
                dev_priv->status_page_dmah = NULL;
        }
  
 -      if (dev_priv->status_gfx_addr) {
 -              dev_priv->status_gfx_addr = 0;
 +      if (dev_priv->render_ring.status_page.gfx_addr) {
 +              dev_priv->render_ring.status_page.gfx_addr = 0;
                drm_core_ioremapfree(&dev_priv->hws_map, dev);
        }
  
@@@ -95,7 -172,7 +95,7 @@@ void i915_kernel_lost_context(struct dr
  {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv;
 -      drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
 +      struct intel_ring_buffer *ring = &dev_priv->render_ring;
  
        /*
         * We should never lose context on the ring with modesetting
        ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
        ring->space = ring->head - (ring->tail + 8);
        if (ring->space < 0)
 -              ring->space += ring->Size;
 +              ring->space += ring->size;
  
        if (!dev->primary->master)
                return;
@@@ -128,9 -205,12 +128,9 @@@ static int i915_dma_cleanup(struct drm_
        if (dev->irq_enabled)
                drm_irq_uninstall(dev);
  
 -      if (dev_priv->ring.virtual_start) {
 -              drm_core_ioremapfree(&dev_priv->ring.map, dev);
 -              dev_priv->ring.virtual_start = NULL;
 -              dev_priv->ring.map.handle = NULL;
 -              dev_priv->ring.map.size = 0;
 -      }
 +      intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
 +      if (HAS_BSD(dev))
 +              intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
  
        /* Clear the HWS virtual address at teardown */
        if (I915_NEED_GFX_HWS(dev))
@@@ -153,24 -233,24 +153,24 @@@ static int i915_initialize(struct drm_d
        }
  
        if (init->ring_size != 0) {
 -              if (dev_priv->ring.ring_obj != NULL) {
 +              if (dev_priv->render_ring.gem_object != NULL) {
                        i915_dma_cleanup(dev);
                        DRM_ERROR("Client tried to initialize ringbuffer in "
                                  "GEM mode\n");
                        return -EINVAL;
                }
  
 -              dev_priv->ring.Size = init->ring_size;
 +              dev_priv->render_ring.size = init->ring_size;
  
 -              dev_priv->ring.map.offset = init->ring_start;
 -              dev_priv->ring.map.size = init->ring_size;
 -              dev_priv->ring.map.type = 0;
 -              dev_priv->ring.map.flags = 0;
 -              dev_priv->ring.map.mtrr = 0;
 +              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->ring.map, dev);
 +              drm_core_ioremap_wc(&dev_priv->render_ring.map, dev);
  
 -              if (dev_priv->ring.map.handle == NULL) {
 +              if (dev_priv->render_ring.map.handle == NULL) {
                        i915_dma_cleanup(dev);
                        DRM_ERROR("can not ioremap virtual address for"
                                  " ring buffer\n");
                }
        }
  
 -      dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
 +      dev_priv->render_ring.virtual_start = dev_priv->render_ring.map.handle;
  
        dev_priv->cpp = init->cpp;
        dev_priv->back_offset = init->back_offset;
@@@ -198,29 -278,26 +198,29 @@@ static int i915_dma_resume(struct drm_d
  {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
  
 +      struct intel_ring_buffer *ring;
        DRM_DEBUG_DRIVER("%s\n", __func__);
  
 -      if (dev_priv->ring.map.handle == NULL) {
 +      ring = &dev_priv->render_ring;
 +
 +      if (ring->map.handle == NULL) {
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
                return -ENOMEM;
        }
  
        /* Program Hardware Status Page */
 -      if (!dev_priv->hw_status_page) {
 +      if (!ring->status_page.page_addr) {
                DRM_ERROR("Can not find hardware status page\n");
                return -EINVAL;
        }
        DRM_DEBUG_DRIVER("hw status page @ %p\n",
 -                              dev_priv->hw_status_page);
 -
 -      if (dev_priv->status_gfx_addr != 0)
 -              I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
 +                              ring->status_page.page_addr);
 +      if (ring->status_page.gfx_addr != 0)
 +              ring->setup_status_page(dev, ring);
        else
                I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
 +
        DRM_DEBUG_DRIVER("Enabled hardware status page\n");
  
        return 0;
@@@ -330,8 -407,9 +330,8 @@@ static int i915_emit_cmds(struct drm_de
  {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int i;
 -      RING_LOCALS;
  
 -      if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
 +      if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8)
                return -EINVAL;
  
        BEGIN_LP_RING((dwords+1)&~1);
@@@ -364,7 -442,9 +364,7 @@@ i915_emit_box(struct drm_device *dev
              struct drm_clip_rect *boxes,
              int i, int DR1, int DR4)
  {
 -      drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_clip_rect box = boxes[i];
 -      RING_LOCALS;
  
        if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
                DRM_ERROR("Bad box %d,%d..%d,%d\n",
@@@ -401,6 -481,7 +401,6 @@@ static void i915_emit_breadcrumb(struc
  {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
 -      RING_LOCALS;
  
        dev_priv->counter++;
        if (dev_priv->counter > 0x7FFFFFFFUL)
@@@ -454,8 -535,10 +454,8 @@@ static int i915_dispatch_batchbuffer(st
                                     drm_i915_batchbuffer_t * batch,
                                     struct drm_clip_rect *cliprects)
  {
 -      drm_i915_private_t *dev_priv = dev->dev_private;
        int nbox = batch->num_cliprects;
        int i = 0, count;
 -      RING_LOCALS;
  
        if ((batch->start | batch->used) & 0x7) {
                DRM_ERROR("alignment");
@@@ -504,6 -587,7 +504,6 @@@ static int i915_dispatch_flip(struct dr
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv =
                dev->primary->master->driver_priv;
 -      RING_LOCALS;
  
        if (!master_priv->sarea_priv)
                return -EINVAL;
@@@ -556,8 -640,7 +556,8 @@@ static int i915_quiescent(struct drm_de
        drm_i915_private_t *dev_priv = dev->dev_private;
  
        i915_kernel_lost_context(dev);
 -      return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
 +      return intel_wait_ring_buffer(dev, &dev_priv->render_ring,
 +                                    dev_priv->render_ring.size - 8);
  }
  
  static int i915_flush_ioctl(struct drm_device *dev, void *data,
@@@ -744,9 -827,6 +744,9 @@@ static int i915_getparam(struct drm_dev
                /* depends on GEM */
                value = dev_priv->has_gem;
                break;
 +      case I915_PARAM_HAS_BSD:
 +              value = HAS_BSD(dev);
 +              break;
        default:
                DRM_DEBUG_DRIVER("Unknown parameter %d\n",
                                 param->param);
@@@ -802,7 -882,6 +802,7 @@@ static int i915_set_status_page(struct 
  {
        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;
  
        if (!I915_NEED_GFX_HWS(dev))
                return -EINVAL;
  
        DRM_DEBUG_DRIVER("set status page addr 0x%08x\n", (u32)hws->addr);
  
 -      dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
 +      ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12);
  
        dev_priv->hws_map.offset = dev->agp->base + hws->addr;
        dev_priv->hws_map.size = 4*1024;
        drm_core_ioremap_wc(&dev_priv->hws_map, dev);
        if (dev_priv->hws_map.handle == NULL) {
                i915_dma_cleanup(dev);
 -              dev_priv->status_gfx_addr = 0;
 +              ring->status_page.gfx_addr = 0;
                DRM_ERROR("can not ioremap virtual address for"
                                " G33 hw status page\n");
                return -ENOMEM;
        }
 -      dev_priv->hw_status_page = dev_priv->hws_map.handle;
 +      ring->status_page.page_addr = dev_priv->hws_map.handle;
 +      memset(ring->status_page.page_addr, 0, PAGE_SIZE);
 +      I915_WRITE(HWS_PGA, ring->status_page.gfx_addr);
  
 -      memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
 -      I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
        DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n",
 -                              dev_priv->status_gfx_addr);
 +                       ring->status_page.gfx_addr);
        DRM_DEBUG_DRIVER("load hws at %p\n",
 -                              dev_priv->hw_status_page);
 +                       ring->status_page.page_addr);
        return 0;
  }
  
@@@ -1320,12 -1399,14 +1320,14 @@@ static void i915_switcheroo_set_state(s
        struct drm_device *dev = pci_get_drvdata(pdev);
        pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
        if (state == VGA_SWITCHEROO_ON) {
-               printk(KERN_INFO "i915: switched off\n");
+               printk(KERN_INFO "i915: switched on\n");
                /* i915 resume handler doesn't set to D0 */
                pci_set_power_state(dev->pdev, PCI_D0);
                i915_resume(dev);
+               drm_kms_helper_poll_enable(dev);
        } else {
                printk(KERN_ERR "i915: switched off\n");
+               drm_kms_helper_poll_disable(dev);
                i915_suspend(dev, pmm);
        }
  }
@@@ -1460,11 -1541,14 +1462,11 @@@ void i915_master_destroy(struct drm_dev
        master->driver_priv = NULL;
  }
  
 -static void i915_get_mem_freq(struct drm_device *dev)
 +static void i915_pineview_get_mem_freq(struct drm_device *dev)
  {
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 tmp;
  
 -      if (!IS_PINEVIEW(dev))
 -              return;
 -
        tmp = I915_READ(CLKCFG);
  
        switch (tmp & CLKCFG_FSB_MASK) {
                dev_priv->mem_freq = 800;
                break;
        }
 +
 +      /* detect pineview DDR3 setting */
 +      tmp = I915_READ(CSHRDDR3CTL);
 +      dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0;
 +}
 +
 +static void i915_ironlake_get_mem_freq(struct drm_device *dev)
 +{
 +      drm_i915_private_t *dev_priv = dev->dev_private;
 +      u16 ddrpll, csipll;
 +
 +      ddrpll = I915_READ16(DDRMPLL1);
 +      csipll = I915_READ16(CSIPLL0);
 +
 +      switch (ddrpll & 0xff) {
 +      case 0xc:
 +              dev_priv->mem_freq = 800;
 +              break;
 +      case 0x10:
 +              dev_priv->mem_freq = 1066;
 +              break;
 +      case 0x14:
 +              dev_priv->mem_freq = 1333;
 +              break;
 +      case 0x18:
 +              dev_priv->mem_freq = 1600;
 +              break;
 +      default:
 +              DRM_DEBUG_DRIVER("unknown memory frequency 0x%02x\n",
 +                               ddrpll & 0xff);
 +              dev_priv->mem_freq = 0;
 +              break;
 +      }
 +
 +      dev_priv->r_t = dev_priv->mem_freq;
 +
 +      switch (csipll & 0x3ff) {
 +      case 0x00c:
 +              dev_priv->fsb_freq = 3200;
 +              break;
 +      case 0x00e:
 +              dev_priv->fsb_freq = 3733;
 +              break;
 +      case 0x010:
 +              dev_priv->fsb_freq = 4266;
 +              break;
 +      case 0x012:
 +              dev_priv->fsb_freq = 4800;
 +              break;
 +      case 0x014:
 +              dev_priv->fsb_freq = 5333;
 +              break;
 +      case 0x016:
 +              dev_priv->fsb_freq = 5866;
 +              break;
 +      case 0x018:
 +              dev_priv->fsb_freq = 6400;
 +              break;
 +      default:
 +              DRM_DEBUG_DRIVER("unknown fsb frequency 0x%04x\n",
 +                               csipll & 0x3ff);
 +              dev_priv->fsb_freq = 0;
 +              break;
 +      }
 +
 +      if (dev_priv->fsb_freq == 3200) {
 +              dev_priv->c_m = 0;
 +      } else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) {
 +              dev_priv->c_m = 1;
 +      } else {
 +              dev_priv->c_m = 2;
 +      }
 +}
 +
 +struct v_table {
 +      u8 vid;
 +      unsigned long vd; /* in .1 mil */
 +      unsigned long vm; /* in .1 mil */
 +      u8 pvid;
 +};
 +
 +static struct v_table v_table[] = {
 +      { 0, 16125, 15000, 0x7f, },
 +      { 1, 16000, 14875, 0x7e, },
 +      { 2, 15875, 14750, 0x7d, },
 +      { 3, 15750, 14625, 0x7c, },
 +      { 4, 15625, 14500, 0x7b, },
 +      { 5, 15500, 14375, 0x7a, },
 +      { 6, 15375, 14250, 0x79, },
 +      { 7, 15250, 14125, 0x78, },
 +      { 8, 15125, 14000, 0x77, },
 +      { 9, 15000, 13875, 0x76, },
 +      { 10, 14875, 13750, 0x75, },
 +      { 11, 14750, 13625, 0x74, },
 +      { 12, 14625, 13500, 0x73, },
 +      { 13, 14500, 13375, 0x72, },
 +      { 14, 14375, 13250, 0x71, },
 +      { 15, 14250, 13125, 0x70, },
 +      { 16, 14125, 13000, 0x6f, },
 +      { 17, 14000, 12875, 0x6e, },
 +      { 18, 13875, 12750, 0x6d, },
 +      { 19, 13750, 12625, 0x6c, },
 +      { 20, 13625, 12500, 0x6b, },
 +      { 21, 13500, 12375, 0x6a, },
 +      { 22, 13375, 12250, 0x69, },
 +      { 23, 13250, 12125, 0x68, },
 +      { 24, 13125, 12000, 0x67, },
 +      { 25, 13000, 11875, 0x66, },
 +      { 26, 12875, 11750, 0x65, },
 +      { 27, 12750, 11625, 0x64, },
 +      { 28, 12625, 11500, 0x63, },
 +      { 29, 12500, 11375, 0x62, },
 +      { 30, 12375, 11250, 0x61, },
 +      { 31, 12250, 11125, 0x60, },
 +      { 32, 12125, 11000, 0x5f, },
 +      { 33, 12000, 10875, 0x5e, },
 +      { 34, 11875, 10750, 0x5d, },
 +      { 35, 11750, 10625, 0x5c, },
 +      { 36, 11625, 10500, 0x5b, },
 +      { 37, 11500, 10375, 0x5a, },
 +      { 38, 11375, 10250, 0x59, },
 +      { 39, 11250, 10125, 0x58, },
 +      { 40, 11125, 10000, 0x57, },
 +      { 41, 11000, 9875, 0x56, },
 +      { 42, 10875, 9750, 0x55, },
 +      { 43, 10750, 9625, 0x54, },
 +      { 44, 10625, 9500, 0x53, },
 +      { 45, 10500, 9375, 0x52, },
 +      { 46, 10375, 9250, 0x51, },
 +      { 47, 10250, 9125, 0x50, },
 +      { 48, 10125, 9000, 0x4f, },
 +      { 49, 10000, 8875, 0x4e, },
 +      { 50, 9875, 8750, 0x4d, },
 +      { 51, 9750, 8625, 0x4c, },
 +      { 52, 9625, 8500, 0x4b, },
 +      { 53, 9500, 8375, 0x4a, },
 +      { 54, 9375, 8250, 0x49, },
 +      { 55, 9250, 8125, 0x48, },
 +      { 56, 9125, 8000, 0x47, },
 +      { 57, 9000, 7875, 0x46, },
 +      { 58, 8875, 7750, 0x45, },
 +      { 59, 8750, 7625, 0x44, },
 +      { 60, 8625, 7500, 0x43, },
 +      { 61, 8500, 7375, 0x42, },
 +      { 62, 8375, 7250, 0x41, },
 +      { 63, 8250, 7125, 0x40, },
 +      { 64, 8125, 7000, 0x3f, },
 +      { 65, 8000, 6875, 0x3e, },
 +      { 66, 7875, 6750, 0x3d, },
 +      { 67, 7750, 6625, 0x3c, },
 +      { 68, 7625, 6500, 0x3b, },
 +      { 69, 7500, 6375, 0x3a, },
 +      { 70, 7375, 6250, 0x39, },
 +      { 71, 7250, 6125, 0x38, },
 +      { 72, 7125, 6000, 0x37, },
 +      { 73, 7000, 5875, 0x36, },
 +      { 74, 6875, 5750, 0x35, },
 +      { 75, 6750, 5625, 0x34, },
 +      { 76, 6625, 5500, 0x33, },
 +      { 77, 6500, 5375, 0x32, },
 +      { 78, 6375, 5250, 0x31, },
 +      { 79, 6250, 5125, 0x30, },
 +      { 80, 6125, 5000, 0x2f, },
 +      { 81, 6000, 4875, 0x2e, },
 +      { 82, 5875, 4750, 0x2d, },
 +      { 83, 5750, 4625, 0x2c, },
 +      { 84, 5625, 4500, 0x2b, },
 +      { 85, 5500, 4375, 0x2a, },
 +      { 86, 5375, 4250, 0x29, },
 +      { 87, 5250, 4125, 0x28, },
 +      { 88, 5125, 4000, 0x27, },
 +      { 89, 5000, 3875, 0x26, },
 +      { 90, 4875, 3750, 0x25, },
 +      { 91, 4750, 3625, 0x24, },
 +      { 92, 4625, 3500, 0x23, },
 +      { 93, 4500, 3375, 0x22, },
 +      { 94, 4375, 3250, 0x21, },
 +      { 95, 4250, 3125, 0x20, },
 +      { 96, 4125, 3000, 0x1f, },
 +      { 97, 4125, 3000, 0x1e, },
 +      { 98, 4125, 3000, 0x1d, },
 +      { 99, 4125, 3000, 0x1c, },
 +      { 100, 4125, 3000, 0x1b, },
 +      { 101, 4125, 3000, 0x1a, },
 +      { 102, 4125, 3000, 0x19, },
 +      { 103, 4125, 3000, 0x18, },
 +      { 104, 4125, 3000, 0x17, },
 +      { 105, 4125, 3000, 0x16, },
 +      { 106, 4125, 3000, 0x15, },
 +      { 107, 4125, 3000, 0x14, },
 +      { 108, 4125, 3000, 0x13, },
 +      { 109, 4125, 3000, 0x12, },
 +      { 110, 4125, 3000, 0x11, },
 +      { 111, 4125, 3000, 0x10, },
 +      { 112, 4125, 3000, 0x0f, },
 +      { 113, 4125, 3000, 0x0e, },
 +      { 114, 4125, 3000, 0x0d, },
 +      { 115, 4125, 3000, 0x0c, },
 +      { 116, 4125, 3000, 0x0b, },
 +      { 117, 4125, 3000, 0x0a, },
 +      { 118, 4125, 3000, 0x09, },
 +      { 119, 4125, 3000, 0x08, },
 +      { 120, 1125, 0, 0x07, },
 +      { 121, 1000, 0, 0x06, },
 +      { 122, 875, 0, 0x05, },
 +      { 123, 750, 0, 0x04, },
 +      { 124, 625, 0, 0x03, },
 +      { 125, 500, 0, 0x02, },
 +      { 126, 375, 0, 0x01, },
 +      { 127, 0, 0, 0x00, },
 +};
 +
 +struct cparams {
 +      int i;
 +      int t;
 +      int m;
 +      int c;
 +};
 +
 +static struct cparams cparams[] = {
 +      { 1, 1333, 301, 28664 },
 +      { 1, 1066, 294, 24460 },
 +      { 1, 800, 294, 25192 },
 +      { 0, 1333, 276, 27605 },
 +      { 0, 1066, 276, 27605 },
 +      { 0, 800, 231, 23784 },
 +};
 +
 +unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
 +{
 +      u64 total_count, diff, ret;
 +      u32 count1, count2, count3, m = 0, c = 0;
 +      unsigned long now = jiffies_to_msecs(jiffies), diff1;
 +      int i;
 +
 +      diff1 = now - dev_priv->last_time1;
 +
 +      count1 = I915_READ(DMIEC);
 +      count2 = I915_READ(DDREC);
 +      count3 = I915_READ(CSIEC);
 +
 +      total_count = count1 + count2 + count3;
 +
 +      /* FIXME: handle per-counter overflow */
 +      if (total_count < dev_priv->last_count1) {
 +              diff = ~0UL - dev_priv->last_count1;
 +              diff += total_count;
 +      } else {
 +              diff = total_count - dev_priv->last_count1;
 +      }
 +
 +      for (i = 0; i < ARRAY_SIZE(cparams); i++) {
 +              if (cparams[i].i == dev_priv->c_m &&
 +                  cparams[i].t == dev_priv->r_t) {
 +                      m = cparams[i].m;
 +                      c = cparams[i].c;
 +                      break;
 +              }
 +      }
 +
 +      div_u64(diff, diff1);
 +      ret = ((m * diff) + c);
 +      div_u64(ret, 10);
 +
 +      dev_priv->last_count1 = total_count;
 +      dev_priv->last_time1 = now;
 +
 +      return ret;
 +}
 +
 +unsigned long i915_mch_val(struct drm_i915_private *dev_priv)
 +{
 +      unsigned long m, x, b;
 +      u32 tsfs;
 +
 +      tsfs = I915_READ(TSFS);
 +
 +      m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT);
 +      x = I915_READ8(TR1);
 +
 +      b = tsfs & TSFS_INTR_MASK;
 +
 +      return ((m * x) / 127) - b;
 +}
 +
 +static unsigned long pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
 +{
 +      unsigned long val = 0;
 +      int i;
 +
 +      for (i = 0; i < ARRAY_SIZE(v_table); i++) {
 +              if (v_table[i].pvid == pxvid) {
 +                      if (IS_MOBILE(dev_priv->dev))
 +                              val = v_table[i].vm;
 +                      else
 +                              val = v_table[i].vd;
 +              }
 +      }
 +
 +      return val;
  }
  
 +void i915_update_gfx_val(struct drm_i915_private *dev_priv)
 +{
 +      struct timespec now, diff1;
 +      u64 diff;
 +      unsigned long diffms;
 +      u32 count;
 +
 +      getrawmonotonic(&now);
 +      diff1 = timespec_sub(now, dev_priv->last_time2);
 +
 +      /* Don't divide by 0 */
 +      diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000;
 +      if (!diffms)
 +              return;
 +
 +      count = I915_READ(GFXEC);
 +
 +      if (count < dev_priv->last_count2) {
 +              diff = ~0UL - dev_priv->last_count2;
 +              diff += count;
 +      } else {
 +              diff = count - dev_priv->last_count2;
 +      }
 +
 +      dev_priv->last_count2 = count;
 +      dev_priv->last_time2 = now;
 +
 +      /* More magic constants... */
 +      diff = diff * 1181;
 +      div_u64(diff, diffms * 10);
 +      dev_priv->gfx_power = diff;
 +}
 +
 +unsigned long i915_gfx_val(struct drm_i915_private *dev_priv)
 +{
 +      unsigned long t, corr, state1, corr2, state2;
 +      u32 pxvid, ext_v;
 +
 +      pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4));
 +      pxvid = (pxvid >> 24) & 0x7f;
 +      ext_v = pvid_to_extvid(dev_priv, pxvid);
 +
 +      state1 = ext_v;
 +
 +      t = i915_mch_val(dev_priv);
 +
 +      /* Revel in the empirically derived constants */
 +
 +      /* Correction factor in 1/100000 units */
 +      if (t > 80)
 +              corr = ((t * 2349) + 135940);
 +      else if (t >= 50)
 +              corr = ((t * 964) + 29317);
 +      else /* < 50 */
 +              corr = ((t * 301) + 1004);
 +
 +      corr = corr * ((150142 * state1) / 10000 - 78642);
 +      corr /= 100000;
 +      corr2 = (corr * dev_priv->corr);
 +
 +      state2 = (corr2 * state1) / 10000;
 +      state2 /= 100; /* convert to mW */
 +
 +      i915_update_gfx_val(dev_priv);
 +
 +      return dev_priv->gfx_power + state2;
 +}
 +
 +/* Global for IPS driver to get at the current i915 device */
 +static struct drm_i915_private *i915_mch_dev;
 +/*
 + * Lock protecting IPS related data structures
 + *   - i915_mch_dev
 + *   - dev_priv->max_delay
 + *   - dev_priv->min_delay
 + *   - dev_priv->fmax
 + *   - dev_priv->gpu_busy
 + */
 +DEFINE_SPINLOCK(mchdev_lock);
 +
 +/**
 + * i915_read_mch_val - return value for IPS use
 + *
 + * Calculate and return a value for the IPS driver to use when deciding whether
 + * we have thermal and power headroom to increase CPU or GPU power budget.
 + */
 +unsigned long i915_read_mch_val(void)
 +{
 +      struct drm_i915_private *dev_priv;
 +      unsigned long chipset_val, graphics_val, ret = 0;
 +
 +      spin_lock(&mchdev_lock);
 +      if (!i915_mch_dev)
 +              goto out_unlock;
 +      dev_priv = i915_mch_dev;
 +
 +      chipset_val = i915_chipset_val(dev_priv);
 +      graphics_val = i915_gfx_val(dev_priv);
 +
 +      ret = chipset_val + graphics_val;
 +
 +out_unlock:
 +      spin_unlock(&mchdev_lock);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(i915_read_mch_val);
 +
 +/**
 + * i915_gpu_raise - raise GPU frequency limit
 + *
 + * Raise the limit; IPS indicates we have thermal headroom.
 + */
 +bool i915_gpu_raise(void)
 +{
 +      struct drm_i915_private *dev_priv;
 +      bool ret = true;
 +
 +      spin_lock(&mchdev_lock);
 +      if (!i915_mch_dev) {
 +              ret = false;
 +              goto out_unlock;
 +      }
 +      dev_priv = i915_mch_dev;
 +
 +      if (dev_priv->max_delay > dev_priv->fmax)
 +              dev_priv->max_delay--;
 +
 +out_unlock:
 +      spin_unlock(&mchdev_lock);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(i915_gpu_raise);
 +
 +/**
 + * i915_gpu_lower - lower GPU frequency limit
 + *
 + * IPS indicates we're close to a thermal limit, so throttle back the GPU
 + * frequency maximum.
 + */
 +bool i915_gpu_lower(void)
 +{
 +      struct drm_i915_private *dev_priv;
 +      bool ret = true;
 +
 +      spin_lock(&mchdev_lock);
 +      if (!i915_mch_dev) {
 +              ret = false;
 +              goto out_unlock;
 +      }
 +      dev_priv = i915_mch_dev;
 +
 +      if (dev_priv->max_delay < dev_priv->min_delay)
 +              dev_priv->max_delay++;
 +
 +out_unlock:
 +      spin_unlock(&mchdev_lock);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(i915_gpu_lower);
 +
 +/**
 + * i915_gpu_busy - indicate GPU business to IPS
 + *
 + * Tell the IPS driver whether or not the GPU is busy.
 + */
 +bool i915_gpu_busy(void)
 +{
 +      struct drm_i915_private *dev_priv;
 +      bool ret = false;
 +
 +      spin_lock(&mchdev_lock);
 +      if (!i915_mch_dev)
 +              goto out_unlock;
 +      dev_priv = i915_mch_dev;
 +
 +      ret = dev_priv->busy;
 +
 +out_unlock:
 +      spin_unlock(&mchdev_lock);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(i915_gpu_busy);
 +
 +/**
 + * i915_gpu_turbo_disable - disable graphics turbo
 + *
 + * Disable graphics turbo by resetting the max frequency and setting the
 + * current frequency to the default.
 + */
 +bool i915_gpu_turbo_disable(void)
 +{
 +      struct drm_i915_private *dev_priv;
 +      bool ret = true;
 +
 +      spin_lock(&mchdev_lock);
 +      if (!i915_mch_dev) {
 +              ret = false;
 +              goto out_unlock;
 +      }
 +      dev_priv = i915_mch_dev;
 +
 +      dev_priv->max_delay = dev_priv->fstart;
 +
 +      if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart))
 +              ret = false;
 +
 +out_unlock:
 +      spin_unlock(&mchdev_lock);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
 +
  /**
   * i915_driver_load - setup chip and create an initial config
   * @dev: DRM device
@@@ -2029,6 -1596,7 +2031,6 @@@ int i915_driver_load(struct drm_device 
        resource_size_t base, size;
        int ret = 0, mmio_bar;
        uint32_t agp_size, prealloc_size, prealloc_start;
 -
        /* i915 has 4 more counters */
        dev->counters += 4;
        dev->types[6] = _DRM_STAT_IRQ;
                dev_priv->has_gem = 0;
        }
  
 +      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_iomapfree;
 +      }
 +
        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_IRONLAKE(dev) || IS_GEN6(dev)) {
                        goto out_workqueue_free;
        }
  
 -      i915_get_mem_freq(dev);
 +      if (IS_PINEVIEW(dev))
 +              i915_pineview_get_mem_freq(dev);
 +      else if (IS_IRONLAKE(dev))
 +              i915_ironlake_get_mem_freq(dev);
  
        /* On the 945G/GM, the chipset reports the MSI capability on the
         * integrated graphics even though the support isn't actually there
  
        spin_lock_init(&dev_priv->user_irq_lock);
        spin_lock_init(&dev_priv->error_lock);
 -      dev_priv->user_irq_refcount = 0;
        dev_priv->trace_irq_seqno = 0;
  
        ret = drm_vblank_init(dev, I915_NUM_PIPE);
  
        setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
                    (unsigned long) dev);
 +
 +      spin_lock(&mchdev_lock);
 +      i915_mch_dev = dev_priv;
 +      dev_priv->mchdev_lock = &mchdev_lock;
 +      spin_unlock(&mchdev_lock);
 +
        return 0;
  
  out_workqueue_free:
@@@ -2208,10 -1761,6 +2210,10 @@@ int i915_driver_unload(struct drm_devic
  
        i915_destroy_error_state(dev);
  
 +      spin_lock(&mchdev_lock);
 +      i915_mch_dev = NULL;
 +      spin_unlock(&mchdev_lock);
 +
        destroy_workqueue(dev_priv->wq);
        del_timer_sync(&dev_priv->hangcheck_timer);