Merge branch 'master' into modesetting-101
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Thu, 25 Oct 2007 09:00:45 +0000 (11:00 +0200)
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Thu, 25 Oct 2007 09:00:45 +0000 (11:00 +0200)
Conflicts:

linux-core/Makefile.kernel
linux-core/drm_bo.c
linux-core/drm_objects.h

1  2 
linux-core/Makefile.kernel
linux-core/drm_bo.c
linux-core/drm_drv.c
linux-core/drm_objects.h
linux-core/drm_stub.c
linux-core/i915_buffer.c
linux-core/intel_fb.c
shared-core/drm.h
shared-core/i915_dma.c
shared-core/i915_drv.h
shared-core/i915_init.c

@@@ -13,8 -13,7 +13,8 @@@ drm-objs    := drm_auth.o drm_bufs.o dr
                drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \
                drm_memory_debug.o ati_pcigart.o drm_sman.o \
                drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \
 -              drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_bo_lock.o
 +              drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \
-               drm_edid.o drm_modes.o
++              drm_edid.o drm_modes.o drm_bo_lock.o
  tdfx-objs   := tdfx_drv.o
  r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
  mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
@@@ -2400,11 -2189,16 +2188,17 @@@ int drm_bo_driver_finish(struct drm_dev
        }
        out:
        mutex_unlock(&dev->struct_mutex);
-       mutex_unlock(&dev->bm.init_mutex);
        return ret;
  }
 +EXPORT_SYMBOL(drm_bo_driver_finish);
  
+ /*
+  * This function is intended to be called on drm driver load.
+  * If you decide to call it from firstopen, you must protect the call
+  * from a potentially racing drm_bo_driver_finish in lastclose. 
+  * (This may happen on X server restart).
+  */
  int drm_bo_driver_init(struct drm_device * dev)
  {
        struct drm_bo_driver *driver = dev->driver->bo_driver;
Simple merge
@@@ -605,10 -612,21 +612,25 @@@ extern void drm_regs_init(struct drm_re
                                              const void *),
                          void (*reg_destroy)(struct drm_reg *));
  
 +extern int drm_mem_reg_ioremap(struct drm_device *dev, struct drm_bo_mem_reg * mem,
 +                             void **virtual);
 +extern void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg * mem,
 +                              void *virtual);
+ /*
+  * drm_bo_lock.c 
+  * Simple replacement for the hardware lock on buffer manager init and clean.
+  */
+ extern void drm_bo_init_lock(struct drm_bo_lock *lock);
+ extern void drm_bo_read_unlock(struct drm_bo_lock *lock);
+ extern int drm_bo_read_lock(struct drm_bo_lock *lock);
+ extern int drm_bo_write_lock(struct drm_bo_lock *lock, 
+                            struct drm_file *file_priv);
+ extern int drm_bo_write_unlock(struct drm_bo_lock *lock, 
+                              struct drm_file *file_priv);
  #ifdef CONFIG_DEBUG_MUTEXES
  #define DRM_ASSERT_LOCKED(_mutex)                                     \
        BUG_ON(!mutex_is_locked(_mutex) ||                              \
Simple merge
Simple merge
index c9cb293,0000000..564a913
mode 100644,000000..100644
--- /dev/null
@@@ -1,666 -1,0 +1,659 @@@
-                                      DRM_BO_FLAG_MEM_VRAM,
-                                      0, 0, 0,
 +/*
 + * Copyright © 2007 David Airlie
 + *
 + * Permission is hereby granted, free of charge, to any person obtaining a
 + * copy of this software and associated documentation files (the "Software"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
 + *
 + * The above copyright notice and this permission notice (including the next
 + * paragraph) shall be included in all copies or substantial portions of the
 + * Software.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 + * DEALINGS IN THE SOFTWARE.
 + *
 + * Authors:
 + *     David Airlie
 + */
 +    /*
 +     *  Modularization
 +     */
 +
 +#include <linux/module.h>
 +#include <linux/kernel.h>
 +#include <linux/errno.h>
 +#include <linux/string.h>
 +#include <linux/mm.h>
 +#include <linux/tty.h>
 +#include <linux/slab.h>
 +#include <linux/delay.h>
 +#include <linux/fb.h>
 +#include <linux/init.h>
 +
 +#include "drmP.h"
 +#include "drm.h"
 +#include "drm_crtc.h"
 +#include "i915_drm.h"
 +#include "i915_drv.h"
 +
 +struct intelfb_par {
 +      struct drm_device *dev;
 +      struct drm_crtc *crtc;
 +};
 +
 +static int
 +var_to_refresh(const struct fb_var_screeninfo *var)
 +{
 +      int xtot = var->xres + var->left_margin + var->right_margin +
 +                 var->hsync_len;
 +      int ytot = var->yres + var->upper_margin + var->lower_margin +
 +                 var->vsync_len;
 +
 +      return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot;
 +}
 +
 +static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
 +                         unsigned blue, unsigned transp,
 +                         struct fb_info *info)
 +{
 +      struct intelfb_par *par = info->par;
 +      struct drm_framebuffer *fb = par->crtc->fb;
 +      struct drm_crtc *crtc = par->crtc;
 +
 +      if (regno > 255)
 +              return 1;
 +
 +      if (fb->depth == 8) {
 +              if (crtc->funcs->gamma_set)
 +                      crtc->funcs->gamma_set(crtc, red, green, blue, regno);
 +              return 0;
 +      }
 +
 +      if (regno < 16) {
 +              switch (fb->depth) {
 +              case 15:
 +                      fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
 +                              ((green & 0xf800) >>  6) |
 +                              ((blue & 0xf800) >> 11);
 +                      break;
 +              case 16:
 +                      fb->pseudo_palette[regno] = (red & 0xf800) |
 +                              ((green & 0xfc00) >>  5) |
 +                              ((blue  & 0xf800) >> 11);
 +                      break;
 +              case 24:
 +              case 32:
 +                      fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
 +                              (green & 0xff00) |
 +                              ((blue  & 0xff00) >> 8);
 +                      break;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +static int intelfb_check_var(struct fb_var_screeninfo *var,
 +                           struct fb_info *info)
 +{
 +        struct intelfb_par *par = info->par;
 +        struct drm_device *dev = par->dev;
 +      struct drm_framebuffer *fb = par->crtc->fb;
 +        struct drm_display_mode *drm_mode;
 +        struct drm_output *output;
 +        int depth, found = 0;
 +
 +        if (!var->pixclock)
 +                return -EINVAL;
 +
 +        /* Need to resize the fb object !!! */
 +        if (var->xres > fb->width || var->yres > fb->height) {
 +                DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
 +                DRM_ERROR("Need resizing code.\n");
 +                return -EINVAL;
 +        }
 +
 +        switch (var->bits_per_pixel) {
 +        case 16:
 +                depth = (var->green.length == 6) ? 16 : 15;
 +                break;
 +        case 32:
 +                depth = (var->transp.length > 0) ? 32 : 24;
 +                break;
 +        default:
 +                depth = var->bits_per_pixel;
 +                break;
 +        }
 +                
 +        switch (depth) {
 +        case 8:
 +                var->red.offset = 0;
 +                var->green.offset = 0;
 +                var->blue.offset = 0;
 +                var->red.length = 8;
 +                var->green.length = 8;
 +                var->blue.length = 8;
 +                var->transp.length = 0;
 +                var->transp.offset = 0;
 +                break;
 +        case 15:
 +                var->red.offset = 10;
 +                var->green.offset = 5;
 +                var->blue.offset = 0;
 +                var->red.length = 5;
 +                var->green.length = 5;
 +                var->blue.length = 5;
 +                var->transp.length = 1;
 +                var->transp.offset = 15;
 +                break;
 +        case 16:
 +                var->red.offset = 11;
 +                var->green.offset = 6;
 +                var->blue.offset = 0;
 +                var->red.length = 5;
 +                var->green.length = 6;
 +                var->blue.length = 5;
 +                var->transp.length = 0;
 +                var->transp.offset = 0;
 +                break;
 +        case 24:
 +                var->red.offset = 16;
 +                var->green.offset = 8;
 +                var->blue.offset = 0;
 +                var->red.length = 8;
 +                var->green.length = 8;
 +                var->blue.length = 8;
 +                var->transp.length = 0;
 +                var->transp.offset = 0;
 +                break;
 +        case 32:
 +                var->red.offset = 16;
 +                var->green.offset = 8;
 +                var->blue.offset = 0;
 +                var->red.length = 8;
 +                var->green.length = 8;
 +                var->blue.length = 8;
 +                var->transp.length = 8;
 +                var->transp.offset = 24;
 +                break;
 +        default:
 +                return -EINVAL; 
 +        }
 +
 +#if 0
 +        /* Here we walk the output mode list and look for modes. If we haven't
 +         * got it, then bail. Not very nice, so this is disabled.
 +         * In the set_par code, we create our mode based on the incoming
 +         * parameters. Nicer, but may not be desired by some.
 +         */
 +        list_for_each_entry(output, &dev->mode_config.output_list, head) {
 +                if (output->crtc == par->crtc)
 +                        break;
 +        }
 +    
 +        list_for_each_entry(drm_mode, &output->modes, head) {
 +                if (drm_mode->hdisplay == var->xres &&
 +                    drm_mode->vdisplay == var->yres &&
 +                    (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) &&
 +                    (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) {
 +                      found = 1;
 +                      break;
 +              }
 +      }
 + 
 +        if (!found)
 +                return -EINVAL;
 +#endif
 +
 +      return 0;
 +}
 +
 +/* this will let fbcon do the mode init */
 +/* FIXME: take mode config lock? */
 +static int intelfb_set_par(struct fb_info *info)
 +{
 +      struct intelfb_par *par = info->par;
 +      struct drm_framebuffer *fb = par->crtc->fb;
 +      struct drm_device *dev = par->dev;
 +        struct drm_display_mode *drm_mode;
 +        struct drm_output *output;
 +        struct fb_var_screeninfo *var = &info->var;
 +      int found = 0;
 +
 +        switch (var->bits_per_pixel) {
 +        case 16:
 +                fb->depth = (var->green.length == 6) ? 16 : 15;
 +                break;
 +        case 32:
 +                fb->depth = (var->transp.length > 0) ? 32 : 24;
 +                break;
 +        default:
 +                fb->depth = var->bits_per_pixel;
 +                break;
 +        }
 +
 +        fb->bits_per_pixel = var->bits_per_pixel;
 +
 +        info->fix.line_length = fb->pitch;
 +        info->fix.smem_len = info->fix.line_length * fb->height;
 +        info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
 +
 +        info->screen_size = info->fix.smem_len; /* ??? */
 +
 +        /* Should we walk the output's modelist or just create our own ???
 +         * For now, we create and destroy a mode based on the incoming 
 +         * parameters. But there's commented out code below which scans 
 +         * the output list too.
 +         */
 +#if 0
 +        list_for_each_entry(output, &dev->mode_config.output_list, head) {
 +                if (output->crtc == par->crtc)
 +                        break;
 +        }
 +    
 +        list_for_each_entry(drm_mode, &output->modes, head) {
 +                if (drm_mode->hdisplay == var->xres &&
 +                    drm_mode->vdisplay == var->yres &&
 +                    (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) &&
 +                    (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) {
 +                      found = 1;
 +                      break;
 +              }
 +        }
 +
 +      if (!found) {
 +              DRM_ERROR("Couldn't find a mode for requested %dx%d-%d\n",
 +                      var->xres,var->yres,var_to_refresh(var));
 +              return -EINVAL;
 +      }
 +#else
 +        drm_mode = drm_mode_create(dev);
 +        drm_mode->hdisplay = var->xres;
 +        drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
 +        drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
 +        drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
 +        drm_mode->vdisplay = var->yres;
 +        drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
 +        drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
 +        drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
 +        drm_mode->clock = PICOS2KHZ(var->pixclock);
 +        drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
 +        drm_mode_set_name(drm_mode);
 +      drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
 +#endif
 +
 +      drm_mode_debug_printmodeline(dev, drm_mode);
 +
 +        if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0))
 +                return -EINVAL;
 +
 +        /* Have to destroy our created mode if we're not searching the mode
 +         * list for it.
 +         */
 +#if 1
 +        drm_mode_destroy(dev, drm_mode);
 +#endif
 +
 +      return 0;
 +}
 +
 +#if 0
 +static void intelfb_copyarea(struct fb_info *info,
 +                           const struct fb_copyarea *region)
 +{
 +        struct intelfb_par *par = info->par;
 +      struct drm_device *dev = par->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset;
 +      u32 cmd, rop_depth_pitch, src_pitch;
 +      RING_LOCALS;
 +
 +      cmd = XY_SRC_COPY_BLT_CMD;
 +      src_x1 = region->sx;
 +      src_y1 = region->sy;
 +      dst_x1 = region->dx;
 +      dst_y1 = region->dy;
 +      dst_x2 = region->dx + region->width;
 +      dst_y2 = region->dy + region->height;
 +      offset = par->fb->offset;
 +      rop_depth_pitch = BLT_ROP_GXCOPY | par->fb->pitch;
 +      src_pitch = par->fb->pitch;
 +
 +      switch (par->fb->bits_per_pixel) {
 +      case 16:
 +              rop_depth_pitch |= BLT_DEPTH_16_565;
 +              break;
 +      case 32:
 +              rop_depth_pitch |= BLT_DEPTH_32;
 +              cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
 +              break;
 +      }
 +
 +      BEGIN_LP_RING(8);
 +      OUT_RING(cmd);
 +      OUT_RING(rop_depth_pitch);
 +      OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
 +      OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
 +      OUT_RING(offset);
 +      OUT_RING((src_y1 << 16) | (src_x1 & 0xffff));
 +      OUT_RING(src_pitch);
 +      OUT_RING(offset);
 +      ADVANCE_LP_RING();
 +}
 +
 +#define ROUND_UP_TO(x, y)     (((x) + (y) - 1) / (y) * (y))
 +#define ROUND_DOWN_TO(x, y)   ((x) / (y) * (y))
 +
 +void intelfb_imageblit(struct fb_info *info, const struct fb_image *image)
 +{
 +        struct intelfb_par *par = info->par;
 +      struct drm_device *dev = par->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      u32 cmd, rop_pitch_depth, tmp;
 +      int nbytes, ndwords, pad;
 +      u32 dst_x1, dst_y1, dst_x2, dst_y2, offset, bg, fg;
 +      int dat, ix, iy, iw;
 +      int i, j;
 +      RING_LOCALS;
 +
 +      /* size in bytes of a padded scanline */
 +      nbytes = ROUND_UP_TO(image->width, 16) / 8;
 +
 +      /* Total bytes of padded scanline data to write out. */
 +      nbytes *= image->height;
 +
 +      /*
 +       * Check if the glyph data exceeds the immediate mode limit.
 +       * It would take a large font (1K pixels) to hit this limit.
 +       */
 +      if (nbytes > 128 || image->depth != 1)
 +              return cfb_imageblit(info, image);
 +
 +      /* Src data is packaged a dword (32-bit) at a time. */
 +      ndwords = ROUND_UP_TO(nbytes, 4) / 4;
 +
 +      /*
 +       * Ring has to be padded to a quad word. But because the command starts
 +         with 7 bytes, pad only if there is an even number of ndwords
 +       */
 +      pad = !(ndwords % 2);
 +
 +      DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width,
 +                image->height, image->depth, image->dx, image->dy);
 +      DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad);
 +
 +      tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords;
 +      cmd = (XY_MONO_SRC_COPY_IMM_BLT & ~0xff) | tmp;
 +      offset = par->fb->offset;
 +      dst_x1 = image->dx;
 +      dst_y1 = image->dy;
 +      dst_x2 = image->dx + image->width;
 +      dst_y2 = image->dy + image->height;
 +      rop_pitch_depth = BLT_ROP_GXCOPY | par->fb->pitch;
 +
 +      switch (par->fb->bits_per_pixel) {
 +      case 8:
 +              rop_pitch_depth |= BLT_DEPTH_8;
 +              fg = image->fg_color;
 +              bg = image->bg_color;
 +              break;
 +      case 16:
 +              rop_pitch_depth |= BLT_DEPTH_16_565;
 +              fg = par->fb->pseudo_palette[image->fg_color];
 +              bg = par->fb->pseudo_palette[image->bg_color];
 +              break;
 +      case 32:
 +              rop_pitch_depth |= BLT_DEPTH_32;
 +              cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
 +              fg = par->fb->pseudo_palette[image->fg_color];
 +              bg = par->fb->pseudo_palette[image->bg_color];
 +              break;
 +      default:
 +              DRM_ERROR("unknown depth %d\n", par->fb->bits_per_pixel);
 +              break;
 +      }
 +      
 +      BEGIN_LP_RING(8 + ndwords);
 +      OUT_RING(cmd);
 +      OUT_RING(rop_pitch_depth);
 +      OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
 +      OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
 +      OUT_RING(offset);
 +      OUT_RING(bg);
 +      OUT_RING(fg);
 +      ix = iy = 0;
 +      iw = ROUND_UP_TO(image->width, 8) / 8;
 +      while (ndwords--) {
 +              dat = 0;
 +              for (j = 0; j < 2; ++j) {
 +                      for (i = 0; i < 2; ++i) {
 +                              if (ix != iw || i == 0)
 +                                      dat |= image->data[iy*iw + ix++] << (i+j*2)*8;
 +                      }
 +                      if (ix == iw && iy != (image->height - 1)) {
 +                              ix = 0;
 +                              ++iy;
 +                      }
 +              }
 +              OUT_RING(dat);
 +      }
 +      if (pad)
 +              OUT_RING(MI_NOOP);
 +      ADVANCE_LP_RING();
 +}
 +#endif
 +
 +static struct fb_ops intelfb_ops = {
 +      .owner = THIS_MODULE,
 +      //      .fb_open = intelfb_open,
 +      //      .fb_read = intelfb_read,
 +      //      .fb_write = intelfb_write,
 +      //      .fb_release = intelfb_release,
 +      //      .fb_ioctl = intelfb_ioctl,
 +      .fb_check_var = intelfb_check_var,
 +      .fb_set_par = intelfb_set_par,
 +      .fb_setcolreg = intelfb_setcolreg,
 +      .fb_fillrect = cfb_fillrect,
 +      .fb_copyarea = cfb_copyarea, //intelfb_copyarea,
 +      .fb_imageblit = cfb_imageblit, //intelfb_imageblit,
 +};
 +
 +int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
 +{
 +      struct fb_info *info;
 +      struct intelfb_par *par;
 +      struct device *device = &dev->pdev->dev; 
 +      struct drm_framebuffer *fb;
 +      struct drm_display_mode *mode = crtc->desired_mode;
 +      struct drm_buffer_object *fbo = NULL;
 +      int ret;
 +
 +      info = framebuffer_alloc(sizeof(struct intelfb_par), device);
 +      if (!info){
 +              return -EINVAL;
 +      }
 +
 +      fb = drm_framebuffer_create(dev);
 +      if (!fb) {
 +              framebuffer_release(info);
 +              DRM_ERROR("failed to allocate fb.\n");
 +              return -EINVAL;
 +      }
 +      crtc->fb = fb;
 +
 +      fb->width = crtc->desired_mode->hdisplay;
 +      fb->height = crtc->desired_mode->vdisplay;
 +
 +      fb->bits_per_pixel = 32;
 +      fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8);
 +      fb->depth = 24;
 +      ret = drm_buffer_object_create(dev, fb->width * fb->height * 4, 
 +                                     drm_bo_type_kernel,
 +                                     DRM_BO_FLAG_READ |
 +                                     DRM_BO_FLAG_WRITE |
 +                                     DRM_BO_FLAG_MEM_TT |
-       ret = drm_bo_set_pin(dev, fbo, 1);
-       if (ret) {
-               printk(KERN_ERR "failed to pin framebuffer, aborting\n");
-               drm_framebuffer_destroy(fb);
-               framebuffer_release(info);
-               return -EINVAL;
-       }
++                                     DRM_BO_FLAG_MEM_VRAM |
++                                     DRM_BO_FLAG_NO_EVICT,
++                                     DRM_BO_HINT_DONT_FENCE, 0, 0,
 +                                     &fbo);
 +      if (ret || !fbo) {
 +              printk(KERN_ERR "failed to allocate framebuffer\n");
 +              drm_framebuffer_destroy(fb);
 +              framebuffer_release(info);
 +              return -EINVAL;
 +      }
 +
 +      fb->offset = fbo->offset;
 +      fb->bo = fbo;
 +      printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width,
 +                     fb->height, fbo->offset, fbo);
 +
 +
 +      fb->fbdev = info;
 +              
 +      par = info->par;
 +
 +      par->dev = dev;
 +      par->crtc = crtc;
 +
 +      info->fbops = &intelfb_ops;
 +
 +      strcpy(info->fix.id, "intelfb");
 +      info->fix.type = FB_TYPE_PACKED_PIXELS;
 +      info->fix.visual = FB_VISUAL_TRUECOLOR;
 +      info->fix.type_aux = 0;
 +      info->fix.xpanstep = 8;
 +      info->fix.ypanstep = 1;
 +      info->fix.ywrapstep = 0;
 +      info->fix.accel = FB_ACCEL_I830;
 +      info->fix.type_aux = 0;
 +      info->fix.mmio_start = 0;
 +      info->fix.mmio_len = 0;
 +      info->fix.line_length = fb->pitch;
 +      info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
 +      info->fix.smem_len = info->fix.line_length * fb->height;
 +
 +      info->flags = FBINFO_DEFAULT;
 +
 +      ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base);
 +      if (ret)
 +              DRM_ERROR("error mapping fb: %d\n", ret);
 +
 +      info->screen_base = fb->virtual_base;
 +      info->screen_size = info->fix.smem_len; /* FIXME */
 +      info->pseudo_palette = fb->pseudo_palette;
 +      info->var.xres_virtual = fb->width;
 +      info->var.yres_virtual = fb->height;
 +      info->var.bits_per_pixel = fb->bits_per_pixel;
 +      info->var.xoffset = 0;
 +      info->var.yoffset = 0;
 +      info->var.activate = FB_ACTIVATE_NOW;
 +      info->var.height = -1;
 +      info->var.width = -1;
 +      info->var.vmode = FB_VMODE_NONINTERLACED;
 +
 +        info->var.xres = mode->hdisplay;
 +        info->var.right_margin = mode->hsync_start - mode->hdisplay;
 +        info->var.hsync_len = mode->hsync_end - mode->hsync_start;
 +        info->var.left_margin = mode->htotal - mode->hsync_end;
 +        info->var.yres = mode->vdisplay;
 +        info->var.lower_margin = mode->vsync_start - mode->vdisplay;
 +        info->var.vsync_len = mode->vsync_end - mode->vsync_start;
 +      info->var.upper_margin = mode->vtotal - mode->vsync_end;
 +        info->var.pixclock = 10000000 / mode->htotal * 1000 /
 +              mode->vtotal * 100;
 +      /* avoid overflow */
 +      info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
 +
 +      info->pixmap.size = 64*1024;
 +      info->pixmap.buf_align = 8;
 +      info->pixmap.access_align = 32;
 +      info->pixmap.flags = FB_PIXMAP_SYSTEM;
 +      info->pixmap.scan_align = 1;
 +
 +      DRM_DEBUG("fb depth is %d\n", fb->depth);
 +      DRM_DEBUG("   pitch is %d\n", fb->pitch);
 +      switch(fb->depth) {
 +      case 8:
 +                info->var.red.offset = 0;
 +                info->var.green.offset = 0;
 +                info->var.blue.offset = 0;
 +                info->var.red.length = 8; /* 8bit DAC */
 +                info->var.green.length = 8;
 +                info->var.blue.length = 8;
 +                info->var.transp.offset = 0;
 +                info->var.transp.length = 0;
 +                break;
 +      case 15:
 +                info->var.red.offset = 10;
 +                info->var.green.offset = 5;
 +                info->var.blue.offset = 0;
 +                info->var.red.length = info->var.green.length =
 +                        info->var.blue.length = 5;
 +                info->var.transp.offset = 15;
 +                info->var.transp.length = 1;
 +                break;
 +      case 16:
 +                info->var.red.offset = 11;
 +                info->var.green.offset = 5;
 +                info->var.blue.offset = 0;
 +                info->var.red.length = 5;
 +                info->var.green.length = 6;
 +                info->var.blue.length = 5;
 +                info->var.transp.offset = 0;
 +              break;
 +      case 24:
 +                info->var.red.offset = 16;
 +                info->var.green.offset = 8;
 +                info->var.blue.offset = 0;
 +                info->var.red.length = info->var.green.length =
 +                        info->var.blue.length = 8;
 +                info->var.transp.offset = 0;
 +                info->var.transp.length = 0;
 +                break;
 +      case 32:
 +              info->var.red.offset = 16;
 +              info->var.green.offset = 8;
 +              info->var.blue.offset = 0;
 +              info->var.red.length = info->var.green.length =
 +                      info->var.blue.length = 8;
 +              info->var.transp.offset = 24;
 +              info->var.transp.length = 8;
 +              break;
 +      default:
 +              break;
 +      }
 +
 +      if (register_framebuffer(info) < 0)
 +              return -EINVAL;
 +
 +      printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
 +             info->fix.id);
 +      return 0;
 +}
 +EXPORT_SYMBOL(intelfb_probe);
 +
 +int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc)
 +{
 +      struct drm_framebuffer *fb = crtc->fb;
 +      struct fb_info *info = fb->fbdev;
 +      
 +      if (info) {
 +              unregister_framebuffer(info);
 +              framebuffer_release(info);
 +              drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base);
 +              drm_bo_usage_deref_unlocked(&fb->bo);
 +              drm_framebuffer_destroy(fb);
 +      }
 +      return 0;
 +}
 +EXPORT_SYMBOL(intelfb_remove);
 +MODULE_LICENSE("GPL");
@@@ -1069,23 -980,12 +1074,24 @@@ struct drm_mode_mode_cmd 
  #define DRM_IOCTL_BO_UNMAP              DRM_IOWR(0xd0, struct drm_bo_handle_arg)
  #define DRM_IOCTL_BO_REFERENCE          DRM_IOWR(0xd1, struct drm_bo_reference_info_arg)
  #define DRM_IOCTL_BO_UNREFERENCE        DRM_IOWR(0xd2, struct drm_bo_handle_arg)
- #define DRM_IOCTL_BO_OP                 DRM_IOWR(0xd3, struct drm_bo_op_arg)
+ #define DRM_IOCTL_BO_SETSTATUS          DRM_IOWR(0xd3, struct drm_bo_map_wait_idle_arg)
  #define DRM_IOCTL_BO_INFO               DRM_IOWR(0xd4, struct drm_bo_reference_info_arg)
  #define DRM_IOCTL_BO_WAIT_IDLE          DRM_IOWR(0xd5, struct drm_bo_map_wait_idle_arg)
- #define DRM_IOCTL_BO_SET_PIN          DRM_IOWR(0xd6, struct drm_bo_set_pin_arg)
+ #define DRM_IOCTL_BO_VERSION          DRM_IOR(0xd6, struct drm_bo_version_arg)
  
 +#define DRM_IOCTL_MODE_GETRESOURCES     DRM_IOWR(0xA0, struct drm_mode_card_res)
 +#define DRM_IOCTL_MODE_GETCRTC          DRM_IOWR(0xA1, struct drm_mode_crtc)
 +#define DRM_IOCTL_MODE_GETOUTPUT        DRM_IOWR(0xA2, struct drm_mode_get_output)
 +#define DRM_IOCTL_MODE_SETCRTC          DRM_IOWR(0xA3, struct drm_mode_crtc)
 +#define DRM_IOCTL_MODE_ADDFB            DRM_IOWR(0xA4, struct drm_mode_fb_cmd)
 +#define DRM_IOCTL_MODE_RMFB             DRM_IOWR(0xA5, unsigned int)
 +#define DRM_IOCTL_MODE_GETFB            DRM_IOWR(0xA6, struct drm_mode_fb_cmd)
 +
 +#define DRM_IOCTL_MODE_ADDMODE         DRM_IOWR(0xA7, struct drm_mode_modeinfo)
 +#define DRM_IOCTL_MODE_RMMODE          DRM_IOWR(0xA8, unsigned int)
 +#define DRM_IOCTL_MODE_ATTACHMODE      DRM_IOWR(0xA9, struct drm_mode_mode_cmd)
 +#define DRM_IOCTL_MODE_DETACHMODE      DRM_IOWR(0xAA, struct drm_mode_mode_cmd)
  /*@}*/
  
  /**
Simple merge
Simple merge
index 8e419b8,0000000..3b43c72
mode 100644,000000..100644
--- /dev/null
@@@ -1,334 -1,0 +1,329 @@@
-               DRM_ERROR("Unable to allocate ring buffer\n");
-               return -EINVAL;
-       }
-       ret = drm_bo_set_pin(dev, dev_priv->ring_buffer, 1);
-       if (ret < 0) {
-               DRM_ERROR("Unable to pin ring buffer\n");
 +/*
 + * Copyright (c) 2007 Intel Corporation
 + *   Jesse Barnes <jesse.barnes@intel.com>
 + *
 + * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
 + *                   2004 Sylvain Meyer
 + *
 + * GPL/BSD dual license
 + */
 +#include "drmP.h"
 +#include "drm.h"
 +#include "drm_sarea.h"
 +#include "i915_drm.h"
 +#include "i915_drv.h"
 +
 +/**
 + * i915_probe_agp - get AGP bootup configuration
 + * @pdev: PCI device
 + * @aperture_size: returns AGP aperture configured size
 + * @preallocated_size: returns size of BIOS preallocated AGP space
 + *
 + * Since Intel integrated graphics are UMA, the BIOS has to set aside
 + * some RAM for the framebuffer at early boot.  This code figures out
 + * how much was set aside so we can use it for our own purposes.
 + */
 +int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size,
 +                 unsigned long *preallocated_size)
 +{
 +      struct pci_dev *bridge_dev;
 +      u16 tmp = 0;
 +      unsigned long overhead;
 +
 +      bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
 +      if (!bridge_dev) {
 +              DRM_ERROR("bridge device not found\n");
 +              return -1;
 +      }
 +
 +      /* Get the fb aperture size and "stolen" memory amount. */
 +      pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
 +      pci_dev_put(bridge_dev);
 +
 +      *aperture_size = 1024 * 1024;
 +      *preallocated_size = 1024 * 1024;
 +
 +      switch (pdev->device) {
 +      case PCI_DEVICE_ID_INTEL_82830_CGC:
 +      case PCI_DEVICE_ID_INTEL_82845G_IG:
 +      case PCI_DEVICE_ID_INTEL_82855GM_IG:
 +      case PCI_DEVICE_ID_INTEL_82865_IG:
 +              if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
 +                      *aperture_size *= 64;
 +              else
 +                      *aperture_size *= 128;
 +              break;
 +      default:
 +              /* 9xx supports large sizes, just look at the length */
 +              *aperture_size = pci_resource_len(pdev, 2);
 +              break;
 +      }
 +
 +      /*
 +       * Some of the preallocated space is taken by the GTT
 +       * and popup.  GTT is 1K per MB of aperture size, and popup is 4K.
 +       */
 +      overhead = (*aperture_size / 1024) + 4096;
 +      switch (tmp & INTEL_855_GMCH_GMS_MASK) {
 +      case INTEL_855_GMCH_GMS_STOLEN_1M:
 +              break; /* 1M already */
 +      case INTEL_855_GMCH_GMS_STOLEN_4M:
 +              *preallocated_size *= 4;
 +              break;
 +      case INTEL_855_GMCH_GMS_STOLEN_8M:
 +              *preallocated_size *= 8;
 +              break;
 +      case INTEL_855_GMCH_GMS_STOLEN_16M:
 +              *preallocated_size *= 16;
 +              break;
 +      case INTEL_855_GMCH_GMS_STOLEN_32M:
 +              *preallocated_size *= 32;
 +              break;
 +      case INTEL_915G_GMCH_GMS_STOLEN_48M:
 +              *preallocated_size *= 48;
 +              break;
 +      case INTEL_915G_GMCH_GMS_STOLEN_64M:
 +              *preallocated_size *= 64;
 +              break;
 +      case INTEL_855_GMCH_GMS_DISABLED:
 +              DRM_ERROR("video memory is disabled\n");
 +              return -1;
 +      default:
 +              DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
 +                      tmp & INTEL_855_GMCH_GMS_MASK);
 +              return -1;
 +      }
 +      *preallocated_size -= overhead;
 +
 +      return 0;
 +}
 +
 +/**
 + * i915_driver_load - setup chip and create an initial config
 + * @dev: DRM device
 + * @flags: startup flags
 + *
 + * The driver load routine has to do several things:
 + *   - drive output discovery via intel_modeset_init()
 + *   - initialize the memory manager
 + *   - allocate initial config memory
 + *   - setup the DRM framebuffer with the allocated memory
 + */
 +int i915_driver_load(struct drm_device *dev, unsigned long flags)
 +{
 +      struct drm_i915_private *dev_priv;
 +      unsigned long agp_size, prealloc_size;
 +      unsigned long sareapage;
 +      int size, ret;
 +
 +      dev_priv = drm_alloc(sizeof(struct drm_i915_private), DRM_MEM_DRIVER);
 +      if (dev_priv == NULL)
 +              return -ENOMEM;
 +
 +      memset(dev_priv, 0, sizeof(struct drm_i915_private));
 +      dev->dev_private = (void *)dev_priv;
 +//    dev_priv->flags = flags;
 +
 +      /* i915 has 4 more counters */
 +      dev->counters += 4;
 +      dev->types[6] = _DRM_STAT_IRQ;
 +      dev->types[7] = _DRM_STAT_PRIMARY;
 +      dev->types[8] = _DRM_STAT_SECONDARY;
 +      dev->types[9] = _DRM_STAT_DMA;
 +
 +      if (IS_I9XX(dev)) {
 +              dev_priv->mmiobase = drm_get_resource_start(dev, 0);
 +              dev_priv->mmiolen = drm_get_resource_len(dev, 0);
 +              dev->mode_config.fb_base =
 +                      drm_get_resource_start(dev, 2) & 0xff000000;
 +      } else if (drm_get_resource_start(dev, 1)) {
 +              dev_priv->mmiobase = drm_get_resource_start(dev, 1);
 +              dev_priv->mmiolen = drm_get_resource_len(dev, 1);
 +              dev->mode_config.fb_base =
 +                      drm_get_resource_start(dev, 0) & 0xff000000;
 +      } else {
 +              DRM_ERROR("Unable to find MMIO registers\n");
 +              return -ENODEV;
 +      }
 +
 +      DRM_DEBUG("fb_base: 0x%08lx\n", dev->mode_config.fb_base);
 +
 +      ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen,
 +                       _DRM_REGISTERS, _DRM_READ_ONLY|_DRM_DRIVER, &dev_priv->mmio_map);
 +      if (ret != 0) {
 +              DRM_ERROR("Cannot add mapping for MMIO registers\n");
 +              return ret;
 +      }
 +
 +      /* prebuild the SAREA */
 +      sareapage = max(SAREA_MAX, PAGE_SIZE);
 +      ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER,
 +                       &dev_priv->sarea);
 +      if (ret) {
 +              DRM_ERROR("SAREA setup failed\n");
 +              return ret;
 +      }
 +
 +      init_waitqueue_head(&dev->lock.lock_queue);
 +
 +      /* FIXME: assume sarea_priv is right after SAREA */
 +        dev_priv->sarea_priv = dev_priv->sarea->handle + sizeof(struct drm_sarea);
 +
 +      /*
 +       * Initialize the memory manager for local and AGP space
 +       */
 +      drm_bo_driver_init(dev);
 +
 +      i915_probe_agp(dev->pdev, &agp_size, &prealloc_size);
 +      printk("setting up %ld bytes of VRAM space\n", prealloc_size);
 +      printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size));
 +      drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT);
 +      drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT);
 +
 +      I915_WRITE(LP_RING + RING_LEN, 0);
 +      I915_WRITE(LP_RING + RING_HEAD, 0);
 +      I915_WRITE(LP_RING + RING_TAIL, 0);
 +
 +      size = PRIMARY_RINGBUFFER_SIZE;
 +      ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel,
 +                                     DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
 +                                     DRM_BO_FLAG_MEM_VRAM |
++                                     DRM_BO_FLAG_NO_EVICT |
 +                                     DRM_BO_HINT_DONT_FENCE, 0, 0x1, 0,
 +                                     &dev_priv->ring_buffer);
 +      if (ret < 0) {
++              DRM_ERROR("Unable to allocate or pin ring buffer\n");
 +              return -EINVAL;
 +      }
 +
 +      /* remap the buffer object properly */
 +      dev_priv->ring.Start = dev_priv->ring_buffer->offset;
 +      dev_priv->ring.End = dev_priv->ring.Start + size;
 +      dev_priv->ring.Size = size;
 +      dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
 +
 +      /* FIXME: need wrapper with PCI mem checks */
 +      ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem,
 +                                (void **) &dev_priv->ring.virtual_start);
 +      if (ret)
 +              DRM_ERROR("error mapping ring buffer: %d\n", ret);
 +
 +      DRM_DEBUG("ring start %08lX, %p, %08lX\n", dev_priv->ring.Start,
 +                dev_priv->ring.virtual_start, dev_priv->ring.Size);
 +
 +      dev_priv->sarea_priv->pf_current_page = 0;
 +
 +      memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size);
 +
 +      I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start);
 +      I915_WRITE(LP_RING + RING_LEN,
 +                 ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) |
 +                 (RING_NO_REPORT | RING_VALID));
 +
 +      /* We are using separate values as placeholders for mechanisms for
 +       * private backbuffer/depthbuffer usage.
 +       */
 +      dev_priv->use_mi_batchbuffer_start = 0;
 +
 +      /* Allow hardware batchbuffers unless told otherwise.
 +       */
 +      dev_priv->allow_batchbuffer = 1;
 +
 +      /* Program Hardware Status Page */
 +      if (!IS_G33(dev)) {
 +              dev_priv->status_page_dmah = 
 +                      drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
 +
 +              if (!dev_priv->status_page_dmah) {
 +                      dev->dev_private = (void *)dev_priv;
 +                      i915_dma_cleanup(dev);
 +                      DRM_ERROR("Can not allocate hardware status page\n");
 +                      return -ENOMEM;
 +              }
 +              dev_priv->hw_status_page = 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);
 +
 +              I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page);
 +      }
 +      DRM_DEBUG("Enabled hardware status page\n");
 +
 +      intel_modeset_init(dev);
 +      drm_initial_config(dev, false);
 +
 +      return 0;
 +}
 +
 +int i915_driver_unload(struct drm_device *dev)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +
 +      if (dev_priv->ring.virtual_start) {
 +              drm_core_ioremapfree(&dev_priv->ring.map, dev);
 +      }
 +
 +      if (dev_priv->status_page_dmah) {
 +              drm_pci_free(dev, dev_priv->status_page_dmah);
 +              dev_priv->status_page_dmah = NULL;
 +              dev_priv->hw_status_page = NULL;
 +              dev_priv->dma_status_page = 0;
 +              /* Need to rewrite hardware status page */
 +              I915_WRITE(I915REG_HWS_PGA, 0x1ffff000);
 +      }
 +
 +      if (dev_priv->status_gfx_addr) {
 +              dev_priv->status_gfx_addr = 0;
 +              drm_core_ioremapfree(&dev_priv->hws_map, dev);
 +              I915_WRITE(I915REG_HWS_PGA, 0x1ffff000);
 +      }
 +
 +      I915_WRITE(LP_RING + RING_LEN, 0);
 +
 +      intel_modeset_cleanup(dev);
 +
 +      drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem,
 +                          dev_priv->ring.virtual_start);
 +
 +      DRM_DEBUG("usage is %d\n", atomic_read(&dev_priv->ring_buffer->usage));
 +      mutex_lock(&dev->struct_mutex);
 +      drm_bo_usage_deref_locked(&dev_priv->ring_buffer);
 +
 +      if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) {
 +              DRM_ERROR("Memory manager type 3 not clean. "
 +                        "Delaying takedown\n");
 +      }
 +      if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) {
 +              DRM_ERROR("Memory manager type 3 not clean. "
 +                        "Delaying takedown\n");
 +      }
 +      mutex_unlock(&dev->struct_mutex);
 +
 +      drm_bo_driver_finish(dev);
 +
 +        DRM_DEBUG("%p, %p\n", dev_priv->mmio_map, dev_priv->sarea);
 +        drm_rmmap(dev, dev_priv->mmio_map);
 +        drm_rmmap(dev, dev_priv->sarea);
 +
 +      drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
 +
 +      dev->dev_private = NULL;
 +      return 0;
 +}
 +
 +void i915_driver_lastclose(struct drm_device *dev)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +
 +      i915_do_cleanup_pageflip(dev);
 +      //i915_mem_takedown(&(dev_priv->agp_heap));
 +      i915_dma_cleanup(dev);
 +}
 +
 +void i915_driver_preclose(struct drm_device *dev, struct drm_file *filp)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +
 +      //i915_mem_release(dev, filp, dev_priv->agp_heap);
 +}
 +