Merge branch 'drm-for-2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/airlie...
Linus Torvalds [Fri, 21 May 2010 18:14:52 +0000 (11:14 -0700)]
* 'drm-for-2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (207 commits)
  drm/radeon/kms/pm/r600: select the mid clock mode for single head low profile
  drm/radeon: fix power supply kconfig interaction.
  drm/radeon/kms: record object that have been list reserved
  drm/radeon: AGP memory is only I/O if the aperture can be mapped by the CPU.
  drm/radeon/kms: don't default display priority to high on rs4xx
  drm/edid: fix typo in 1600x1200@75 mode
  drm/nouveau: fix i2c-related init table handlers
  drm/nouveau: support init table i2c device identifier 0x81
  drm/nouveau: ensure we've parsed i2c table entry for INIT_*I2C* handlers
  drm/nouveau: display error message for any failed init table opcode
  drm/nouveau: fix init table handlers to return proper error codes
  drm/nv50: support fractional feedback divider on newer chips
  drm/nv50: fix monitor detection on certain chipsets
  drm/nv50: store full dcb i2c entry from vbios
  drm/nv50: fix suspend/resume with DP outputs
  drm/nv50: output calculated crtc pll when debugging on
  drm/nouveau: dump pll limits entries when debugging is on
  drm/nouveau: bios parser fixes for eDP boards
  drm/nouveau: fix a nouveau_bo dereference after it's been destroyed
  drm/nv40: remove some completed ctxprog TODOs
  ...

169 files changed:
Documentation/DocBook/Makefile
Documentation/DocBook/drm.tmpl [new file with mode: 0644]
arch/x86/include/asm/cacheflush.h
arch/x86/mm/pageattr.c
drivers/char/agp/agp.h
drivers/char/agp/ali-agp.c
drivers/char/agp/amd-k7-agp.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/ati-agp.c
drivers/char/agp/efficeon-agp.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-agp.h [new file with mode: 0644]
drivers/char/agp/intel-gtt.c [new file with mode: 0644]
drivers/char/agp/nvidia-agp.c
drivers/char/agp/sis-agp.c
drivers/char/agp/uninorth-agp.c
drivers/char/agp/via-agp.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/drm_auth.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_dma.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/dvo.h
drivers/gpu/drm/i915/dvo_ch7017.c
drivers/gpu/drm/i915/dvo_ch7xxx.c
drivers/gpu/drm/i915/dvo_ivch.c
drivers/gpu/drm/i915/dvo_sil164.c
drivers/gpu/drm/i915/dvo_tfp410.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_debug.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/i915_trace.h
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_debugfs.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_encoder.h
drivers/gpu/drm/nouveau/nouveau_fb.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_fbcon.h
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_grctx.c
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_irq.c
drivers/gpu/drm/nouveau/nouveau_reg.h
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv04_fbcon.c
drivers/gpu/drm/nouveau/nv04_graph.c
drivers/gpu/drm/nouveau/nv40_grctx.c
drivers/gpu/drm/nouveau/nv50_calc.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_fbcon.c
drivers/gpu/drm/nouveau/nv50_sor.c
drivers/gpu/drm/radeon/atombios.h
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_reg.h
drivers/gpu/drm/radeon/evergreend.h [new file with mode: 0644]
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r100d.h
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r300d.h
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r500_reg.h
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_audio.c
drivers/gpu/drm/radeon/r600_blit_kms.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/r600_reg.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_bios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_object.h
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_reg.h
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs600d.h
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv515d.h
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/savage/savage_bci.c
drivers/gpu/drm/ttm/Makefile
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/ttm/ttm_memory.c
drivers/gpu/drm/ttm/ttm_page_alloc.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
drivers/gpu/vga/Kconfig
drivers/video/efifb.c
drivers/video/fbmem.c
drivers/video/fbsysfs.c
drivers/video/offb.c
drivers/video/vesafb.c
drivers/video/vga16fb.c
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_edid.h
include/drm/drm_fb_helper.h
include/drm/drm_fixed.h [moved from drivers/gpu/drm/radeon/radeon_fixed.h with 60% similarity]
include/drm/radeon_drm.h
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/drm/ttm/ttm_page_alloc.h [new file with mode: 0644]
include/linux/fb.h

index 325cfd1..c7e5dc7 100644 (file)
@@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
            genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
            mac80211.xml debugobjects.xml sh.xml regulator.xml \
            alsa-driver-api.xml writing-an-alsa-driver.xml \
-           tracepoint.xml media.xml
+           tracepoint.xml media.xml drm.xml
 
 ###
 # The build process is as follows (targets):
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
new file mode 100644 (file)
index 0000000..7583dc7
--- /dev/null
@@ -0,0 +1,839 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="drmDevelopersGuide">
+  <bookinfo>
+    <title>Linux DRM Developer's Guide</title>
+
+    <copyright>
+      <year>2008-2009</year>
+      <holder>
+       Intel Corporation (Jesse Barnes &lt;jesse.barnes@intel.com&gt;)
+      </holder>
+    </copyright>
+
+    <legalnotice>
+      <para>
+       The contents of this file may be used under the terms of the GNU
+       General Public License version 2 (the "GPL") as distributed in
+       the kernel source COPYING file.
+      </para>
+    </legalnotice>
+  </bookinfo>
+
+<toc></toc>
+
+  <!-- Introduction -->
+
+  <chapter id="drmIntroduction">
+    <title>Introduction</title>
+    <para>
+      The Linux DRM layer contains code intended to support the needs
+      of complex graphics devices, usually containing programmable
+      pipelines well suited to 3D graphics acceleration.  Graphics
+      drivers in the kernel can make use of DRM functions to make
+      tasks like memory management, interrupt handling and DMA easier,
+      and provide a uniform interface to applications.
+    </para>
+    <para>
+      A note on versions: this guide covers features found in the DRM
+      tree, including the TTM memory manager, output configuration and
+      mode setting, and the new vblank internals, in addition to all
+      the regular features found in current kernels.
+    </para>
+    <para>
+      [Insert diagram of typical DRM stack here]
+    </para>
+  </chapter>
+
+  <!-- Internals -->
+
+  <chapter id="drmInternals">
+    <title>DRM Internals</title>
+    <para>
+      This chapter documents DRM internals relevant to driver authors
+      and developers working to add support for the latest features to
+      existing drivers.
+    </para>
+    <para>
+      First, we'll go over some typical driver initialization
+      requirements, like setting up command buffers, creating an
+      initial output configuration, and initializing core services.
+      Subsequent sections will cover core internals in more detail,
+      providing implementation notes and examples.
+    </para>
+    <para>
+      The DRM layer provides several services to graphics drivers,
+      many of them driven by the application interfaces it provides
+      through libdrm, the library that wraps most of the DRM ioctls.
+      These include vblank event handling, memory
+      management, output management, framebuffer management, command
+      submission &amp; fencing, suspend/resume support, and DMA
+      services.
+    </para>
+    <para>
+      The core of every DRM driver is struct drm_device.  Drivers
+      will typically statically initialize a drm_device structure,
+      then pass it to drm_init() at load time.
+    </para>
+
+  <!-- Internals: driver init -->
+
+  <sect1>
+    <title>Driver initialization</title>
+    <para>
+      Before calling the DRM initialization routines, the driver must
+      first create and fill out a struct drm_device structure.
+    </para>
+    <programlisting>
+      static struct drm_driver driver = {
+       /* don't use mtrr's here, the Xserver or user space app should
+        * deal with them for intel hardware.
+        */
+       .driver_features =
+           DRIVER_USE_AGP | DRIVER_REQUIRE_AGP |
+           DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_MODESET,
+       .load = i915_driver_load,
+       .unload = i915_driver_unload,
+       .firstopen = i915_driver_firstopen,
+       .lastclose = i915_driver_lastclose,
+       .preclose = i915_driver_preclose,
+       .save = i915_save,
+       .restore = i915_restore,
+       .device_is_agp = i915_driver_device_is_agp,
+       .get_vblank_counter = i915_get_vblank_counter,
+       .enable_vblank = i915_enable_vblank,
+       .disable_vblank = i915_disable_vblank,
+       .irq_preinstall = i915_driver_irq_preinstall,
+       .irq_postinstall = i915_driver_irq_postinstall,
+       .irq_uninstall = i915_driver_irq_uninstall,
+       .irq_handler = i915_driver_irq_handler,
+       .reclaim_buffers = drm_core_reclaim_buffers,
+       .get_map_ofs = drm_core_get_map_ofs,
+       .get_reg_ofs = drm_core_get_reg_ofs,
+       .fb_probe = intelfb_probe,
+       .fb_remove = intelfb_remove,
+       .fb_resize = intelfb_resize,
+       .master_create = i915_master_create,
+       .master_destroy = i915_master_destroy,
+#if defined(CONFIG_DEBUG_FS)
+       .debugfs_init = i915_debugfs_init,
+       .debugfs_cleanup = i915_debugfs_cleanup,
+#endif
+       .gem_init_object = i915_gem_init_object,
+       .gem_free_object = i915_gem_free_object,
+       .gem_vm_ops = &amp;i915_gem_vm_ops,
+       .ioctls = i915_ioctls,
+       .fops = {
+               .owner = THIS_MODULE,
+               .open = drm_open,
+               .release = drm_release,
+               .ioctl = drm_ioctl,
+               .mmap = drm_mmap,
+               .poll = drm_poll,
+               .fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+               .compat_ioctl = i915_compat_ioctl,
+#endif
+               },
+       .pci_driver = {
+               .name = DRIVER_NAME,
+               .id_table = pciidlist,
+               .probe = probe,
+               .remove = __devexit_p(drm_cleanup_pci),
+               },
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL,
+      };
+    </programlisting>
+    <para>
+      In the example above, taken from the i915 DRM driver, the driver
+      sets several flags indicating what core features it supports.
+      We'll go over the individual callbacks in later sections.  Since
+      flags indicate which features your driver supports to the DRM
+      core, you need to set most of them prior to calling drm_init().  Some,
+      like DRIVER_MODESET can be set later based on user supplied parameters,
+      but that's the exception rather than the rule.
+    </para>
+    <variablelist>
+      <title>Driver flags</title>
+      <varlistentry>
+       <term>DRIVER_USE_AGP</term>
+       <listitem><para>
+           Driver uses AGP interface
+       </para></listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>DRIVER_REQUIRE_AGP</term>
+       <listitem><para>
+           Driver needs AGP interface to function.
+       </para></listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>DRIVER_USE_MTRR</term>
+       <listitem>
+         <para>
+           Driver uses MTRR interface for mapping memory.  Deprecated.
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>DRIVER_PCI_DMA</term>
+       <listitem><para>
+           Driver is capable of PCI DMA.  Deprecated.
+       </para></listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>DRIVER_SG</term>
+       <listitem><para>
+           Driver can perform scatter/gather DMA.  Deprecated.
+       </para></listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>DRIVER_HAVE_DMA</term>
+       <listitem><para>Driver supports DMA.  Deprecated.</para></listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>DRIVER_HAVE_IRQ</term><term>DRIVER_IRQ_SHARED</term>
+       <listitem>
+         <para>
+           DRIVER_HAVE_IRQ indicates whether the driver has a IRQ
+           handler, DRIVER_IRQ_SHARED indicates whether the device &amp;
+           handler support shared IRQs (note that this is required of
+           PCI drivers).
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>DRIVER_DMA_QUEUE</term>
+       <listitem>
+         <para>
+           If the driver queues DMA requests and completes them
+           asynchronously, this flag should be set.  Deprecated.
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>DRIVER_FB_DMA</term>
+       <listitem>
+         <para>
+           Driver supports DMA to/from the framebuffer.  Deprecated.
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>DRIVER_MODESET</term>
+       <listitem>
+         <para>
+           Driver supports mode setting interfaces.
+         </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+    <para>
+      In this specific case, the driver requires AGP and supports
+      IRQs.  DMA, as we'll see, is handled by device specific ioctls
+      in this case.  It also supports the kernel mode setting APIs, though
+      unlike in the actual i915 driver source, this example unconditionally
+      exports KMS capability.
+    </para>
+  </sect1>
+
+  <!-- Internals: driver load -->
+
+  <sect1>
+    <title>Driver load</title>
+    <para>
+      In the previous section, we saw what a typical drm_driver
+      structure might look like.  One of the more important fields in
+      the structure is the hook for the load function.
+    </para>
+    <programlisting>
+      static struct drm_driver driver = {
+       ...
+       .load = i915_driver_load,
+        ...
+      };
+    </programlisting>
+    <para>
+      The load function has many responsibilities: allocating a driver
+      private structure, specifying supported performance counters,
+      configuring the device (e.g. mapping registers &amp; command
+      buffers), initializing the memory manager, and setting up the
+      initial output configuration.
+    </para>
+    <para>
+      Note that the tasks performed at driver load time must not
+      conflict with DRM client requirements.  For instance, if user
+      level mode setting drivers are in use, it would be problematic
+      to perform output discovery &amp; configuration at load time.
+      Likewise, if pre-memory management aware user level drivers are
+      in use, memory management and command buffer setup may need to
+      be omitted.  These requirements are driver specific, and care
+      needs to be taken to keep both old and new applications and
+      libraries working.  The i915 driver supports the "modeset"
+      module parameter to control whether advanced features are
+      enabled at load time or in legacy fashion.  If compatibility is
+      a concern (e.g. with drivers converted over to the new interfaces
+      from the old ones), care must be taken to prevent incompatible
+      device initialization and control with the currently active
+      userspace drivers.
+    </para>
+
+    <sect2>
+      <title>Driver private &amp; performance counters</title>
+      <para>
+       The driver private hangs off the main drm_device structure and
+       can be used for tracking various device specific bits of
+       information, like register offsets, command buffer status,
+       register state for suspend/resume, etc.  At load time, a
+       driver can simply allocate one and set drm_device.dev_priv
+       appropriately; at unload the driver can free it and set
+       drm_device.dev_priv to NULL.
+      </para>
+      <para>
+       The DRM supports several counters which can be used for rough
+       performance characterization.  Note that the DRM stat counter
+       system is not often used by applications, and supporting
+       additional counters is completely optional.
+      </para>
+      <para>
+       These interfaces are deprecated and should not be used.  If performance
+       monitoring is desired, the developer should investigate and
+       potentially enhance the kernel perf and tracing infrastructure to export
+       GPU related performance information to performance monitoring
+       tools and applications.
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>Configuring the device</title>
+      <para>
+       Obviously, device configuration will be device specific.
+       However, there are several common operations: finding a
+       device's PCI resources, mapping them, and potentially setting
+       up an IRQ handler.
+      </para>
+      <para>
+       Finding &amp; mapping resources is fairly straightforward.  The
+       DRM wrapper functions, drm_get_resource_start() and
+       drm_get_resource_len() can be used to find BARs on the given
+       drm_device struct.  Once those values have been retrieved, the
+       driver load function can call drm_addmap() to create a new
+       mapping for the BAR in question.  Note you'll probably want a
+       drm_local_map_t in your driver private structure to track any
+       mappings you create.
+<!-- !Fdrivers/gpu/drm/drm_bufs.c drm_get_resource_* -->
+<!-- !Finclude/drm/drmP.h drm_local_map_t -->
+      </para>
+      <para>
+       if compatibility with other operating systems isn't a concern
+       (DRM drivers can run under various BSD variants and OpenSolaris),
+       native Linux calls can be used for the above, e.g. pci_resource_*
+       and iomap*/iounmap.  See the Linux device driver book for more
+       info.
+      </para>
+      <para>
+       Once you have a register map, you can use the DRM_READn() and
+       DRM_WRITEn() macros to access the registers on your device, or
+       use driver specific versions to offset into your MMIO space
+       relative to a driver specific base pointer (see I915_READ for
+       example).
+      </para>
+      <para>
+       If your device supports interrupt generation, you may want to
+       setup an interrupt handler at driver load time as well.  This
+       is done using the drm_irq_install() function.  If your device
+       supports vertical blank interrupts, it should call
+       drm_vblank_init() to initialize the core vblank handling code before
+       enabling interrupts on your device.  This ensures the vblank related
+       structures are allocated and allows the core to handle vblank events.
+      </para>
+<!--!Fdrivers/char/drm/drm_irq.c drm_irq_install-->
+      <para>
+       Once your interrupt handler is registered (it'll use your
+       drm_driver.irq_handler as the actual interrupt handling
+       function), you can safely enable interrupts on your device,
+       assuming any other state your interrupt handler uses is also
+       initialized.
+      </para>
+      <para>
+       Another task that may be necessary during configuration is
+       mapping the video BIOS.  On many devices, the VBIOS describes
+       device configuration, LCD panel timings (if any), and contains
+       flags indicating device state.  Mapping the BIOS can be done
+       using the pci_map_rom() call, a convenience function that
+       takes care of mapping the actual ROM, whether it has been
+       shadowed into memory (typically at address 0xc0000) or exists
+       on the PCI device in the ROM BAR.  Note that once you've
+       mapped the ROM and extracted any necessary information, be
+       sure to unmap it; on many devices the ROM address decoder is
+       shared with other BARs, so leaving it mapped can cause
+       undesired behavior like hangs or memory corruption.
+<!--!Fdrivers/pci/rom.c pci_map_rom-->
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>Memory manager initialization</title>
+      <para>
+       In order to allocate command buffers, cursor memory, scanout
+       buffers, etc., as well as support the latest features provided
+       by packages like Mesa and the X.Org X server, your driver
+       should support a memory manager.
+      </para>
+      <para>
+       If your driver supports memory management (it should!), you'll
+       need to set that up at load time as well.  How you intialize
+       it depends on which memory manager you're using, TTM or GEM.
+      </para>
+      <sect3>
+       <title>TTM initialization</title>
+       <para>
+         TTM (for Translation Table Manager) manages video memory and
+         aperture space for graphics devices. TTM supports both UMA devices
+         and devices with dedicated video RAM (VRAM), i.e. most discrete
+         graphics devices.  If your device has dedicated RAM, supporting
+         TTM is desireable.  TTM also integrates tightly with your
+         driver specific buffer execution function.  See the radeon
+         driver for examples.
+       </para>
+       <para>
+         The core TTM structure is the ttm_bo_driver struct.  It contains
+         several fields with function pointers for initializing the TTM,
+         allocating and freeing memory, waiting for command completion
+         and fence synchronization, and memory migration.  See the
+         radeon_ttm.c file for an example of usage.
+       </para>
+       <para>
+         The ttm_global_reference structure is made up of several fields:
+       </para>
+       <programlisting>
+         struct ttm_global_reference {
+               enum ttm_global_types global_type;
+               size_t size;
+               void *object;
+               int (*init) (struct ttm_global_reference *);
+               void (*release) (struct ttm_global_reference *);
+         };
+       </programlisting>
+       <para>
+         There should be one global reference structure for your memory
+         manager as a whole, and there will be others for each object
+         created by the memory manager at runtime.  Your global TTM should
+         have a type of TTM_GLOBAL_TTM_MEM.  The size field for the global
+         object should be sizeof(struct ttm_mem_global), and the init and
+         release hooks should point at your driver specific init and
+         release routines, which will probably eventually call
+         ttm_mem_global_init and ttm_mem_global_release respectively.
+       </para>
+       <para>
+         Once your global TTM accounting structure is set up and initialized
+         (done by calling ttm_global_item_ref on the global object you
+         just created), you'll need to create a buffer object TTM to
+         provide a pool for buffer object allocation by clients and the
+         kernel itself.  The type of this object should be TTM_GLOBAL_TTM_BO,
+         and its size should be sizeof(struct ttm_bo_global).  Again,
+         driver specific init and release functions can be provided,
+         likely eventually calling ttm_bo_global_init and
+         ttm_bo_global_release, respectively.  Also like the previous
+         object, ttm_global_item_ref is used to create an initial reference
+         count for the TTM, which will call your initalization function.
+       </para>
+      </sect3>
+      <sect3>
+       <title>GEM initialization</title>
+       <para>
+         GEM is an alternative to TTM, designed specifically for UMA
+         devices.  It has simpler initialization and execution requirements
+         than TTM, but has no VRAM management capability.  Core GEM
+         initialization is comprised of a basic drm_mm_init call to create
+         a GTT DRM MM object, which provides an address space pool for
+         object allocation.  In a KMS configuration, the driver will
+         need to allocate and initialize a command ring buffer following
+         basic GEM initialization.  Most UMA devices have a so-called
+         "stolen" memory region, which provides space for the initial
+         framebuffer and large, contiguous memory regions required by the
+         device.  This space is not typically managed by GEM, and must
+         be initialized separately into its own DRM MM object.
+       </para>
+       <para>
+         Initialization will be driver specific, and will depend on
+         the architecture of the device.  In the case of Intel
+         integrated graphics chips like 965GM, GEM initialization can
+         be done by calling the internal GEM init function,
+         i915_gem_do_init().  Since the 965GM is a UMA device
+         (i.e. it doesn't have dedicated VRAM), GEM will manage
+         making regular RAM available for GPU operations.  Memory set
+         aside by the BIOS (called "stolen" memory by the i915
+         driver) will be managed by the DRM memrange allocator; the
+         rest of the aperture will be managed by GEM.
+         <programlisting>
+           /* Basic memrange allocator for stolen space (aka vram) */
+           drm_memrange_init(&amp;dev_priv->vram, 0, prealloc_size);
+           /* Let GEM Manage from end of prealloc space to end of aperture */
+           i915_gem_do_init(dev, prealloc_size, agp_size);
+         </programlisting>
+<!--!Edrivers/char/drm/drm_memrange.c-->
+       </para>
+       <para>
+         Once the memory manager has been set up, we can allocate the
+         command buffer.  In the i915 case, this is also done with a
+         GEM function, i915_gem_init_ringbuffer().
+       </para>
+      </sect3>
+    </sect2>
+
+    <sect2>
+      <title>Output configuration</title>
+      <para>
+       The final initialization task is output configuration.  This involves
+       finding and initializing the CRTCs, encoders and connectors
+       for your device, creating an initial configuration and
+       registering a framebuffer console driver.
+      </para>
+      <sect3>
+       <title>Output discovery and initialization</title>
+       <para>
+         Several core functions exist to create CRTCs, encoders and
+         connectors, namely drm_crtc_init(), drm_connector_init() and
+         drm_encoder_init(), along with several "helper" functions to
+         perform common tasks.
+       </para>
+       <para>
+         Connectors should be registered with sysfs once they've been
+         detected and initialized, using the
+         drm_sysfs_connector_add() function.  Likewise, when they're
+         removed from the system, they should be destroyed with
+         drm_sysfs_connector_remove().
+       </para>
+       <programlisting>
+<![CDATA[
+void intel_crt_init(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+       struct intel_output *intel_output;
+
+       intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
+       if (!intel_output)
+               return;
+
+       connector = &intel_output->base;
+       drm_connector_init(dev, &intel_output->base,
+                          &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
+
+       drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs,
+                        DRM_MODE_ENCODER_DAC);
+
+       drm_mode_connector_attach_encoder(&intel_output->base,
+                                         &intel_output->enc);
+
+       /* Set up the DDC bus. */
+       intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A");
+       if (!intel_output->ddc_bus) {
+               dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
+                          "failed.\n");
+               return;
+       }
+
+       intel_output->type = INTEL_OUTPUT_ANALOG;
+       connector->interlace_allowed = 0;
+       connector->doublescan_allowed = 0;
+
+       drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs);
+       drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
+
+       drm_sysfs_connector_add(connector);
+}
+]]>
+       </programlisting>
+       <para>
+         In the example above (again, taken from the i915 driver), a
+         CRT connector and encoder combination is created.  A device
+         specific i2c bus is also created, for fetching EDID data and
+         performing monitor detection.  Once the process is complete,
+         the new connector is regsitered with sysfs, to make its
+         properties available to applications.
+       </para>
+       <sect4>
+         <title>Helper functions and core functions</title>
+         <para>
+           Since many PC-class graphics devices have similar display output
+           designs, the DRM provides a set of helper functions to make
+           output management easier.  The core helper routines handle
+           encoder re-routing and disabling of unused functions following
+           mode set.  Using the helpers is optional, but recommended for
+           devices with PC-style architectures (i.e. a set of display planes
+           for feeding pixels to encoders which are in turn routed to
+           connectors).  Devices with more complex requirements needing
+           finer grained management can opt to use the core callbacks
+           directly.
+         </para>
+         <para>
+           [Insert typical diagram here.]  [Insert OMAP style config here.]
+         </para>
+       </sect4>
+       <para>
+         For each encoder, CRTC and connector, several functions must
+         be provided, depending on the object type.  Encoder objects
+         need should provide a DPMS (basically on/off) function, mode fixup
+         (for converting requested modes into native hardware timings),
+         and prepare, set and commit functions for use by the core DRM
+         helper functions.  Connector helpers need to provide mode fetch and
+         validity functions as well as an encoder matching function for
+         returing an ideal encoder for a given connector.  The core
+         connector functions include a DPMS callback, (deprecated)
+         save/restore routines, detection, mode probing, property handling,
+         and cleanup functions.
+       </para>
+<!--!Edrivers/char/drm/drm_crtc.h-->
+<!--!Edrivers/char/drm/drm_crtc.c-->
+<!--!Edrivers/char/drm/drm_crtc_helper.c-->
+      </sect3>
+    </sect2>
+  </sect1>
+
+  <!-- Internals: vblank handling -->
+
+  <sect1>
+    <title>VBlank event handling</title>
+    <para>
+      The DRM core exposes two vertical blank related ioctls:
+      DRM_IOCTL_WAIT_VBLANK and DRM_IOCTL_MODESET_CTL.
+<!--!Edrivers/char/drm/drm_irq.c-->
+    </para>
+    <para>
+      DRM_IOCTL_WAIT_VBLANK takes a struct drm_wait_vblank structure
+      as its argument, and is used to block or request a signal when a
+      specified vblank event occurs.
+    </para>
+    <para>
+      DRM_IOCTL_MODESET_CTL should be called by application level
+      drivers before and after mode setting, since on many devices the
+      vertical blank counter will be reset at that time.  Internally,
+      the DRM snapshots the last vblank count when the ioctl is called
+      with the _DRM_PRE_MODESET command so that the counter won't go
+      backwards (which is dealt with when _DRM_POST_MODESET is used).
+    </para>
+    <para>
+      To support the functions above, the DRM core provides several
+      helper functions for tracking vertical blank counters, and
+      requires drivers to provide several callbacks:
+      get_vblank_counter(), enable_vblank() and disable_vblank().  The
+      core uses get_vblank_counter() to keep the counter accurate
+      across interrupt disable periods.  It should return the current
+      vertical blank event count, which is often tracked in a device
+      register.  The enable and disable vblank callbacks should enable
+      and disable vertical blank interrupts, respectively.  In the
+      absence of DRM clients waiting on vblank events, the core DRM
+      code will use the disable_vblank() function to disable
+      interrupts, which saves power.  They'll be re-enabled again when
+      a client calls the vblank wait ioctl above.
+    </para>
+    <para>
+      Devices that don't provide a count register can simply use an
+      internal atomic counter incremented on every vertical blank
+      interrupt, and can make their enable and disable vblank
+      functions into no-ops.
+    </para>
+  </sect1>
+
+  <sect1>
+    <title>Memory management</title>
+    <para>
+      The memory manager lies at the heart of many DRM operations, and
+      is also required to support advanced client features like OpenGL
+      pbuffers.  The DRM currently contains two memory managers, TTM
+      and GEM.
+    </para>
+
+    <sect2>
+      <title>The Translation Table Manager (TTM)</title>
+      <para>
+       TTM was developed by Tungsten Graphics, primarily by Thomas
+       Hellström, and is intended to be a flexible, high performance
+       graphics memory manager.
+      </para>
+      <para>
+       Drivers wishing to support TTM must fill out a drm_bo_driver
+       structure.
+      </para>
+      <para>
+       TTM design background and information belongs here.
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>The Graphics Execution Manager (GEM)</title>
+      <para>
+       GEM is an Intel project, authored by Eric Anholt and Keith
+       Packard.  It provides simpler interfaces than TTM, and is well
+       suited for UMA devices.
+      </para>
+      <para>
+       GEM-enabled drivers must provide gem_init_object() and
+       gem_free_object() callbacks to support the core memory
+       allocation routines.  They should also provide several driver
+       specific ioctls to support command execution, pinning, buffer
+       read &amp; write, mapping, and domain ownership transfers.
+      </para>
+      <para>
+       On a fundamental level, GEM involves several operations: memory
+       allocation and freeing, command execution, and aperture management
+       at command execution time.  Buffer object allocation is relatively
+       straightforward and largely provided by Linux's shmem layer, which
+       provides memory to back each object.  When mapped into the GTT
+       or used in a command buffer, the backing pages for an object are
+       flushed to memory and marked write combined so as to be coherent
+       with the GPU.  Likewise, when the GPU finishes rendering to an object,
+       if the CPU accesses it, it must be made coherent with the CPU's view
+       of memory, usually involving GPU cache flushing of various kinds.
+       This core CPU&lt;-&gt;GPU coherency management is provided by the GEM
+       set domain function, which evaluates an object's current domain and
+       performs any necessary flushing or synchronization to put the object
+       into the desired coherency domain (note that the object may be busy,
+       i.e. an active render target; in that case the set domain function
+       will block the client and wait for rendering to complete before
+       performing any necessary flushing operations).
+      </para>
+      <para>
+       Perhaps the most important GEM function is providing a command
+       execution interface to clients.  Client programs construct command
+       buffers containing references to previously allocated memory objects
+       and submit them to GEM.  At that point, GEM will take care to bind
+       all the objects into the GTT, execute the buffer, and provide
+       necessary synchronization between clients accessing the same buffers.
+       This often involves evicting some objects from the GTT and re-binding
+       others (a fairly expensive operation), and providing relocation
+       support which hides fixed GTT offsets from clients.  Clients must
+       take care not to submit command buffers that reference more objects
+       than can fit in the GTT or GEM will reject them and no rendering
+       will occur.  Similarly, if several objects in the buffer require
+       fence registers to be allocated for correct rendering (e.g. 2D blits
+       on pre-965 chips), care must be taken not to require more fence
+       registers than are available to the client.  Such resource management
+       should be abstracted from the client in libdrm.
+      </para>
+    </sect2>
+
+  </sect1>
+
+  <!-- Output management -->
+  <sect1>
+    <title>Output management</title>
+    <para>
+      At the core of the DRM output management code is a set of
+      structures representing CRTCs, encoders and connectors.
+    </para>
+    <para>
+      A CRTC is an abstraction representing a part of the chip that
+      contains a pointer to a scanout buffer.  Therefore, the number
+      of CRTCs available determines how many independent scanout
+      buffers can be active at any given time.  The CRTC structure
+      contains several fields to support this: a pointer to some video
+      memory, a display mode, and an (x, y) offset into the video
+      memory to support panning or configurations where one piece of
+      video memory spans multiple CRTCs.
+    </para>
+    <para>
+      An encoder takes pixel data from a CRTC and converts it to a
+      format suitable for any attached connectors.  On some devices,
+      it may be possible to have a CRTC send data to more than one
+      encoder.  In that case, both encoders would receive data from
+      the same scanout buffer, resulting in a "cloned" display
+      configuration across the connectors attached to each encoder.
+    </para>
+    <para>
+      A connector is the final destination for pixel data on a device,
+      and usually connects directly to an external display device like
+      a monitor or laptop panel.  A connector can only be attached to
+      one encoder at a time.  The connector is also the structure
+      where information about the attached display is kept, so it
+      contains fields for display data, EDID data, DPMS &amp;
+      connection status, and information about modes supported on the
+      attached displays.
+    </para>
+<!--!Edrivers/char/drm/drm_crtc.c-->
+  </sect1>
+
+  <sect1>
+    <title>Framebuffer management</title>
+    <para>
+      In order to set a mode on a given CRTC, encoder and connector
+      configuration, clients need to provide a framebuffer object which
+      will provide a source of pixels for the CRTC to deliver to the encoder(s)
+      and ultimately the connector(s) in the configuration.  A framebuffer
+      is fundamentally a driver specific memory object, made into an opaque
+      handle by the DRM addfb function.  Once an fb has been created this
+      way it can be passed to the KMS mode setting routines for use in
+      a configuration.
+    </para>
+  </sect1>
+
+  <sect1>
+    <title>Command submission &amp; fencing</title>
+    <para>
+      This should cover a few device specific command submission
+      implementations.
+    </para>
+  </sect1>
+
+  <sect1>
+    <title>Suspend/resume</title>
+    <para>
+      The DRM core provides some suspend/resume code, but drivers
+      wanting full suspend/resume support should provide save() and
+      restore() functions.  These will be called at suspend,
+      hibernate, or resume time, and should perform any state save or
+      restore required by your device across suspend or hibernate
+      states.
+    </para>
+  </sect1>
+
+  <sect1>
+    <title>DMA services</title>
+    <para>
+      This should cover how DMA mapping etc. is supported by the core.
+      These functions are deprecated and should not be used.
+    </para>
+  </sect1>
+  </chapter>
+
+  <!-- External interfaces -->
+
+  <chapter id="drmExternals">
+    <title>Userland interfaces</title>
+    <para>
+      The DRM core exports several interfaces to applications,
+      generally intended to be used through corresponding libdrm
+      wrapper functions.  In addition, drivers export device specific
+      interfaces for use by userspace drivers &amp; device aware
+      applications through ioctls and sysfs files.
+    </para>
+    <para>
+      External interfaces include: memory mapping, context management,
+      DMA operations, AGP management, vblank control, fence
+      management, memory management, and output management.
+    </para>
+    <para>
+      Cover generic ioctls and sysfs layout here.  Only need high
+      level info, since man pages will cover the rest.
+    </para>
+  </chapter>
+
+  <!-- API reference -->
+
+  <appendix id="drmDriverApi">
+    <title>DRM Driver API</title>
+    <para>
+      Include auto-generated API reference here (need to reference it
+      from paragraphs above too).
+    </para>
+  </appendix>
+
+</book>
index c70068d..63e35ec 100644 (file)
@@ -145,9 +145,11 @@ int set_memory_np(unsigned long addr, int numpages);
 int set_memory_4k(unsigned long addr, int numpages);
 
 int set_memory_array_uc(unsigned long *addr, int addrinarray);
+int set_memory_array_wc(unsigned long *addr, int addrinarray);
 int set_memory_array_wb(unsigned long *addr, int addrinarray);
 
 int set_pages_array_uc(struct page **pages, int addrinarray);
+int set_pages_array_wc(struct page **pages, int addrinarray);
 int set_pages_array_wb(struct page **pages, int addrinarray);
 
 /*
index 28195c3..532e793 100644 (file)
@@ -997,7 +997,8 @@ out_err:
 }
 EXPORT_SYMBOL(set_memory_uc);
 
-int set_memory_array_uc(unsigned long *addr, int addrinarray)
+int _set_memory_array(unsigned long *addr, int addrinarray,
+               unsigned long new_type)
 {
        int i, j;
        int ret;
@@ -1007,13 +1008,19 @@ int set_memory_array_uc(unsigned long *addr, int addrinarray)
         */
        for (i = 0; i < addrinarray; i++) {
                ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE,
-                                       _PAGE_CACHE_UC_MINUS, NULL);
+                                       new_type, NULL);
                if (ret)
                        goto out_free;
        }
 
        ret = change_page_attr_set(addr, addrinarray,
                                    __pgprot(_PAGE_CACHE_UC_MINUS), 1);
+
+       if (!ret && new_type == _PAGE_CACHE_WC)
+               ret = change_page_attr_set_clr(addr, addrinarray,
+                                              __pgprot(_PAGE_CACHE_WC),
+                                              __pgprot(_PAGE_CACHE_MASK),
+                                              0, CPA_ARRAY, NULL);
        if (ret)
                goto out_free;
 
@@ -1025,8 +1032,19 @@ out_free:
 
        return ret;
 }
+
+int set_memory_array_uc(unsigned long *addr, int addrinarray)
+{
+       return _set_memory_array(addr, addrinarray, _PAGE_CACHE_UC_MINUS);
+}
 EXPORT_SYMBOL(set_memory_array_uc);
 
+int set_memory_array_wc(unsigned long *addr, int addrinarray)
+{
+       return _set_memory_array(addr, addrinarray, _PAGE_CACHE_WC);
+}
+EXPORT_SYMBOL(set_memory_array_wc);
+
 int _set_memory_wc(unsigned long addr, int numpages)
 {
        int ret;
@@ -1153,26 +1171,34 @@ int set_pages_uc(struct page *page, int numpages)
 }
 EXPORT_SYMBOL(set_pages_uc);
 
-int set_pages_array_uc(struct page **pages, int addrinarray)
+static int _set_pages_array(struct page **pages, int addrinarray,
+               unsigned long new_type)
 {
        unsigned long start;
        unsigned long end;
        int i;
        int free_idx;
+       int ret;
 
        for (i = 0; i < addrinarray; i++) {
                if (PageHighMem(pages[i]))
                        continue;
                start = page_to_pfn(pages[i]) << PAGE_SHIFT;
                end = start + PAGE_SIZE;
-               if (reserve_memtype(start, end, _PAGE_CACHE_UC_MINUS, NULL))
+               if (reserve_memtype(start, end, new_type, NULL))
                        goto err_out;
        }
 
-       if (cpa_set_pages_array(pages, addrinarray,
-                       __pgprot(_PAGE_CACHE_UC_MINUS)) == 0) {
-               return 0; /* Success */
-       }
+       ret = cpa_set_pages_array(pages, addrinarray,
+                       __pgprot(_PAGE_CACHE_UC_MINUS));
+       if (!ret && new_type == _PAGE_CACHE_WC)
+               ret = change_page_attr_set_clr(NULL, addrinarray,
+                                              __pgprot(_PAGE_CACHE_WC),
+                                              __pgprot(_PAGE_CACHE_MASK),
+                                              0, CPA_PAGES_ARRAY, pages);
+       if (ret)
+               goto err_out;
+       return 0; /* Success */
 err_out:
        free_idx = i;
        for (i = 0; i < free_idx; i++) {
@@ -1184,8 +1210,19 @@ err_out:
        }
        return -EINVAL;
 }
+
+int set_pages_array_uc(struct page **pages, int addrinarray)
+{
+       return _set_pages_array(pages, addrinarray, _PAGE_CACHE_UC_MINUS);
+}
 EXPORT_SYMBOL(set_pages_array_uc);
 
+int set_pages_array_wc(struct page **pages, int addrinarray)
+{
+       return _set_pages_array(pages, addrinarray, _PAGE_CACHE_WC);
+}
+EXPORT_SYMBOL(set_pages_array_wc);
+
 int set_pages_wb(struct page *page, int numpages)
 {
        unsigned long addr = (unsigned long)page_address(page);
index 870f12c..1204909 100644 (file)
@@ -178,86 +178,6 @@ struct agp_bridge_data {
 #define PGE_EMPTY(b, p)        (!(p) || (p) == (unsigned long) (b)->scratch_page)
 
 
-/* Intel registers */
-#define INTEL_APSIZE   0xb4
-#define INTEL_ATTBASE  0xb8
-#define INTEL_AGPCTRL  0xb0
-#define INTEL_NBXCFG   0x50
-#define INTEL_ERRSTS   0x91
-
-/* Intel i830 registers */
-#define I830_GMCH_CTRL                 0x52
-#define I830_GMCH_ENABLED              0x4
-#define I830_GMCH_MEM_MASK             0x1
-#define I830_GMCH_MEM_64M              0x1
-#define I830_GMCH_MEM_128M             0
-#define I830_GMCH_GMS_MASK             0x70
-#define I830_GMCH_GMS_DISABLED         0x00
-#define I830_GMCH_GMS_LOCAL            0x10
-#define I830_GMCH_GMS_STOLEN_512       0x20
-#define I830_GMCH_GMS_STOLEN_1024      0x30
-#define I830_GMCH_GMS_STOLEN_8192      0x40
-#define I830_RDRAM_CHANNEL_TYPE                0x03010
-#define I830_RDRAM_ND(x)               (((x) & 0x20) >> 5)
-#define I830_RDRAM_DDT(x)              (((x) & 0x18) >> 3)
-
-/* This one is for I830MP w. an external graphic card */
-#define INTEL_I830_ERRSTS      0x92
-
-/* Intel 855GM/852GM registers */
-#define I855_GMCH_GMS_MASK             0xF0
-#define I855_GMCH_GMS_STOLEN_0M                0x0
-#define I855_GMCH_GMS_STOLEN_1M                (0x1 << 4)
-#define I855_GMCH_GMS_STOLEN_4M                (0x2 << 4)
-#define I855_GMCH_GMS_STOLEN_8M                (0x3 << 4)
-#define I855_GMCH_GMS_STOLEN_16M       (0x4 << 4)
-#define I855_GMCH_GMS_STOLEN_32M       (0x5 << 4)
-#define I85X_CAPID                     0x44
-#define I85X_VARIANT_MASK              0x7
-#define I85X_VARIANT_SHIFT             5
-#define I855_GME                       0x0
-#define I855_GM                                0x4
-#define I852_GME                       0x2
-#define I852_GM                                0x5
-
-/* Intel i845 registers */
-#define INTEL_I845_AGPM                0x51
-#define INTEL_I845_ERRSTS      0xc8
-
-/* Intel i860 registers */
-#define INTEL_I860_MCHCFG      0x50
-#define INTEL_I860_ERRSTS      0xc8
-
-/* Intel i810 registers */
-#define I810_GMADDR            0x10
-#define I810_MMADDR            0x14
-#define I810_PTE_BASE          0x10000
-#define I810_PTE_MAIN_UNCACHED 0x00000000
-#define I810_PTE_LOCAL         0x00000002
-#define I810_PTE_VALID         0x00000001
-#define I830_PTE_SYSTEM_CACHED  0x00000006
-#define I810_SMRAM_MISCC       0x70
-#define I810_GFX_MEM_WIN_SIZE  0x00010000
-#define I810_GFX_MEM_WIN_32M   0x00010000
-#define I810_GMS               0x000000c0
-#define I810_GMS_DISABLE       0x00000000
-#define I810_PGETBL_CTL                0x2020
-#define I810_PGETBL_ENABLED    0x00000001
-#define I965_PGETBL_SIZE_MASK  0x0000000e
-#define I965_PGETBL_SIZE_512KB (0 << 1)
-#define I965_PGETBL_SIZE_256KB (1 << 1)
-#define I965_PGETBL_SIZE_128KB (2 << 1)
-#define I965_PGETBL_SIZE_1MB   (3 << 1)
-#define I965_PGETBL_SIZE_2MB   (4 << 1)
-#define I965_PGETBL_SIZE_1_5MB (5 << 1)
-#define G33_PGETBL_SIZE_MASK    (3 << 8)
-#define G33_PGETBL_SIZE_1M      (1 << 8)
-#define G33_PGETBL_SIZE_2M      (2 << 8)
-
-#define I810_DRAM_CTL          0x3000
-#define I810_DRAM_ROW_0                0x00000001
-#define I810_DRAM_ROW_0_SDRAM  0x00000001
-
 struct agp_device_ids {
        unsigned short device_id; /* first, to make table easier to read */
        enum chipset_type chipset;
index d2ce68f..fd79351 100644 (file)
@@ -204,6 +204,7 @@ static const struct agp_bridge_driver ali_generic_bridge = {
        .aperture_sizes         = ali_generic_sizes,
        .size_type              = U32_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = ali_configure,
        .fetch_size             = ali_fetch_size,
        .cleanup                = ali_cleanup,
index a7637d7..b6b1568 100644 (file)
@@ -142,6 +142,7 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)
 {
        struct aper_size_info_lvl2 *value;
        struct amd_page_map page_dir;
+       unsigned long __iomem *cur_gatt;
        unsigned long addr;
        int retval;
        u32 temp;
@@ -178,6 +179,13 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)
                readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));        /* PCI Posting. */
        }
 
+       for (i = 0; i < value->num_entries; i++) {
+               addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
+               cur_gatt = GET_GATT(addr);
+               writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
+               readl(cur_gatt+GET_GATT_OFF(addr));     /* PCI Posting. */
+       }
+
        return 0;
 }
 
@@ -375,6 +383,7 @@ static const struct agp_bridge_driver amd_irongate_driver = {
        .aperture_sizes         = amd_irongate_sizes,
        .size_type              = LVL2_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = amd_irongate_configure,
        .fetch_size             = amd_irongate_fetch_size,
        .cleanup                = amd_irongate_cleanup,
index fd50ead..67ea3a6 100644 (file)
@@ -210,6 +210,7 @@ static const struct agp_bridge_driver amd_8151_driver = {
        .aperture_sizes         = amd_8151_sizes,
        .size_type              = U32_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = amd_8151_configure,
        .fetch_size             = amd64_fetch_size,
        .cleanup                = amd64_cleanup,
@@ -499,6 +500,10 @@ static int __devinit agp_amd64_probe(struct pci_dev *pdev,
        u8 cap_ptr;
        int err;
 
+       /* The Highlander principle */
+       if (agp_bridges_found)
+               return -ENODEV;
+
        cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
        if (!cap_ptr)
                return -ENODEV;
@@ -562,6 +567,8 @@ static void __devexit agp_amd64_remove(struct pci_dev *pdev)
                           amd64_aperture_sizes[bridge->aperture_size_idx].size);
        agp_remove_bridge(bridge);
        agp_put_bridge(bridge);
+
+       agp_bridges_found--;
 }
 
 #ifdef CONFIG_PM
@@ -709,6 +716,11 @@ static struct pci_device_id agp_amd64_pci_table[] = {
 
 MODULE_DEVICE_TABLE(pci, agp_amd64_pci_table);
 
+static DEFINE_PCI_DEVICE_TABLE(agp_amd64_pci_promisc_table) = {
+       { PCI_DEVICE_CLASS(0, 0) },
+       { }
+};
+
 static struct pci_driver agp_amd64_pci_driver = {
        .name           = "agpgart-amd64",
        .id_table       = agp_amd64_pci_table,
@@ -734,7 +746,6 @@ int __init agp_amd64_init(void)
                return err;
 
        if (agp_bridges_found == 0) {
-               struct pci_dev *dev;
                if (!agp_try_unsupported && !agp_try_unsupported_boot) {
                        printk(KERN_INFO PFX "No supported AGP bridge found.\n");
 #ifdef MODULE
@@ -750,17 +761,10 @@ int __init agp_amd64_init(void)
                        return -ENODEV;
 
                /* Look for any AGP bridge */
-               dev = NULL;
-               err = -ENODEV;
-               for_each_pci_dev(dev) {
-                       if (!pci_find_capability(dev, PCI_CAP_ID_AGP))
-                               continue;
-                       /* Only one bridge supported right now */
-                       if (agp_amd64_probe(dev, NULL) == 0) {
-                               err = 0;
-                               break;
-                       }
-               }
+               agp_amd64_pci_driver.id_table = agp_amd64_pci_promisc_table;
+               err = driver_attach(&agp_amd64_pci_driver.driver);
+               if (err == 0 && agp_bridges_found == 0)
+                       err = -ENODEV;
        }
        return err;
 }
index 3b2ecbe..dc30e22 100644 (file)
@@ -341,6 +341,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge)
 {
        struct aper_size_info_lvl2 *value;
        struct ati_page_map page_dir;
+       unsigned long __iomem *cur_gatt;
        unsigned long addr;
        int retval;
        u32 temp;
@@ -395,6 +396,12 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge)
                readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));        /* PCI Posting. */
        }
 
+       for (i = 0; i < value->num_entries; i++) {
+               addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
+               cur_gatt = GET_GATT(addr);
+               writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
+       }
+
        return 0;
 }
 
@@ -415,6 +422,7 @@ static const struct agp_bridge_driver ati_generic_bridge = {
        .aperture_sizes         = ati_generic_sizes,
        .size_type              = LVL2_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = ati_configure,
        .fetch_size             = ati_fetch_size,
        .cleanup                = ati_cleanup,
index 793f39e..aa109cb 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/page-flags.h>
 #include <linux/mm.h>
 #include "agp.h"
+#include "intel-agp.h"
 
 /*
  * The real differences to the generic AGP code is
index aa4248e..d836a71 100644 (file)
 #include <linux/agp_backend.h>
 #include <asm/smp.h>
 #include "agp.h"
+#include "intel-agp.h"
+
+#include "intel-gtt.c"
 
 int intel_agp_enabled;
 EXPORT_SYMBOL(intel_agp_enabled);
 
-/*
- * If we have Intel graphics, we're not going to have anything other than
- * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
- * on the Intel IOMMU support (CONFIG_DMAR).
- * Only newer chipsets need to bother with this, of course.
- */
-#ifdef CONFIG_DMAR
-#define USE_PCI_DMA_API 1
-#endif
-
-#define PCI_DEVICE_ID_INTEL_E7221_HB   0x2588
-#define PCI_DEVICE_ID_INTEL_E7221_IG   0x258a
-#define PCI_DEVICE_ID_INTEL_82946GZ_HB      0x2970
-#define PCI_DEVICE_ID_INTEL_82946GZ_IG      0x2972
-#define PCI_DEVICE_ID_INTEL_82G35_HB     0x2980
-#define PCI_DEVICE_ID_INTEL_82G35_IG     0x2982
-#define PCI_DEVICE_ID_INTEL_82965Q_HB       0x2990
-#define PCI_DEVICE_ID_INTEL_82965Q_IG       0x2992
-#define PCI_DEVICE_ID_INTEL_82965G_HB       0x29A0
-#define PCI_DEVICE_ID_INTEL_82965G_IG       0x29A2
-#define PCI_DEVICE_ID_INTEL_82965GM_HB      0x2A00
-#define PCI_DEVICE_ID_INTEL_82965GM_IG      0x2A02
-#define PCI_DEVICE_ID_INTEL_82965GME_HB     0x2A10
-#define PCI_DEVICE_ID_INTEL_82965GME_IG     0x2A12
-#define PCI_DEVICE_ID_INTEL_82945GME_HB     0x27AC
-#define PCI_DEVICE_ID_INTEL_82945GME_IG     0x27AE
-#define PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB        0xA010
-#define PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG        0xA011
-#define PCI_DEVICE_ID_INTEL_PINEVIEW_HB         0xA000
-#define PCI_DEVICE_ID_INTEL_PINEVIEW_IG         0xA001
-#define PCI_DEVICE_ID_INTEL_G33_HB          0x29C0
-#define PCI_DEVICE_ID_INTEL_G33_IG          0x29C2
-#define PCI_DEVICE_ID_INTEL_Q35_HB          0x29B0
-#define PCI_DEVICE_ID_INTEL_Q35_IG          0x29B2
-#define PCI_DEVICE_ID_INTEL_Q33_HB          0x29D0
-#define PCI_DEVICE_ID_INTEL_Q33_IG          0x29D2
-#define PCI_DEVICE_ID_INTEL_B43_HB          0x2E40
-#define PCI_DEVICE_ID_INTEL_B43_IG          0x2E42
-#define PCI_DEVICE_ID_INTEL_GM45_HB         0x2A40
-#define PCI_DEVICE_ID_INTEL_GM45_IG         0x2A42
-#define PCI_DEVICE_ID_INTEL_EAGLELAKE_HB        0x2E00
-#define PCI_DEVICE_ID_INTEL_EAGLELAKE_IG        0x2E02
-#define PCI_DEVICE_ID_INTEL_Q45_HB          0x2E10
-#define PCI_DEVICE_ID_INTEL_Q45_IG          0x2E12
-#define PCI_DEVICE_ID_INTEL_G45_HB          0x2E20
-#define PCI_DEVICE_ID_INTEL_G45_IG          0x2E22
-#define PCI_DEVICE_ID_INTEL_G41_HB          0x2E30
-#define PCI_DEVICE_ID_INTEL_G41_IG          0x2E32
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB          0x0040
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG          0x0042
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB          0x0044
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB         0x0062
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB    0x006a
-#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG          0x0046
-#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB  0x0100
-#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG  0x0102
-#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB  0x0104
-#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG  0x0106
-
-/* cover 915 and 945 variants */
-#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
-
-#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
-                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
-
-#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
-
-#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
-               IS_SNB)
-
-extern int agp_memory_reserved;
-
-
-/* Intel 815 register */
-#define INTEL_815_APCONT       0x51
-#define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF
-
-/* Intel i820 registers */
-#define INTEL_I820_RDCR                0x51
-#define INTEL_I820_ERRSTS      0xc8
-
-/* Intel i840 registers */
-#define INTEL_I840_MCHCFG      0x50
-#define INTEL_I840_ERRSTS      0xc8
-
-/* Intel i850 registers */
-#define INTEL_I850_MCHCFG      0x50
-#define INTEL_I850_ERRSTS      0xc8
-
-/* intel 915G registers */
-#define I915_GMADDR    0x18
-#define I915_MMADDR    0x10
-#define I915_PTEADDR   0x1C
-#define I915_GMCH_GMS_STOLEN_48M       (0x6 << 4)
-#define I915_GMCH_GMS_STOLEN_64M       (0x7 << 4)
-#define G33_GMCH_GMS_STOLEN_128M       (0x8 << 4)
-#define G33_GMCH_GMS_STOLEN_256M       (0x9 << 4)
-#define INTEL_GMCH_GMS_STOLEN_96M      (0xa << 4)
-#define INTEL_GMCH_GMS_STOLEN_160M     (0xb << 4)
-#define INTEL_GMCH_GMS_STOLEN_224M     (0xc << 4)
-#define INTEL_GMCH_GMS_STOLEN_352M     (0xd << 4)
-
-#define I915_IFPADDR    0x60
-
-/* Intel 965G registers */
-#define I965_MSAC 0x62
-#define I965_IFPADDR    0x70
-
-/* Intel 7505 registers */
-#define INTEL_I7505_APSIZE     0x74
-#define INTEL_I7505_NCAPID     0x60
-#define INTEL_I7505_NISTAT     0x6c
-#define INTEL_I7505_ATTBASE    0x78
-#define INTEL_I7505_ERRSTS     0x42
-#define INTEL_I7505_AGPCTRL    0x70
-#define INTEL_I7505_MCHCFG     0x50
-
-#define SNB_GMCH_CTRL  0x50
-#define SNB_GMCH_GMS_STOLEN_MASK       0xF8
-#define SNB_GMCH_GMS_STOLEN_32M                (1 << 3)
-#define SNB_GMCH_GMS_STOLEN_64M                (2 << 3)
-#define SNB_GMCH_GMS_STOLEN_96M                (3 << 3)
-#define SNB_GMCH_GMS_STOLEN_128M       (4 << 3)
-#define SNB_GMCH_GMS_STOLEN_160M       (5 << 3)
-#define SNB_GMCH_GMS_STOLEN_192M       (6 << 3)
-#define SNB_GMCH_GMS_STOLEN_224M       (7 << 3)
-#define SNB_GMCH_GMS_STOLEN_256M       (8 << 3)
-#define SNB_GMCH_GMS_STOLEN_288M       (9 << 3)
-#define SNB_GMCH_GMS_STOLEN_320M       (0xa << 3)
-#define SNB_GMCH_GMS_STOLEN_352M       (0xb << 3)
-#define SNB_GMCH_GMS_STOLEN_384M       (0xc << 3)
-#define SNB_GMCH_GMS_STOLEN_416M       (0xd << 3)
-#define SNB_GMCH_GMS_STOLEN_448M       (0xe << 3)
-#define SNB_GMCH_GMS_STOLEN_480M       (0xf << 3)
-#define SNB_GMCH_GMS_STOLEN_512M       (0x10 << 3)
-#define SNB_GTT_SIZE_0M                        (0 << 8)
-#define SNB_GTT_SIZE_1M                        (1 << 8)
-#define SNB_GTT_SIZE_2M                        (2 << 8)
-#define SNB_GTT_SIZE_MASK              (3 << 8)
-
-static const struct aper_size_info_fixed intel_i810_sizes[] =
-{
-       {64, 16384, 4},
-       /* The 32M mode still requires a 64k gatt */
-       {32, 8192, 4}
-};
-
-#define AGP_DCACHE_MEMORY      1
-#define AGP_PHYS_MEMORY                2
-#define INTEL_AGP_CACHED_MEMORY 3
-
-static struct gatt_mask intel_i810_masks[] =
-{
-       {.mask = I810_PTE_VALID, .type = 0},
-       {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
-       {.mask = I810_PTE_VALID, .type = 0},
-       {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED,
-        .type = INTEL_AGP_CACHED_MEMORY}
-};
-
-static struct _intel_private {
-       struct pci_dev *pcidev; /* device one */
-       u8 __iomem *registers;
-       u32 __iomem *gtt;               /* I915G */
-       int num_dcache_entries;
-       /* gtt_entries is the number of gtt entries that are already mapped
-        * to stolen memory.  Stolen memory is larger than the memory mapped
-        * through gtt_entries, as it includes some reserved space for the BIOS
-        * popup and for the GTT.
-        */
-       int gtt_entries;                        /* i830+ */
-       int gtt_total_size;
-       union {
-               void __iomem *i9xx_flush_page;
-               void *i8xx_flush_page;
-       };
-       struct page *i8xx_page;
-       struct resource ifp_resource;
-       int resource_valid;
-} intel_private;
-
-#ifdef USE_PCI_DMA_API
-static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
-{
-       *ret = pci_map_page(intel_private.pcidev, page, 0,
-                           PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-       if (pci_dma_mapping_error(intel_private.pcidev, *ret))
-               return -EINVAL;
-       return 0;
-}
-
-static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
-{
-       pci_unmap_page(intel_private.pcidev, dma,
-                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-}
-
-static void intel_agp_free_sglist(struct agp_memory *mem)
-{
-       struct sg_table st;
-
-       st.sgl = mem->sg_list;
-       st.orig_nents = st.nents = mem->page_count;
-
-       sg_free_table(&st);
-
-       mem->sg_list = NULL;
-       mem->num_sg = 0;
-}
-
-static int intel_agp_map_memory(struct agp_memory *mem)
-{
-       struct sg_table st;
-       struct scatterlist *sg;
-       int i;
-
-       DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
-
-       if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
-               return -ENOMEM;
-
-       mem->sg_list = sg = st.sgl;
-
-       for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
-               sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
-
-       mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
-                                mem->page_count, PCI_DMA_BIDIRECTIONAL);
-       if (unlikely(!mem->num_sg)) {
-               intel_agp_free_sglist(mem);
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-static void intel_agp_unmap_memory(struct agp_memory *mem)
-{
-       DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
-
-       pci_unmap_sg(intel_private.pcidev, mem->sg_list,
-                    mem->page_count, PCI_DMA_BIDIRECTIONAL);
-       intel_agp_free_sglist(mem);
-}
-
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
-                                       off_t pg_start, int mask_type)
-{
-       struct scatterlist *sg;
-       int i, j;
-
-       j = pg_start;
-
-       WARN_ON(!mem->num_sg);
-
-       if (mem->num_sg == mem->page_count) {
-               for_each_sg(mem->sg_list, sg, mem->page_count, i) {
-                       writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                       sg_dma_address(sg), mask_type),
-                                       intel_private.gtt+j);
-                       j++;
-               }
-       } else {
-               /* sg may merge pages, but we have to separate
-                * per-page addr for GTT */
-               unsigned int len, m;
-
-               for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
-                       len = sg_dma_len(sg) / PAGE_SIZE;
-                       for (m = 0; m < len; m++) {
-                               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                                                      sg_dma_address(sg) + m * PAGE_SIZE,
-                                                                      mask_type),
-                                      intel_private.gtt+j);
-                               j++;
-                       }
-               }
-       }
-       readl(intel_private.gtt+j-1);
-}
-
-#else
-
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
-                                       off_t pg_start, int mask_type)
-{
-       int i, j;
-       u32 cache_bits = 0;
-
-       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
-           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
-       {
-               cache_bits = I830_PTE_SYSTEM_CACHED;
-       }
-
-       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                               page_to_phys(mem->pages[i]), mask_type),
-                      intel_private.gtt+j);
-       }
-
-       readl(intel_private.gtt+j-1);
-}
-
-#endif
-
-static int intel_i810_fetch_size(void)
-{
-       u32 smram_miscc;
-       struct aper_size_info_fixed *values;
-
-       pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
-       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
-       if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
-               dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n");
-               return 0;
-       }
-       if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
-               agp_bridge->previous_size =
-                       agp_bridge->current_size = (void *) (values + 1);
-               agp_bridge->aperture_size_idx = 1;
-               return values[1].size;
-       } else {
-               agp_bridge->previous_size =
-                       agp_bridge->current_size = (void *) (values);
-               agp_bridge->aperture_size_idx = 0;
-               return values[0].size;
-       }
-
-       return 0;
-}
-
-static int intel_i810_configure(void)
-{
-       struct aper_size_info_fixed *current_size;
-       u32 temp;
-       int i;
-
-       current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-       if (!intel_private.registers) {
-               pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
-               temp &= 0xfff80000;
-
-               intel_private.registers = ioremap(temp, 128 * 4096);
-               if (!intel_private.registers) {
-                       dev_err(&intel_private.pcidev->dev,
-                               "can't remap memory\n");
-                       return -ENOMEM;
-               }
-       }
-
-       if ((readl(intel_private.registers+I810_DRAM_CTL)
-               & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
-               /* This will need to be dynamically assigned */
-               dev_info(&intel_private.pcidev->dev,
-                        "detected 4MB dedicated video ram\n");
-               intel_private.num_dcache_entries = 1024;
-       }
-       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
-       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-       writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
-
-       if (agp_bridge->driver->needs_scratch_page) {
-               for (i = 0; i < current_size->num_entries; i++) {
-                       writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
-               }
-               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */
-       }
-       global_cache_flush();
-       return 0;
-}
-
-static void intel_i810_cleanup(void)
-{
-       writel(0, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers); /* PCI Posting. */
-       iounmap(intel_private.registers);
-}
-
-static void intel_i810_tlbflush(struct agp_memory *mem)
-{
-       return;
-}
-
-static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
-{
-       return;
-}
-
-/* Exists to support ARGB cursors */
-static struct page *i8xx_alloc_pages(void)
-{
-       struct page *page;
-
-       page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
-       if (page == NULL)
-               return NULL;
-
-       if (set_pages_uc(page, 4) < 0) {
-               set_pages_wb(page, 4);
-               __free_pages(page, 2);
-               return NULL;
-       }
-       get_page(page);
-       atomic_inc(&agp_bridge->current_memory_agp);
-       return page;
-}
-
-static void i8xx_destroy_pages(struct page *page)
-{
-       if (page == NULL)
-               return;
-
-       set_pages_wb(page, 4);
-       put_page(page);
-       __free_pages(page, 2);
-       atomic_dec(&agp_bridge->current_memory_agp);
-}
-
-static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
-                                       int type)
-{
-       if (type < AGP_USER_TYPES)
-               return type;
-       else if (type == AGP_USER_CACHED_MEMORY)
-               return INTEL_AGP_CACHED_MEMORY;
-       else
-               return 0;
-}
-
-static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
-                               int type)
-{
-       int i, j, num_entries;
-       void *temp;
-       int ret = -EINVAL;
-       int mask_type;
-
-       if (mem->page_count == 0)
-               goto out;
-
-       temp = agp_bridge->current_size;
-       num_entries = A_SIZE_FIX(temp)->num_entries;
-
-       if ((pg_start + mem->page_count) > num_entries)
-               goto out_err;
-
-
-       for (j = pg_start; j < (pg_start + mem->page_count); j++) {
-               if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
-                       ret = -EBUSY;
-                       goto out_err;
-               }
-       }
-
-       if (type != mem->type)
-               goto out_err;
-
-       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-       switch (mask_type) {
-       case AGP_DCACHE_MEMORY:
-               if (!mem->is_flushed)
-                       global_cache_flush();
-               for (i = pg_start; i < (pg_start + mem->page_count); i++) {
-                       writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID,
-                              intel_private.registers+I810_PTE_BASE+(i*4));
-               }
-               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
-               break;
-       case AGP_PHYS_MEMORY:
-       case AGP_NORMAL_MEMORY:
-               if (!mem->is_flushed)
-                       global_cache_flush();
-               for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-                       writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                       page_to_phys(mem->pages[i]), mask_type),
-                              intel_private.registers+I810_PTE_BASE+(j*4));
-               }
-               readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
-               break;
-       default:
-               goto out_err;
-       }
-
-       agp_bridge->driver->tlb_flush(mem);
-out:
-       ret = 0;
-out_err:
-       mem->is_flushed = true;
-       return ret;
-}
-
-static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
-                               int type)
-{
-       int i;
-
-       if (mem->page_count == 0)
-               return 0;
-
-       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-               writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
-       }
-       readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
-
-       agp_bridge->driver->tlb_flush(mem);
-       return 0;
-}
-
-/*
- * The i810/i830 requires a physical address to program its mouse
- * pointer into hardware.
- * However the Xserver still writes to it through the agp aperture.
- */
-static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
-{
-       struct agp_memory *new;
-       struct page *page;
-
-       switch (pg_count) {
-       case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge);
-               break;
-       case 4:
-               /* kludge to get 4 physical pages for ARGB cursor */
-               page = i8xx_alloc_pages();
-               break;
-       default:
-               return NULL;
-       }
-
-       if (page == NULL)
-               return NULL;
-
-       new = agp_create_memory(pg_count);
-       if (new == NULL)
-               return NULL;
-
-       new->pages[0] = page;
-       if (pg_count == 4) {
-               /* kludge to get 4 physical pages for ARGB cursor */
-               new->pages[1] = new->pages[0] + 1;
-               new->pages[2] = new->pages[1] + 1;
-               new->pages[3] = new->pages[2] + 1;
-       }
-       new->page_count = pg_count;
-       new->num_scratch_pages = pg_count;
-       new->type = AGP_PHYS_MEMORY;
-       new->physical = page_to_phys(new->pages[0]);
-       return new;
-}
-
-static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
-{
-       struct agp_memory *new;
-
-       if (type == AGP_DCACHE_MEMORY) {
-               if (pg_count != intel_private.num_dcache_entries)
-                       return NULL;
-
-               new = agp_create_memory(1);
-               if (new == NULL)
-                       return NULL;
-
-               new->type = AGP_DCACHE_MEMORY;
-               new->page_count = pg_count;
-               new->num_scratch_pages = 0;
-               agp_free_page_array(new);
-               return new;
-       }
-       if (type == AGP_PHYS_MEMORY)
-               return alloc_agpphysmem_i8xx(pg_count, type);
-       return NULL;
-}
-
-static void intel_i810_free_by_type(struct agp_memory *curr)
-{
-       agp_free_key(curr->key);
-       if (curr->type == AGP_PHYS_MEMORY) {
-               if (curr->page_count == 4)
-                       i8xx_destroy_pages(curr->pages[0]);
-               else {
-                       agp_bridge->driver->agp_destroy_page(curr->pages[0],
-                                                            AGP_PAGE_DESTROY_UNMAP);
-                       agp_bridge->driver->agp_destroy_page(curr->pages[0],
-                                                            AGP_PAGE_DESTROY_FREE);
-               }
-               agp_free_page_array(curr);
-       }
-       kfree(curr);
-}
-
-static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
-                                           dma_addr_t addr, int type)
-{
-       /* Type checking must be done elsewhere */
-       return addr | bridge->driver->masks[type].mask;
-}
-
-static struct aper_size_info_fixed intel_i830_sizes[] =
-{
-       {128, 32768, 5},
-       /* The 64M mode still requires a 128k gatt */
-       {64, 16384, 5},
-       {256, 65536, 6},
-       {512, 131072, 7},
-};
-
-static void intel_i830_init_gtt_entries(void)
-{
-       u16 gmch_ctrl;
-       int gtt_entries = 0;
-       u8 rdct;
-       int local = 0;
-       static const int ddt[4] = { 0, 16, 32, 64 };
-       int size; /* reserved space (in kb) at the top of stolen memory */
-
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-
-       if (IS_I965) {
-               u32 pgetbl_ctl;
-               pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
-
-               /* The 965 has a field telling us the size of the GTT,
-                * which may be larger than what is necessary to map the
-                * aperture.
-                */
-               switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
-               case I965_PGETBL_SIZE_128KB:
-                       size = 128;
-                       break;
-               case I965_PGETBL_SIZE_256KB:
-                       size = 256;
-                       break;
-               case I965_PGETBL_SIZE_512KB:
-                       size = 512;
-                       break;
-               case I965_PGETBL_SIZE_1MB:
-                       size = 1024;
-                       break;
-               case I965_PGETBL_SIZE_2MB:
-                       size = 2048;
-                       break;
-               case I965_PGETBL_SIZE_1_5MB:
-                       size = 1024 + 512;
-                       break;
-               default:
-                       dev_info(&intel_private.pcidev->dev,
-                                "unknown page table size, assuming 512KB\n");
-                       size = 512;
-               }
-               size += 4; /* add in BIOS popup space */
-       } else if (IS_G33 && !IS_PINEVIEW) {
-       /* G33's GTT size defined in gmch_ctrl */
-               switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
-               case G33_PGETBL_SIZE_1M:
-                       size = 1024;
-                       break;
-               case G33_PGETBL_SIZE_2M:
-                       size = 2048;
-                       break;
-               default:
-                       dev_info(&agp_bridge->dev->dev,
-                                "unknown page table size 0x%x, assuming 512KB\n",
-                               (gmch_ctrl & G33_PGETBL_SIZE_MASK));
-                       size = 512;
-               }
-               size += 4;
-       } else if (IS_G4X || IS_PINEVIEW) {
-               /* On 4 series hardware, GTT stolen is separate from graphics
-                * stolen, ignore it in stolen gtt entries counting.  However,
-                * 4KB of the stolen memory doesn't get mapped to the GTT.
-                */
-               size = 4;
-       } else {
-               /* On previous hardware, the GTT size was just what was
-                * required to map the aperture.
-                */
-               size = agp_bridge->driver->fetch_size() + 4;
-       }
-
-       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
-           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
-               switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
-               case I830_GMCH_GMS_STOLEN_512:
-                       gtt_entries = KB(512) - KB(size);
-                       break;
-               case I830_GMCH_GMS_STOLEN_1024:
-                       gtt_entries = MB(1) - KB(size);
-                       break;
-               case I830_GMCH_GMS_STOLEN_8192:
-                       gtt_entries = MB(8) - KB(size);
-                       break;
-               case I830_GMCH_GMS_LOCAL:
-                       rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
-                       gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
-                                       MB(ddt[I830_RDRAM_DDT(rdct)]);
-                       local = 1;
-                       break;
-               default:
-                       gtt_entries = 0;
-                       break;
-               }
-       } else if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
-                  agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) {
-               /*
-                * SandyBridge has new memory control reg at 0x50.w
-                */
-               u16 snb_gmch_ctl;
-               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
-               switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
-               case SNB_GMCH_GMS_STOLEN_32M:
-                       gtt_entries = MB(32) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_64M:
-                       gtt_entries = MB(64) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_96M:
-                       gtt_entries = MB(96) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_128M:
-                       gtt_entries = MB(128) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_160M:
-                       gtt_entries = MB(160) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_192M:
-                       gtt_entries = MB(192) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_224M:
-                       gtt_entries = MB(224) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_256M:
-                       gtt_entries = MB(256) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_288M:
-                       gtt_entries = MB(288) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_320M:
-                       gtt_entries = MB(320) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_352M:
-                       gtt_entries = MB(352) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_384M:
-                       gtt_entries = MB(384) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_416M:
-                       gtt_entries = MB(416) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_448M:
-                       gtt_entries = MB(448) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_480M:
-                       gtt_entries = MB(480) - KB(size);
-                       break;
-               case SNB_GMCH_GMS_STOLEN_512M:
-                       gtt_entries = MB(512) - KB(size);
-                       break;
-               }
-       } else {
-               switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
-               case I855_GMCH_GMS_STOLEN_1M:
-                       gtt_entries = MB(1) - KB(size);
-                       break;
-               case I855_GMCH_GMS_STOLEN_4M:
-                       gtt_entries = MB(4) - KB(size);
-                       break;
-               case I855_GMCH_GMS_STOLEN_8M:
-                       gtt_entries = MB(8) - KB(size);
-                       break;
-               case I855_GMCH_GMS_STOLEN_16M:
-                       gtt_entries = MB(16) - KB(size);
-                       break;
-               case I855_GMCH_GMS_STOLEN_32M:
-                       gtt_entries = MB(32) - KB(size);
-                       break;
-               case I915_GMCH_GMS_STOLEN_48M:
-                       /* Check it's really I915G */
-                       if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
-                               gtt_entries = MB(48) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case I915_GMCH_GMS_STOLEN_64M:
-                       /* Check it's really I915G */
-                       if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
-                               gtt_entries = MB(64) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case G33_GMCH_GMS_STOLEN_128M:
-                       if (IS_G33 || IS_I965 || IS_G4X)
-                               gtt_entries = MB(128) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case G33_GMCH_GMS_STOLEN_256M:
-                       if (IS_G33 || IS_I965 || IS_G4X)
-                               gtt_entries = MB(256) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_96M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(96) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_160M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(160) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_224M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(224) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_352M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(352) - KB(size);
-                       else
-                               gtt_entries = 0;
-                       break;
-               default:
-                       gtt_entries = 0;
-                       break;
-               }
-       }
-       if (gtt_entries > 0) {
-               dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
-                      gtt_entries / KB(1), local ? "local" : "stolen");
-               gtt_entries /= KB(4);
-       } else {
-               dev_info(&agp_bridge->dev->dev,
-                      "no pre-allocated video memory detected\n");
-               gtt_entries = 0;
-       }
-
-       intel_private.gtt_entries = gtt_entries;
-}
-
-static void intel_i830_fini_flush(void)
-{
-       kunmap(intel_private.i8xx_page);
-       intel_private.i8xx_flush_page = NULL;
-       unmap_page_from_agp(intel_private.i8xx_page);
-
-       __free_page(intel_private.i8xx_page);
-       intel_private.i8xx_page = NULL;
-}
-
-static void intel_i830_setup_flush(void)
-{
-       /* return if we've already set the flush mechanism up */
-       if (intel_private.i8xx_page)
-               return;
-
-       intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
-       if (!intel_private.i8xx_page)
-               return;
-
-       intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
-       if (!intel_private.i8xx_flush_page)
-               intel_i830_fini_flush();
-}
-
-/* The chipset_flush interface needs to get data that has already been
- * flushed out of the CPU all the way out to main memory, because the GPU
- * doesn't snoop those buffers.
- *
- * The 8xx series doesn't have the same lovely interface for flushing the
- * chipset write buffers that the later chips do. According to the 865
- * specs, it's 64 octwords, or 1KB.  So, to get those previous things in
- * that buffer out, we just fill 1KB and clflush it out, on the assumption
- * that it'll push whatever was in there out.  It appears to work.
- */
-static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
-{
-       unsigned int *pg = intel_private.i8xx_flush_page;
-
-       memset(pg, 0, 1024);
-
-       if (cpu_has_clflush)
-               clflush_cache_range(pg, 1024);
-       else if (wbinvd_on_all_cpus() != 0)
-               printk(KERN_ERR "Timed out waiting for cache flush.\n");
-}
-
-/* The intel i830 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
-{
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp;
-
-       size = agp_bridge->current_size;
-       page_order = size->page_order;
-       num_entries = size->num_entries;
-       agp_bridge->gatt_table_real = NULL;
-
-       pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
-       temp &= 0xfff80000;
-
-       intel_private.registers = ioremap(temp, 128 * 4096);
-       if (!intel_private.registers)
-               return -ENOMEM;
-
-       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-       global_cache_flush();   /* FIXME: ?? */
-
-       /* we have to call this as early as possible after the MMIO base address is known */
-       intel_i830_init_gtt_entries();
-
-       agp_bridge->gatt_table = NULL;
-
-       agp_bridge->gatt_bus_addr = temp;
-
-       return 0;
-}
-
-/* Return the gatt table to a sane state. Use the top of stolen
- * memory for the GTT.
- */
-static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
-{
-       return 0;
-}
-
-static int intel_i830_fetch_size(void)
-{
-       u16 gmch_ctrl;
-       struct aper_size_info_fixed *values;
-
-       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
-       if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
-           agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
-               /* 855GM/852GM/865G has 128MB aperture size */
-               agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
-               agp_bridge->aperture_size_idx = 0;
-               return values[0].size;
-       }
-
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-
-       if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
-               agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
-               agp_bridge->aperture_size_idx = 0;
-               return values[0].size;
-       } else {
-               agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + 1);
-               agp_bridge->aperture_size_idx = 1;
-               return values[1].size;
-       }
-
-       return 0;
-}
-
-static int intel_i830_configure(void)
-{
-       struct aper_size_info_fixed *current_size;
-       u32 temp;
-       u16 gmch_ctrl;
-       int i;
-
-       current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
-       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-       gmch_ctrl |= I830_GMCH_ENABLED;
-       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
-
-       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
-
-       if (agp_bridge->driver->needs_scratch_page) {
-               for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
-                       writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
-               }
-               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */
-       }
-
-       global_cache_flush();
-
-       intel_i830_setup_flush();
-       return 0;
-}
-
-static void intel_i830_cleanup(void)
-{
-       iounmap(intel_private.registers);
-}
-
-static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
-{
-       int i, j, num_entries;
-       void *temp;
-       int ret = -EINVAL;
-       int mask_type;
-
-       if (mem->page_count == 0)
-               goto out;
-
-       temp = agp_bridge->current_size;
-       num_entries = A_SIZE_FIX(temp)->num_entries;
-
-       if (pg_start < intel_private.gtt_entries) {
-               dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
-                          "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
-                          pg_start, intel_private.gtt_entries);
-
-               dev_info(&intel_private.pcidev->dev,
-                        "trying to insert into local/stolen memory\n");
-               goto out_err;
-       }
-
-       if ((pg_start + mem->page_count) > num_entries)
-               goto out_err;
-
-       /* The i830 can't check the GTT for entries since its read only,
-        * depend on the caller to make the correct offset decisions.
-        */
-
-       if (type != mem->type)
-               goto out_err;
-
-       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
-           mask_type != INTEL_AGP_CACHED_MEMORY)
-               goto out_err;
-
-       if (!mem->is_flushed)
-               global_cache_flush();
-
-       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                               page_to_phys(mem->pages[i]), mask_type),
-                      intel_private.registers+I810_PTE_BASE+(j*4));
-       }
-       readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
-       agp_bridge->driver->tlb_flush(mem);
-
-out:
-       ret = 0;
-out_err:
-       mem->is_flushed = true;
-       return ret;
-}
-
-static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
-{
-       int i;
-
-       if (mem->page_count == 0)
-               return 0;
-
-       if (pg_start < intel_private.gtt_entries) {
-               dev_info(&intel_private.pcidev->dev,
-                        "trying to disable local/stolen memory\n");
-               return -EINVAL;
-       }
-
-       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-               writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
-       }
-       readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
-
-       agp_bridge->driver->tlb_flush(mem);
-       return 0;
-}
-
-static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
-{
-       if (type == AGP_PHYS_MEMORY)
-               return alloc_agpphysmem_i8xx(pg_count, type);
-       /* always return NULL for other allocation types for now */
-       return NULL;
-}
-
-static int intel_alloc_chipset_flush_resource(void)
-{
-       int ret;
-       ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
-                                    PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
-                                    pcibios_align_resource, agp_bridge->dev);
-
-       return ret;
-}
-
-static void intel_i915_setup_chipset_flush(void)
-{
-       int ret;
-       u32 temp;
-
-       pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
-       if (!(temp & 0x1)) {
-               intel_alloc_chipset_flush_resource();
-               intel_private.resource_valid = 1;
-               pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
-       } else {
-               temp &= ~1;
-
-               intel_private.resource_valid = 1;
-               intel_private.ifp_resource.start = temp;
-               intel_private.ifp_resource.end = temp + PAGE_SIZE;
-               ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
-               /* some BIOSes reserve this area in a pnp some don't */
-               if (ret)
-                       intel_private.resource_valid = 0;
-       }
-}
-
-static void intel_i965_g33_setup_chipset_flush(void)
-{
-       u32 temp_hi, temp_lo;
-       int ret;
-
-       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
-       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
-
-       if (!(temp_lo & 0x1)) {
-
-               intel_alloc_chipset_flush_resource();
-
-               intel_private.resource_valid = 1;
-               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
-                       upper_32_bits(intel_private.ifp_resource.start));
-               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
-       } else {
-               u64 l64;
-
-               temp_lo &= ~0x1;
-               l64 = ((u64)temp_hi << 32) | temp_lo;
-
-               intel_private.resource_valid = 1;
-               intel_private.ifp_resource.start = l64;
-               intel_private.ifp_resource.end = l64 + PAGE_SIZE;
-               ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
-               /* some BIOSes reserve this area in a pnp some don't */
-               if (ret)
-                       intel_private.resource_valid = 0;
-       }
-}
-
-static void intel_i9xx_setup_flush(void)
-{
-       /* return if already configured */
-       if (intel_private.ifp_resource.start)
-               return;
-
-       if (IS_SNB)
-               return;
-
-       /* setup a resource for this object */
-       intel_private.ifp_resource.name = "Intel Flush Page";
-       intel_private.ifp_resource.flags = IORESOURCE_MEM;
-
-       /* Setup chipset flush for 915 */
-       if (IS_I965 || IS_G33 || IS_G4X) {
-               intel_i965_g33_setup_chipset_flush();
-       } else {
-               intel_i915_setup_chipset_flush();
-       }
-
-       if (intel_private.ifp_resource.start) {
-               intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE);
-               if (!intel_private.i9xx_flush_page)
-                       dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing");
-       }
-}
-
-static int intel_i915_configure(void)
-{
-       struct aper_size_info_fixed *current_size;
-       u32 temp;
-       u16 gmch_ctrl;
-       int i;
-
-       current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-       pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp);
-
-       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-       gmch_ctrl |= I830_GMCH_ENABLED;
-       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
-
-       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
-
-       if (agp_bridge->driver->needs_scratch_page) {
-               for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
-                       writel(agp_bridge->scratch_page, intel_private.gtt+i);
-               }
-               readl(intel_private.gtt+i-1);   /* PCI Posting. */
-       }
-
-       global_cache_flush();
-
-       intel_i9xx_setup_flush();
-
-       return 0;
-}
-
-static void intel_i915_cleanup(void)
-{
-       if (intel_private.i9xx_flush_page)
-               iounmap(intel_private.i9xx_flush_page);
-       if (intel_private.resource_valid)
-               release_resource(&intel_private.ifp_resource);
-       intel_private.ifp_resource.start = 0;
-       intel_private.resource_valid = 0;
-       iounmap(intel_private.gtt);
-       iounmap(intel_private.registers);
-}
-
-static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
-{
-       if (intel_private.i9xx_flush_page)
-               writel(1, intel_private.i9xx_flush_page);
-}
-
-static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
-{
-       int num_entries;
-       void *temp;
-       int ret = -EINVAL;
-       int mask_type;
-
-       if (mem->page_count == 0)
-               goto out;
-
-       temp = agp_bridge->current_size;
-       num_entries = A_SIZE_FIX(temp)->num_entries;
-
-       if (pg_start < intel_private.gtt_entries) {
-               dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
-                          "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
-                          pg_start, intel_private.gtt_entries);
-
-               dev_info(&intel_private.pcidev->dev,
-                        "trying to insert into local/stolen memory\n");
-               goto out_err;
-       }
-
-       if ((pg_start + mem->page_count) > num_entries)
-               goto out_err;
-
-       /* The i915 can't check the GTT for entries since it's read only;
-        * depend on the caller to make the correct offset decisions.
-        */
-
-       if (type != mem->type)
-               goto out_err;
-
-       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
-           mask_type != INTEL_AGP_CACHED_MEMORY)
-               goto out_err;
-
-       if (!mem->is_flushed)
-               global_cache_flush();
-
-       intel_agp_insert_sg_entries(mem, pg_start, mask_type);
-       agp_bridge->driver->tlb_flush(mem);
-
- out:
-       ret = 0;
- out_err:
-       mem->is_flushed = true;
-       return ret;
-}
-
-static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
-{
-       int i;
-
-       if (mem->page_count == 0)
-               return 0;
-
-       if (pg_start < intel_private.gtt_entries) {
-               dev_info(&intel_private.pcidev->dev,
-                        "trying to disable local/stolen memory\n");
-               return -EINVAL;
-       }
-
-       for (i = pg_start; i < (mem->page_count + pg_start); i++)
-               writel(agp_bridge->scratch_page, intel_private.gtt+i);
-
-       readl(intel_private.gtt+i-1);
-
-       agp_bridge->driver->tlb_flush(mem);
-       return 0;
-}
-
-/* Return the aperture size by just checking the resource length.  The effect
- * described in the spec of the MSAC registers is just changing of the
- * resource size.
- */
-static int intel_i9xx_fetch_size(void)
-{
-       int num_sizes = ARRAY_SIZE(intel_i830_sizes);
-       int aper_size; /* size in megabytes */
-       int i;
-
-       aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1);
-
-       for (i = 0; i < num_sizes; i++) {
-               if (aper_size == intel_i830_sizes[i].size) {
-                       agp_bridge->current_size = intel_i830_sizes + i;
-                       agp_bridge->previous_size = agp_bridge->current_size;
-                       return aper_size;
-               }
-       }
-
-       return 0;
-}
-
-/* The intel i915 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
-{
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp, temp2;
-       int gtt_map_size = 256 * 1024;
-
-       size = agp_bridge->current_size;
-       page_order = size->page_order;
-       num_entries = size->num_entries;
-       agp_bridge->gatt_table_real = NULL;
-
-       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-       pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
-
-       if (IS_G33)
-           gtt_map_size = 1024 * 1024; /* 1M on G33 */
-       intel_private.gtt = ioremap(temp2, gtt_map_size);
-       if (!intel_private.gtt)
-               return -ENOMEM;
-
-       intel_private.gtt_total_size = gtt_map_size / 4;
-
-       temp &= 0xfff80000;
-
-       intel_private.registers = ioremap(temp, 128 * 4096);
-       if (!intel_private.registers) {
-               iounmap(intel_private.gtt);
-               return -ENOMEM;
-       }
-
-       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-       global_cache_flush();   /* FIXME: ? */
-
-       /* we have to call this as early as possible after the MMIO base address is known */
-       intel_i830_init_gtt_entries();
-
-       agp_bridge->gatt_table = NULL;
-
-       agp_bridge->gatt_bus_addr = temp;
-
-       return 0;
-}
-
-/*
- * The i965 supports 36-bit physical addresses, but to keep
- * the format of the GTT the same, the bits that don't fit
- * in a 32-bit word are shifted down to bits 4..7.
- *
- * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
- * is always zero on 32-bit architectures, so no need to make
- * this conditional.
- */
-static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
-                                           dma_addr_t addr, int type)
-{
-       /* Shift high bits down */
-       addr |= (addr >> 28) & 0xf0;
-
-       /* Type checking must be done elsewhere */
-       return addr | bridge->driver->masks[type].mask;
-}
-
-static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
-{
-       u16 snb_gmch_ctl;
-
-       switch (agp_bridge->dev->device) {
-       case PCI_DEVICE_ID_INTEL_GM45_HB:
-       case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB:
-       case PCI_DEVICE_ID_INTEL_Q45_HB:
-       case PCI_DEVICE_ID_INTEL_G45_HB:
-       case PCI_DEVICE_ID_INTEL_G41_HB:
-       case PCI_DEVICE_ID_INTEL_B43_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
-       case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
-               *gtt_offset = *gtt_size = MB(2);
-               break;
-       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
-       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
-               *gtt_offset = MB(2);
-
-               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
-               switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
-               default:
-               case SNB_GTT_SIZE_0M:
-                       printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
-                       *gtt_size = MB(0);
-                       break;
-               case SNB_GTT_SIZE_1M:
-                       *gtt_size = MB(1);
-                       break;
-               case SNB_GTT_SIZE_2M:
-                       *gtt_size = MB(2);
-                       break;
-               }
-               break;
-       default:
-               *gtt_offset = *gtt_size = KB(512);
-       }
-}
-
-/* The intel i965 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
-{
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp;
-       int gtt_offset, gtt_size;
-
-       size = agp_bridge->current_size;
-       page_order = size->page_order;
-       num_entries = size->num_entries;
-       agp_bridge->gatt_table_real = NULL;
-
-       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-
-       temp &= 0xfff00000;
-
-       intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
-
-       intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
-
-       if (!intel_private.gtt)
-               return -ENOMEM;
-
-       intel_private.gtt_total_size = gtt_size / 4;
-
-       intel_private.registers = ioremap(temp, 128 * 4096);
-       if (!intel_private.registers) {
-               iounmap(intel_private.gtt);
-               return -ENOMEM;
-       }
-
-       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-       global_cache_flush();   /* FIXME: ? */
-
-       /* we have to call this as early as possible after the MMIO base address is known */
-       intel_i830_init_gtt_entries();
-
-       agp_bridge->gatt_table = NULL;
-
-       agp_bridge->gatt_bus_addr = temp;
-
-       return 0;
-}
-
-
 static int intel_fetch_size(void)
 {
        int i;
@@ -1982,6 +464,7 @@ static const struct agp_bridge_driver intel_generic_driver = {
        .aperture_sizes         = intel_generic_sizes,
        .size_type              = U16_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = intel_configure,
        .fetch_size             = intel_fetch_size,
        .cleanup                = intel_cleanup,
@@ -2003,38 +486,12 @@ static const struct agp_bridge_driver intel_generic_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_810_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i810_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 2,
-       .needs_scratch_page     = true,
-       .configure              = intel_i810_configure,
-       .fetch_size             = intel_i810_fetch_size,
-       .cleanup                = intel_i810_cleanup,
-       .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i810_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = agp_generic_create_gatt_table,
-       .free_gatt_table        = agp_generic_free_gatt_table,
-       .insert_memory          = intel_i810_insert_entries,
-       .remove_memory          = intel_i810_remove_entries,
-       .alloc_by_type          = intel_i810_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
-};
-
 static const struct agp_bridge_driver intel_815_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_815_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 2,
+       .needs_scratch_page     = true,
        .configure              = intel_815_configure,
        .fetch_size             = intel_815_fetch_size,
        .cleanup                = intel_8xx_cleanup,
@@ -2056,39 +513,12 @@ static const struct agp_bridge_driver intel_815_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_830_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i830_configure,
-       .fetch_size             = intel_i830_fetch_size,
-       .cleanup                = intel_i830_cleanup,
-       .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i810_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i830_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i830_insert_entries,
-       .remove_memory          = intel_i830_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i830_chipset_flush,
-};
-
 static const struct agp_bridge_driver intel_820_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = intel_820_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_820_cleanup,
@@ -2115,6 +545,7 @@ static const struct agp_bridge_driver intel_830mp_driver = {
        .aperture_sizes         = intel_830mp_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 4,
+       .needs_scratch_page     = true,
        .configure              = intel_830mp_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
@@ -2141,6 +572,7 @@ static const struct agp_bridge_driver intel_840_driver = {
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = intel_840_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
@@ -2167,6 +599,7 @@ static const struct agp_bridge_driver intel_845_driver = {
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = intel_845_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
@@ -2193,6 +626,7 @@ static const struct agp_bridge_driver intel_850_driver = {
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = intel_850_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
@@ -2219,6 +653,7 @@ static const struct agp_bridge_driver intel_860_driver = {
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = intel_860_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
@@ -2240,79 +675,12 @@ static const struct agp_bridge_driver intel_860_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_915_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i915_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i810_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i915_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i915_insert_entries,
-       .remove_memory          = intel_i915_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-       .agp_map_page           = intel_agp_map_page,
-       .agp_unmap_page         = intel_agp_unmap_page,
-       .agp_map_memory         = intel_agp_map_memory,
-       .agp_unmap_memory       = intel_agp_unmap_memory,
-#endif
-};
-
-static const struct agp_bridge_driver intel_i965_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i915_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i965_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i965_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i915_insert_entries,
-       .remove_memory          = intel_i915_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-       .agp_map_page           = intel_agp_map_page,
-       .agp_unmap_page         = intel_agp_unmap_page,
-       .agp_map_memory         = intel_agp_map_memory,
-       .agp_unmap_memory       = intel_agp_unmap_memory,
-#endif
-};
-
 static const struct agp_bridge_driver intel_7505_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = intel_8xx_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = intel_7505_configure,
        .fetch_size             = intel_8xx_fetch_size,
        .cleanup                = intel_8xx_cleanup,
@@ -2334,40 +702,6 @@ static const struct agp_bridge_driver intel_7505_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_g33_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i915_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .tlb_flush              = intel_i810_tlbflush,
-       .mask_memory            = intel_i965_mask_memory,
-       .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
-       .cache_flush            = global_cache_flush,
-       .create_gatt_table      = intel_i915_create_gatt_table,
-       .free_gatt_table        = intel_i830_free_gatt_table,
-       .insert_memory          = intel_i915_insert_entries,
-       .remove_memory          = intel_i915_remove_entries,
-       .alloc_by_type          = intel_i830_alloc_by_type,
-       .free_by_type           = intel_i810_free_by_type,
-       .agp_alloc_page         = agp_generic_alloc_page,
-       .agp_alloc_pages        = agp_generic_alloc_pages,
-       .agp_destroy_page       = agp_generic_destroy_page,
-       .agp_destroy_pages      = agp_generic_destroy_pages,
-       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-       .chipset_flush          = intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-       .agp_map_page           = intel_agp_map_page,
-       .agp_unmap_page         = intel_agp_unmap_page,
-       .agp_map_memory         = intel_agp_map_memory,
-       .agp_unmap_memory       = intel_agp_unmap_memory,
-#endif
-};
-
 static int find_gmch(u16 device)
 {
        struct pci_dev *gmch_device;
@@ -2392,103 +726,137 @@ static int find_gmch(u16 device)
 static const struct intel_driver_description {
        unsigned int chip_id;
        unsigned int gmch_chip_id;
-       unsigned int multi_gmch_chip; /* if we have more gfx chip type on this HB. */
        char *name;
        const struct agp_bridge_driver *driver;
        const struct agp_bridge_driver *gmch_driver;
 } intel_agp_chipsets[] = {
-       { PCI_DEVICE_ID_INTEL_82443LX_0, 0, 0, "440LX", &intel_generic_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82443BX_0, 0, 0, "440BX", &intel_generic_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82443GX_0, 0, 0, "440GX", &intel_generic_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, 0, "i810",
+       { PCI_DEVICE_ID_INTEL_82443LX_0, 0, "440LX", &intel_generic_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82443BX_0, 0, "440BX", &intel_generic_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82443GX_0, 0, "440GX", &intel_generic_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, "i810",
                NULL, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, 0, "i810",
+       { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, "i810",
                NULL, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, 0, "i810",
+       { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, "i810",
                NULL, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, 0, "i815",
+       { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, "i815",
                &intel_815_driver, &intel_810_driver },
-       { PCI_DEVICE_ID_INTEL_82820_HB, 0, 0, "i820", &intel_820_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, 0, "i820", &intel_820_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, 0, "830M",
+       { PCI_DEVICE_ID_INTEL_82820_HB, 0, "i820", &intel_820_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, "i820", &intel_820_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
                &intel_830mp_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82840_HB, 0, 0, "i840", &intel_840_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82845_HB, 0, 0, "845G", &intel_845_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, 0, "830M",
+       { PCI_DEVICE_ID_INTEL_82840_HB, 0, "i840", &intel_840_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82845_HB, 0, "845G", &intel_845_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
                &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82850_HB, 0, 0, "i850", &intel_850_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, 0, "854",
+       { PCI_DEVICE_ID_INTEL_82850_HB, 0, "i850", &intel_850_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, "854",
                &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, 0, "855PM", &intel_845_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, 0, "855GM",
+       { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, "855PM", &intel_845_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
                &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82860_HB, 0, 0, "i860", &intel_860_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, 0, "865",
+       { PCI_DEVICE_ID_INTEL_82860_HB, 0, "i860", &intel_860_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, "865",
                &intel_845_driver, &intel_830_driver },
-       { PCI_DEVICE_ID_INTEL_82875_HB, 0, 0, "i875", &intel_845_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, 0, "E7221 (i915)",
+       { PCI_DEVICE_ID_INTEL_82875_HB, 0, "i875", &intel_845_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, 0, "915G",
+       { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, 0, "915GM",
+       { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, 0, "945G",
+       { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 0, "945GM",
+       { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME",
+       { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
                NULL, &intel_915_driver },
-       { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ",
+       { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, 0, "G35",
+       { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, 0, "965Q",
+       { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, 0, "965G",
+       { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 0, "965GM",
+       { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE",
+       { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_7505_0, 0, 0, "E7505", &intel_7505_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_7205_0, 0, 0, "E7205", &intel_7505_driver, NULL },
-       { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, 0, "G33",
+       { PCI_DEVICE_ID_INTEL_7505_0, 0, "E7505", &intel_7505_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_7205_0, 0, "E7205", &intel_7505_driver, NULL },
+       { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, "G33",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, 0, "Q35",
+       { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
+       { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "GMA3150",
+       { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "GMA3150",
+       { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
                NULL, &intel_g33_driver },
-       { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0,
+       { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG,
            "GM45", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, 0,
+       { PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG,
            "Eaglelake", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG, 0,
+       { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG,
            "Q45/Q43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG, 0,
+       { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG,
            "G45/G43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG, 0,
+       { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG,
            "B43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
+       { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG,
            "G41", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 0,
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
            "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
            "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
            "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
            "HD Graphics", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG, 0,
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG,
            "Sandybridge", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, 0,
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG,
            "Sandybridge", NULL, &intel_i965_driver },
-       { 0, 0, 0, NULL, NULL, NULL }
+       { 0, 0, NULL, NULL, NULL }
 };
 
+static int __devinit intel_gmch_probe(struct pci_dev *pdev,
+                                     struct agp_bridge_data *bridge)
+{
+       int i;
+       bridge->driver = NULL;
+
+       for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
+               if ((intel_agp_chipsets[i].gmch_chip_id != 0) &&
+                       find_gmch(intel_agp_chipsets[i].gmch_chip_id)) {
+                       bridge->driver =
+                               intel_agp_chipsets[i].gmch_driver;
+                       break;
+               }
+       }
+
+       if (!bridge->driver)
+               return 0;
+
+       bridge->dev_private_data = &intel_private;
+       bridge->dev = pdev;
+
+       dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
+
+       if (bridge->driver->mask_memory == intel_i965_mask_memory) {
+               if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
+                       dev_err(&intel_private.pcidev->dev,
+                               "set gfx device dma mask 36bit failed!\n");
+               else
+                       pci_set_consistent_dma_mask(intel_private.pcidev,
+                                                   DMA_BIT_MASK(36));
+       }
+
+       return 1;
+}
+
 static int __devinit agp_intel_probe(struct pci_dev *pdev,
                                     const struct pci_device_id *ent)
 {
@@ -2503,22 +871,18 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
        if (!bridge)
                return -ENOMEM;
 
+       bridge->capndx = cap_ptr;
+
+       if (intel_gmch_probe(pdev, bridge))
+               goto found_gmch;
+
        for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
                /* In case that multiple models of gfx chip may
                   stand on same host bridge type, this can be
                   sure we detect the right IGD. */
                if (pdev->device == intel_agp_chipsets[i].chip_id) {
-                       if ((intel_agp_chipsets[i].gmch_chip_id != 0) &&
-                               find_gmch(intel_agp_chipsets[i].gmch_chip_id)) {
-                               bridge->driver =
-                                       intel_agp_chipsets[i].gmch_driver;
-                               break;
-                       } else if (intel_agp_chipsets[i].multi_gmch_chip) {
-                               continue;
-                       } else {
-                               bridge->driver = intel_agp_chipsets[i].driver;
-                               break;
-                       }
+                       bridge->driver = intel_agp_chipsets[i].driver;
+                       break;
                }
        }
 
@@ -2530,18 +894,16 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                return -ENODEV;
        }
 
-       if (bridge->driver == NULL) {
-               /* bridge has no AGP and no IGD detected */
+       if (!bridge->driver) {
                if (cap_ptr)
                        dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n",
-                                intel_agp_chipsets[i].gmch_chip_id);
+                                intel_agp_chipsets[i].gmch_chip_id);
                agp_put_bridge(bridge);
                return -ENODEV;
        }
 
        bridge->dev = pdev;
-       bridge->capndx = cap_ptr;
-       bridge->dev_private_data = &intel_private;
+       bridge->dev_private_data = NULL;
 
        dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
 
@@ -2577,15 +939,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                                &bridge->mode);
        }
 
-       if (bridge->driver->mask_memory == intel_i965_mask_memory) {
-               if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
-                       dev_err(&intel_private.pcidev->dev,
-                               "set gfx device dma mask 36bit failed!\n");
-               else
-                       pci_set_consistent_dma_mask(intel_private.pcidev,
-                                                   DMA_BIT_MASK(36));
-       }
-
+found_gmch:
        pci_set_drvdata(pdev, bridge);
        err = agp_add_bridge(bridge);
        if (!err)
@@ -2611,22 +965,7 @@ static int agp_intel_resume(struct pci_dev *pdev)
        struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
        int ret_val;
 
-       if (bridge->driver == &intel_generic_driver)
-               intel_configure();
-       else if (bridge->driver == &intel_850_driver)
-               intel_850_configure();
-       else if (bridge->driver == &intel_845_driver)
-               intel_845_configure();
-       else if (bridge->driver == &intel_830mp_driver)
-               intel_830mp_configure();
-       else if (bridge->driver == &intel_915_driver)
-               intel_i915_configure();
-       else if (bridge->driver == &intel_830_driver)
-               intel_i830_configure();
-       else if (bridge->driver == &intel_810_driver)
-               intel_i810_configure();
-       else if (bridge->driver == &intel_i965_driver)
-               intel_i915_configure();
+       bridge->driver->configure();
 
        ret_val = agp_rebind_memory();
        if (ret_val != 0)
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
new file mode 100644 (file)
index 0000000..2547465
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Common Intel AGPGART and GTT definitions.
+ */
+
+/* Intel registers */
+#define INTEL_APSIZE   0xb4
+#define INTEL_ATTBASE  0xb8
+#define INTEL_AGPCTRL  0xb0
+#define INTEL_NBXCFG   0x50
+#define INTEL_ERRSTS   0x91
+
+/* Intel i830 registers */
+#define I830_GMCH_CTRL                 0x52
+#define I830_GMCH_ENABLED              0x4
+#define I830_GMCH_MEM_MASK             0x1
+#define I830_GMCH_MEM_64M              0x1
+#define I830_GMCH_MEM_128M             0
+#define I830_GMCH_GMS_MASK             0x70
+#define I830_GMCH_GMS_DISABLED         0x00
+#define I830_GMCH_GMS_LOCAL            0x10
+#define I830_GMCH_GMS_STOLEN_512       0x20
+#define I830_GMCH_GMS_STOLEN_1024      0x30
+#define I830_GMCH_GMS_STOLEN_8192      0x40
+#define I830_RDRAM_CHANNEL_TYPE                0x03010
+#define I830_RDRAM_ND(x)               (((x) & 0x20) >> 5)
+#define I830_RDRAM_DDT(x)              (((x) & 0x18) >> 3)
+
+/* This one is for I830MP w. an external graphic card */
+#define INTEL_I830_ERRSTS      0x92
+
+/* Intel 855GM/852GM registers */
+#define I855_GMCH_GMS_MASK             0xF0
+#define I855_GMCH_GMS_STOLEN_0M                0x0
+#define I855_GMCH_GMS_STOLEN_1M                (0x1 << 4)
+#define I855_GMCH_GMS_STOLEN_4M                (0x2 << 4)
+#define I855_GMCH_GMS_STOLEN_8M                (0x3 << 4)
+#define I855_GMCH_GMS_STOLEN_16M       (0x4 << 4)
+#define I855_GMCH_GMS_STOLEN_32M       (0x5 << 4)
+#define I85X_CAPID                     0x44
+#define I85X_VARIANT_MASK              0x7
+#define I85X_VARIANT_SHIFT             5
+#define I855_GME                       0x0
+#define I855_GM                                0x4
+#define I852_GME                       0x2
+#define I852_GM                                0x5
+
+/* Intel i845 registers */
+#define INTEL_I845_AGPM                0x51
+#define INTEL_I845_ERRSTS      0xc8
+
+/* Intel i860 registers */
+#define INTEL_I860_MCHCFG      0x50
+#define INTEL_I860_ERRSTS      0xc8
+
+/* Intel i810 registers */
+#define I810_GMADDR            0x10
+#define I810_MMADDR            0x14
+#define I810_PTE_BASE          0x10000
+#define I810_PTE_MAIN_UNCACHED 0x00000000
+#define I810_PTE_LOCAL         0x00000002
+#define I810_PTE_VALID         0x00000001
+#define I830_PTE_SYSTEM_CACHED  0x00000006
+#define I810_SMRAM_MISCC       0x70
+#define I810_GFX_MEM_WIN_SIZE  0x00010000
+#define I810_GFX_MEM_WIN_32M   0x00010000
+#define I810_GMS               0x000000c0
+#define I810_GMS_DISABLE       0x00000000
+#define I810_PGETBL_CTL                0x2020
+#define I810_PGETBL_ENABLED    0x00000001
+#define I965_PGETBL_SIZE_MASK  0x0000000e
+#define I965_PGETBL_SIZE_512KB (0 << 1)
+#define I965_PGETBL_SIZE_256KB (1 << 1)
+#define I965_PGETBL_SIZE_128KB (2 << 1)
+#define I965_PGETBL_SIZE_1MB   (3 << 1)
+#define I965_PGETBL_SIZE_2MB   (4 << 1)
+#define I965_PGETBL_SIZE_1_5MB (5 << 1)
+#define G33_PGETBL_SIZE_MASK    (3 << 8)
+#define G33_PGETBL_SIZE_1M      (1 << 8)
+#define G33_PGETBL_SIZE_2M      (2 << 8)
+
+#define I810_DRAM_CTL          0x3000
+#define I810_DRAM_ROW_0                0x00000001
+#define I810_DRAM_ROW_0_SDRAM  0x00000001
+
+/* Intel 815 register */
+#define INTEL_815_APCONT       0x51
+#define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF
+
+/* Intel i820 registers */
+#define INTEL_I820_RDCR                0x51
+#define INTEL_I820_ERRSTS      0xc8
+
+/* Intel i840 registers */
+#define INTEL_I840_MCHCFG      0x50
+#define INTEL_I840_ERRSTS      0xc8
+
+/* Intel i850 registers */
+#define INTEL_I850_MCHCFG      0x50
+#define INTEL_I850_ERRSTS      0xc8
+
+/* intel 915G registers */
+#define I915_GMADDR    0x18
+#define I915_MMADDR    0x10
+#define I915_PTEADDR   0x1C
+#define I915_GMCH_GMS_STOLEN_48M       (0x6 << 4)
+#define I915_GMCH_GMS_STOLEN_64M       (0x7 << 4)
+#define G33_GMCH_GMS_STOLEN_128M       (0x8 << 4)
+#define G33_GMCH_GMS_STOLEN_256M       (0x9 << 4)
+#define INTEL_GMCH_GMS_STOLEN_96M      (0xa << 4)
+#define INTEL_GMCH_GMS_STOLEN_160M     (0xb << 4)
+#define INTEL_GMCH_GMS_STOLEN_224M     (0xc << 4)
+#define INTEL_GMCH_GMS_STOLEN_352M     (0xd << 4)
+
+#define I915_IFPADDR    0x60
+
+/* Intel 965G registers */
+#define I965_MSAC 0x62
+#define I965_IFPADDR    0x70
+
+/* Intel 7505 registers */
+#define INTEL_I7505_APSIZE     0x74
+#define INTEL_I7505_NCAPID     0x60
+#define INTEL_I7505_NISTAT     0x6c
+#define INTEL_I7505_ATTBASE    0x78
+#define INTEL_I7505_ERRSTS     0x42
+#define INTEL_I7505_AGPCTRL    0x70
+#define INTEL_I7505_MCHCFG     0x50
+
+#define SNB_GMCH_CTRL  0x50
+#define SNB_GMCH_GMS_STOLEN_MASK       0xF8
+#define SNB_GMCH_GMS_STOLEN_32M                (1 << 3)
+#define SNB_GMCH_GMS_STOLEN_64M                (2 << 3)
+#define SNB_GMCH_GMS_STOLEN_96M                (3 << 3)
+#define SNB_GMCH_GMS_STOLEN_128M       (4 << 3)
+#define SNB_GMCH_GMS_STOLEN_160M       (5 << 3)
+#define SNB_GMCH_GMS_STOLEN_192M       (6 << 3)
+#define SNB_GMCH_GMS_STOLEN_224M       (7 << 3)
+#define SNB_GMCH_GMS_STOLEN_256M       (8 << 3)
+#define SNB_GMCH_GMS_STOLEN_288M       (9 << 3)
+#define SNB_GMCH_GMS_STOLEN_320M       (0xa << 3)
+#define SNB_GMCH_GMS_STOLEN_352M       (0xb << 3)
+#define SNB_GMCH_GMS_STOLEN_384M       (0xc << 3)
+#define SNB_GMCH_GMS_STOLEN_416M       (0xd << 3)
+#define SNB_GMCH_GMS_STOLEN_448M       (0xe << 3)
+#define SNB_GMCH_GMS_STOLEN_480M       (0xf << 3)
+#define SNB_GMCH_GMS_STOLEN_512M       (0x10 << 3)
+#define SNB_GTT_SIZE_0M                        (0 << 8)
+#define SNB_GTT_SIZE_1M                        (1 << 8)
+#define SNB_GTT_SIZE_2M                        (2 << 8)
+#define SNB_GTT_SIZE_MASK              (3 << 8)
+
+/* pci devices ids */
+#define PCI_DEVICE_ID_INTEL_E7221_HB   0x2588
+#define PCI_DEVICE_ID_INTEL_E7221_IG   0x258a
+#define PCI_DEVICE_ID_INTEL_82946GZ_HB      0x2970
+#define PCI_DEVICE_ID_INTEL_82946GZ_IG      0x2972
+#define PCI_DEVICE_ID_INTEL_82G35_HB     0x2980
+#define PCI_DEVICE_ID_INTEL_82G35_IG     0x2982
+#define PCI_DEVICE_ID_INTEL_82965Q_HB       0x2990
+#define PCI_DEVICE_ID_INTEL_82965Q_IG       0x2992
+#define PCI_DEVICE_ID_INTEL_82965G_HB       0x29A0
+#define PCI_DEVICE_ID_INTEL_82965G_IG       0x29A2
+#define PCI_DEVICE_ID_INTEL_82965GM_HB      0x2A00
+#define PCI_DEVICE_ID_INTEL_82965GM_IG      0x2A02
+#define PCI_DEVICE_ID_INTEL_82965GME_HB     0x2A10
+#define PCI_DEVICE_ID_INTEL_82965GME_IG     0x2A12
+#define PCI_DEVICE_ID_INTEL_82945GME_HB     0x27AC
+#define PCI_DEVICE_ID_INTEL_82945GME_IG     0x27AE
+#define PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB        0xA010
+#define PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG        0xA011
+#define PCI_DEVICE_ID_INTEL_PINEVIEW_HB         0xA000
+#define PCI_DEVICE_ID_INTEL_PINEVIEW_IG         0xA001
+#define PCI_DEVICE_ID_INTEL_G33_HB          0x29C0
+#define PCI_DEVICE_ID_INTEL_G33_IG          0x29C2
+#define PCI_DEVICE_ID_INTEL_Q35_HB          0x29B0
+#define PCI_DEVICE_ID_INTEL_Q35_IG          0x29B2
+#define PCI_DEVICE_ID_INTEL_Q33_HB          0x29D0
+#define PCI_DEVICE_ID_INTEL_Q33_IG          0x29D2
+#define PCI_DEVICE_ID_INTEL_B43_HB          0x2E40
+#define PCI_DEVICE_ID_INTEL_B43_IG          0x2E42
+#define PCI_DEVICE_ID_INTEL_GM45_HB         0x2A40
+#define PCI_DEVICE_ID_INTEL_GM45_IG         0x2A42
+#define PCI_DEVICE_ID_INTEL_EAGLELAKE_HB        0x2E00
+#define PCI_DEVICE_ID_INTEL_EAGLELAKE_IG        0x2E02
+#define PCI_DEVICE_ID_INTEL_Q45_HB          0x2E10
+#define PCI_DEVICE_ID_INTEL_Q45_IG          0x2E12
+#define PCI_DEVICE_ID_INTEL_G45_HB          0x2E20
+#define PCI_DEVICE_ID_INTEL_G45_IG          0x2E22
+#define PCI_DEVICE_ID_INTEL_G41_HB          0x2E30
+#define PCI_DEVICE_ID_INTEL_G41_IG          0x2E32
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB          0x0040
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG          0x0042
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB          0x0044
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB         0x0062
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB    0x006a
+#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG          0x0046
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB  0x0100
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG  0x0102
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB  0x0104
+#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG  0x0106
+
+/* cover 915 and 945 variants */
+#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
+
+#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
+
+#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
+
+#define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
+
+#define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
+
+#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
+               IS_SNB)
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
new file mode 100644 (file)
index 0000000..e8ea682
--- /dev/null
@@ -0,0 +1,1516 @@
+/*
+ * Intel GTT (Graphics Translation Table) routines
+ *
+ * Caveat: This driver implements the linux agp interface, but this is far from
+ * a agp driver! GTT support ended up here for purely historical reasons: The
+ * old userspace intel graphics drivers needed an interface to map memory into
+ * the GTT. And the drm provides a default interface for graphic devices sitting
+ * on an agp port. So it made sense to fake the GTT support as an agp port to
+ * avoid having to create a new api.
+ *
+ * With gem this does not make much sense anymore, just needlessly complicates
+ * the code. But as long as the old graphics stack is still support, it's stuck
+ * here.
+ *
+ * /fairy-tale-mode off
+ */
+
+/*
+ * If we have Intel graphics, we're not going to have anything other than
+ * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
+ * on the Intel IOMMU support (CONFIG_DMAR).
+ * Only newer chipsets need to bother with this, of course.
+ */
+#ifdef CONFIG_DMAR
+#define USE_PCI_DMA_API 1
+#endif
+
+static const struct aper_size_info_fixed intel_i810_sizes[] =
+{
+       {64, 16384, 4},
+       /* The 32M mode still requires a 64k gatt */
+       {32, 8192, 4}
+};
+
+#define AGP_DCACHE_MEMORY      1
+#define AGP_PHYS_MEMORY                2
+#define INTEL_AGP_CACHED_MEMORY 3
+
+static struct gatt_mask intel_i810_masks[] =
+{
+       {.mask = I810_PTE_VALID, .type = 0},
+       {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
+       {.mask = I810_PTE_VALID, .type = 0},
+       {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED,
+        .type = INTEL_AGP_CACHED_MEMORY}
+};
+
+static struct _intel_private {
+       struct pci_dev *pcidev; /* device one */
+       u8 __iomem *registers;
+       u32 __iomem *gtt;               /* I915G */
+       int num_dcache_entries;
+       /* gtt_entries is the number of gtt entries that are already mapped
+        * to stolen memory.  Stolen memory is larger than the memory mapped
+        * through gtt_entries, as it includes some reserved space for the BIOS
+        * popup and for the GTT.
+        */
+       int gtt_entries;                        /* i830+ */
+       int gtt_total_size;
+       union {
+               void __iomem *i9xx_flush_page;
+               void *i8xx_flush_page;
+       };
+       struct page *i8xx_page;
+       struct resource ifp_resource;
+       int resource_valid;
+} intel_private;
+
+#ifdef USE_PCI_DMA_API
+static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
+{
+       *ret = pci_map_page(intel_private.pcidev, page, 0,
+                           PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+       if (pci_dma_mapping_error(intel_private.pcidev, *ret))
+               return -EINVAL;
+       return 0;
+}
+
+static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
+{
+       pci_unmap_page(intel_private.pcidev, dma,
+                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+}
+
+static void intel_agp_free_sglist(struct agp_memory *mem)
+{
+       struct sg_table st;
+
+       st.sgl = mem->sg_list;
+       st.orig_nents = st.nents = mem->page_count;
+
+       sg_free_table(&st);
+
+       mem->sg_list = NULL;
+       mem->num_sg = 0;
+}
+
+static int intel_agp_map_memory(struct agp_memory *mem)
+{
+       struct sg_table st;
+       struct scatterlist *sg;
+       int i;
+
+       DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
+
+       if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
+               return -ENOMEM;
+
+       mem->sg_list = sg = st.sgl;
+
+       for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
+               sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
+
+       mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
+                                mem->page_count, PCI_DMA_BIDIRECTIONAL);
+       if (unlikely(!mem->num_sg)) {
+               intel_agp_free_sglist(mem);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void intel_agp_unmap_memory(struct agp_memory *mem)
+{
+       DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
+
+       pci_unmap_sg(intel_private.pcidev, mem->sg_list,
+                    mem->page_count, PCI_DMA_BIDIRECTIONAL);
+       intel_agp_free_sglist(mem);
+}
+
+static void intel_agp_insert_sg_entries(struct agp_memory *mem,
+                                       off_t pg_start, int mask_type)
+{
+       struct scatterlist *sg;
+       int i, j;
+
+       j = pg_start;
+
+       WARN_ON(!mem->num_sg);
+
+       if (mem->num_sg == mem->page_count) {
+               for_each_sg(mem->sg_list, sg, mem->page_count, i) {
+                       writel(agp_bridge->driver->mask_memory(agp_bridge,
+                                       sg_dma_address(sg), mask_type),
+                                       intel_private.gtt+j);
+                       j++;
+               }
+       } else {
+               /* sg may merge pages, but we have to separate
+                * per-page addr for GTT */
+               unsigned int len, m;
+
+               for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
+                       len = sg_dma_len(sg) / PAGE_SIZE;
+                       for (m = 0; m < len; m++) {
+                               writel(agp_bridge->driver->mask_memory(agp_bridge,
+                                                                      sg_dma_address(sg) + m * PAGE_SIZE,
+                                                                      mask_type),
+                                      intel_private.gtt+j);
+                               j++;
+                       }
+               }
+       }
+       readl(intel_private.gtt+j-1);
+}
+
+#else
+
+static void intel_agp_insert_sg_entries(struct agp_memory *mem,
+                                       off_t pg_start, int mask_type)
+{
+       int i, j;
+       u32 cache_bits = 0;
+
+       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
+           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
+       {
+               cache_bits = I830_PTE_SYSTEM_CACHED;
+       }
+
+       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+               writel(agp_bridge->driver->mask_memory(agp_bridge,
+                               page_to_phys(mem->pages[i]), mask_type),
+                      intel_private.gtt+j);
+       }
+
+       readl(intel_private.gtt+j-1);
+}
+
+#endif
+
+static int intel_i810_fetch_size(void)
+{
+       u32 smram_miscc;
+       struct aper_size_info_fixed *values;
+
+       pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
+       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
+
+       if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
+               dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n");
+               return 0;
+       }
+       if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
+               agp_bridge->current_size = (void *) (values + 1);
+               agp_bridge->aperture_size_idx = 1;
+               return values[1].size;
+       } else {
+               agp_bridge->current_size = (void *) (values);
+               agp_bridge->aperture_size_idx = 0;
+               return values[0].size;
+       }
+
+       return 0;
+}
+
+static int intel_i810_configure(void)
+{
+       struct aper_size_info_fixed *current_size;
+       u32 temp;
+       int i;
+
+       current_size = A_SIZE_FIX(agp_bridge->current_size);
+
+       if (!intel_private.registers) {
+               pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
+               temp &= 0xfff80000;
+
+               intel_private.registers = ioremap(temp, 128 * 4096);
+               if (!intel_private.registers) {
+                       dev_err(&intel_private.pcidev->dev,
+                               "can't remap memory\n");
+                       return -ENOMEM;
+               }
+       }
+
+       if ((readl(intel_private.registers+I810_DRAM_CTL)
+               & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
+               /* This will need to be dynamically assigned */
+               dev_info(&intel_private.pcidev->dev,
+                        "detected 4MB dedicated video ram\n");
+               intel_private.num_dcache_entries = 1024;
+       }
+       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
+       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+       writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
+       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+
+       if (agp_bridge->driver->needs_scratch_page) {
+               for (i = 0; i < current_size->num_entries; i++) {
+                       writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+               }
+               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */
+       }
+       global_cache_flush();
+       return 0;
+}
+
+static void intel_i810_cleanup(void)
+{
+       writel(0, intel_private.registers+I810_PGETBL_CTL);
+       readl(intel_private.registers); /* PCI Posting. */
+       iounmap(intel_private.registers);
+}
+
+static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+{
+       return;
+}
+
+/* Exists to support ARGB cursors */
+static struct page *i8xx_alloc_pages(void)
+{
+       struct page *page;
+
+       page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
+       if (page == NULL)
+               return NULL;
+
+       if (set_pages_uc(page, 4) < 0) {
+               set_pages_wb(page, 4);
+               __free_pages(page, 2);
+               return NULL;
+       }
+       get_page(page);
+       atomic_inc(&agp_bridge->current_memory_agp);
+       return page;
+}
+
+static void i8xx_destroy_pages(struct page *page)
+{
+       if (page == NULL)
+               return;
+
+       set_pages_wb(page, 4);
+       put_page(page);
+       __free_pages(page, 2);
+       atomic_dec(&agp_bridge->current_memory_agp);
+}
+
+static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
+                                       int type)
+{
+       if (type < AGP_USER_TYPES)
+               return type;
+       else if (type == AGP_USER_CACHED_MEMORY)
+               return INTEL_AGP_CACHED_MEMORY;
+       else
+               return 0;
+}
+
+static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
+                               int type)
+{
+       int i, j, num_entries;
+       void *temp;
+       int ret = -EINVAL;
+       int mask_type;
+
+       if (mem->page_count == 0)
+               goto out;
+
+       temp = agp_bridge->current_size;
+       num_entries = A_SIZE_FIX(temp)->num_entries;
+
+       if ((pg_start + mem->page_count) > num_entries)
+               goto out_err;
+
+
+       for (j = pg_start; j < (pg_start + mem->page_count); j++) {
+               if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
+                       ret = -EBUSY;
+                       goto out_err;
+               }
+       }
+
+       if (type != mem->type)
+               goto out_err;
+
+       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+
+       switch (mask_type) {
+       case AGP_DCACHE_MEMORY:
+               if (!mem->is_flushed)
+                       global_cache_flush();
+               for (i = pg_start; i < (pg_start + mem->page_count); i++) {
+                       writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID,
+                              intel_private.registers+I810_PTE_BASE+(i*4));
+               }
+               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+               break;
+       case AGP_PHYS_MEMORY:
+       case AGP_NORMAL_MEMORY:
+               if (!mem->is_flushed)
+                       global_cache_flush();
+               for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+                       writel(agp_bridge->driver->mask_memory(agp_bridge,
+                                       page_to_phys(mem->pages[i]), mask_type),
+                              intel_private.registers+I810_PTE_BASE+(j*4));
+               }
+               readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
+               break;
+       default:
+               goto out_err;
+       }
+
+out:
+       ret = 0;
+out_err:
+       mem->is_flushed = true;
+       return ret;
+}
+
+static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
+                               int type)
+{
+       int i;
+
+       if (mem->page_count == 0)
+               return 0;
+
+       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+               writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+       }
+       readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+
+       return 0;
+}
+
+/*
+ * The i810/i830 requires a physical address to program its mouse
+ * pointer into hardware.
+ * However the Xserver still writes to it through the agp aperture.
+ */
+static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
+{
+       struct agp_memory *new;
+       struct page *page;
+
+       switch (pg_count) {
+       case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge);
+               break;
+       case 4:
+               /* kludge to get 4 physical pages for ARGB cursor */
+               page = i8xx_alloc_pages();
+               break;
+       default:
+               return NULL;
+       }
+
+       if (page == NULL)
+               return NULL;
+
+       new = agp_create_memory(pg_count);
+       if (new == NULL)
+               return NULL;
+
+       new->pages[0] = page;
+       if (pg_count == 4) {
+               /* kludge to get 4 physical pages for ARGB cursor */
+               new->pages[1] = new->pages[0] + 1;
+               new->pages[2] = new->pages[1] + 1;
+               new->pages[3] = new->pages[2] + 1;
+       }
+       new->page_count = pg_count;
+       new->num_scratch_pages = pg_count;
+       new->type = AGP_PHYS_MEMORY;
+       new->physical = page_to_phys(new->pages[0]);
+       return new;
+}
+
+static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
+{
+       struct agp_memory *new;
+
+       if (type == AGP_DCACHE_MEMORY) {
+               if (pg_count != intel_private.num_dcache_entries)
+                       return NULL;
+
+               new = agp_create_memory(1);
+               if (new == NULL)
+                       return NULL;
+
+               new->type = AGP_DCACHE_MEMORY;
+               new->page_count = pg_count;
+               new->num_scratch_pages = 0;
+               agp_free_page_array(new);
+               return new;
+       }
+       if (type == AGP_PHYS_MEMORY)
+               return alloc_agpphysmem_i8xx(pg_count, type);
+       return NULL;
+}
+
+static void intel_i810_free_by_type(struct agp_memory *curr)
+{
+       agp_free_key(curr->key);
+       if (curr->type == AGP_PHYS_MEMORY) {
+               if (curr->page_count == 4)
+                       i8xx_destroy_pages(curr->pages[0]);
+               else {
+                       agp_bridge->driver->agp_destroy_page(curr->pages[0],
+                                                            AGP_PAGE_DESTROY_UNMAP);
+                       agp_bridge->driver->agp_destroy_page(curr->pages[0],
+                                                            AGP_PAGE_DESTROY_FREE);
+               }
+               agp_free_page_array(curr);
+       }
+       kfree(curr);
+}
+
+static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
+                                           dma_addr_t addr, int type)
+{
+       /* Type checking must be done elsewhere */
+       return addr | bridge->driver->masks[type].mask;
+}
+
+static struct aper_size_info_fixed intel_i830_sizes[] =
+{
+       {128, 32768, 5},
+       /* The 64M mode still requires a 128k gatt */
+       {64, 16384, 5},
+       {256, 65536, 6},
+       {512, 131072, 7},
+};
+
+static void intel_i830_init_gtt_entries(void)
+{
+       u16 gmch_ctrl;
+       int gtt_entries = 0;
+       u8 rdct;
+       int local = 0;
+       static const int ddt[4] = { 0, 16, 32, 64 };
+       int size; /* reserved space (in kb) at the top of stolen memory */
+
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+
+       if (IS_I965) {
+               u32 pgetbl_ctl;
+               pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+
+               /* The 965 has a field telling us the size of the GTT,
+                * which may be larger than what is necessary to map the
+                * aperture.
+                */
+               switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+               case I965_PGETBL_SIZE_128KB:
+                       size = 128;
+                       break;
+               case I965_PGETBL_SIZE_256KB:
+                       size = 256;
+                       break;
+               case I965_PGETBL_SIZE_512KB:
+                       size = 512;
+                       break;
+               case I965_PGETBL_SIZE_1MB:
+                       size = 1024;
+                       break;
+               case I965_PGETBL_SIZE_2MB:
+                       size = 2048;
+                       break;
+               case I965_PGETBL_SIZE_1_5MB:
+                       size = 1024 + 512;
+                       break;
+               default:
+                       dev_info(&intel_private.pcidev->dev,
+                                "unknown page table size, assuming 512KB\n");
+                       size = 512;
+               }
+               size += 4; /* add in BIOS popup space */
+       } else if (IS_G33 && !IS_PINEVIEW) {
+       /* G33's GTT size defined in gmch_ctrl */
+               switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
+               case G33_PGETBL_SIZE_1M:
+                       size = 1024;
+                       break;
+               case G33_PGETBL_SIZE_2M:
+                       size = 2048;
+                       break;
+               default:
+                       dev_info(&agp_bridge->dev->dev,
+                                "unknown page table size 0x%x, assuming 512KB\n",
+                               (gmch_ctrl & G33_PGETBL_SIZE_MASK));
+                       size = 512;
+               }
+               size += 4;
+       } else if (IS_G4X || IS_PINEVIEW) {
+               /* On 4 series hardware, GTT stolen is separate from graphics
+                * stolen, ignore it in stolen gtt entries counting.  However,
+                * 4KB of the stolen memory doesn't get mapped to the GTT.
+                */
+               size = 4;
+       } else {
+               /* On previous hardware, the GTT size was just what was
+                * required to map the aperture.
+                */
+               size = agp_bridge->driver->fetch_size() + 4;
+       }
+
+       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
+           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
+               switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+               case I830_GMCH_GMS_STOLEN_512:
+                       gtt_entries = KB(512) - KB(size);
+                       break;
+               case I830_GMCH_GMS_STOLEN_1024:
+                       gtt_entries = MB(1) - KB(size);
+                       break;
+               case I830_GMCH_GMS_STOLEN_8192:
+                       gtt_entries = MB(8) - KB(size);
+                       break;
+               case I830_GMCH_GMS_LOCAL:
+                       rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
+                       gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
+                                       MB(ddt[I830_RDRAM_DDT(rdct)]);
+                       local = 1;
+                       break;
+               default:
+                       gtt_entries = 0;
+                       break;
+               }
+       } else if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
+                  agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) {
+               /*
+                * SandyBridge has new memory control reg at 0x50.w
+                */
+               u16 snb_gmch_ctl;
+               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+               switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
+               case SNB_GMCH_GMS_STOLEN_32M:
+                       gtt_entries = MB(32) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_64M:
+                       gtt_entries = MB(64) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_96M:
+                       gtt_entries = MB(96) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_128M:
+                       gtt_entries = MB(128) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_160M:
+                       gtt_entries = MB(160) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_192M:
+                       gtt_entries = MB(192) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_224M:
+                       gtt_entries = MB(224) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_256M:
+                       gtt_entries = MB(256) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_288M:
+                       gtt_entries = MB(288) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_320M:
+                       gtt_entries = MB(320) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_352M:
+                       gtt_entries = MB(352) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_384M:
+                       gtt_entries = MB(384) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_416M:
+                       gtt_entries = MB(416) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_448M:
+                       gtt_entries = MB(448) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_480M:
+                       gtt_entries = MB(480) - KB(size);
+                       break;
+               case SNB_GMCH_GMS_STOLEN_512M:
+                       gtt_entries = MB(512) - KB(size);
+                       break;
+               }
+       } else {
+               switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
+               case I855_GMCH_GMS_STOLEN_1M:
+                       gtt_entries = MB(1) - KB(size);
+                       break;
+               case I855_GMCH_GMS_STOLEN_4M:
+                       gtt_entries = MB(4) - KB(size);
+                       break;
+               case I855_GMCH_GMS_STOLEN_8M:
+                       gtt_entries = MB(8) - KB(size);
+                       break;
+               case I855_GMCH_GMS_STOLEN_16M:
+                       gtt_entries = MB(16) - KB(size);
+                       break;
+               case I855_GMCH_GMS_STOLEN_32M:
+                       gtt_entries = MB(32) - KB(size);
+                       break;
+               case I915_GMCH_GMS_STOLEN_48M:
+                       /* Check it's really I915G */
+                       if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
+                               gtt_entries = MB(48) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case I915_GMCH_GMS_STOLEN_64M:
+                       /* Check it's really I915G */
+                       if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
+                               gtt_entries = MB(64) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case G33_GMCH_GMS_STOLEN_128M:
+                       if (IS_G33 || IS_I965 || IS_G4X)
+                               gtt_entries = MB(128) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case G33_GMCH_GMS_STOLEN_256M:
+                       if (IS_G33 || IS_I965 || IS_G4X)
+                               gtt_entries = MB(256) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case INTEL_GMCH_GMS_STOLEN_96M:
+                       if (IS_I965 || IS_G4X)
+                               gtt_entries = MB(96) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case INTEL_GMCH_GMS_STOLEN_160M:
+                       if (IS_I965 || IS_G4X)
+                               gtt_entries = MB(160) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case INTEL_GMCH_GMS_STOLEN_224M:
+                       if (IS_I965 || IS_G4X)
+                               gtt_entries = MB(224) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               case INTEL_GMCH_GMS_STOLEN_352M:
+                       if (IS_I965 || IS_G4X)
+                               gtt_entries = MB(352) - KB(size);
+                       else
+                               gtt_entries = 0;
+                       break;
+               default:
+                       gtt_entries = 0;
+                       break;
+               }
+       }
+       if (gtt_entries > 0) {
+               dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
+                      gtt_entries / KB(1), local ? "local" : "stolen");
+               gtt_entries /= KB(4);
+       } else {
+               dev_info(&agp_bridge->dev->dev,
+                      "no pre-allocated video memory detected\n");
+               gtt_entries = 0;
+       }
+
+       intel_private.gtt_entries = gtt_entries;
+}
+
+static void intel_i830_fini_flush(void)
+{
+       kunmap(intel_private.i8xx_page);
+       intel_private.i8xx_flush_page = NULL;
+       unmap_page_from_agp(intel_private.i8xx_page);
+
+       __free_page(intel_private.i8xx_page);
+       intel_private.i8xx_page = NULL;
+}
+
+static void intel_i830_setup_flush(void)
+{
+       /* return if we've already set the flush mechanism up */
+       if (intel_private.i8xx_page)
+               return;
+
+       intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
+       if (!intel_private.i8xx_page)
+               return;
+
+       intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
+       if (!intel_private.i8xx_flush_page)
+               intel_i830_fini_flush();
+}
+
+/* The chipset_flush interface needs to get data that has already been
+ * flushed out of the CPU all the way out to main memory, because the GPU
+ * doesn't snoop those buffers.
+ *
+ * The 8xx series doesn't have the same lovely interface for flushing the
+ * chipset write buffers that the later chips do. According to the 865
+ * specs, it's 64 octwords, or 1KB.  So, to get those previous things in
+ * that buffer out, we just fill 1KB and clflush it out, on the assumption
+ * that it'll push whatever was in there out.  It appears to work.
+ */
+static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
+{
+       unsigned int *pg = intel_private.i8xx_flush_page;
+
+       memset(pg, 0, 1024);
+
+       if (cpu_has_clflush)
+               clflush_cache_range(pg, 1024);
+       else if (wbinvd_on_all_cpus() != 0)
+               printk(KERN_ERR "Timed out waiting for cache flush.\n");
+}
+
+/* The intel i830 automatically initializes the agp aperture during POST.
+ * Use the memory already set aside for in the GTT.
+ */
+static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
+{
+       int page_order;
+       struct aper_size_info_fixed *size;
+       int num_entries;
+       u32 temp;
+
+       size = agp_bridge->current_size;
+       page_order = size->page_order;
+       num_entries = size->num_entries;
+       agp_bridge->gatt_table_real = NULL;
+
+       pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
+       temp &= 0xfff80000;
+
+       intel_private.registers = ioremap(temp, 128 * 4096);
+       if (!intel_private.registers)
+               return -ENOMEM;
+
+       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
+       global_cache_flush();   /* FIXME: ?? */
+
+       /* we have to call this as early as possible after the MMIO base address is known */
+       intel_i830_init_gtt_entries();
+
+       agp_bridge->gatt_table = NULL;
+
+       agp_bridge->gatt_bus_addr = temp;
+
+       return 0;
+}
+
+/* Return the gatt table to a sane state. Use the top of stolen
+ * memory for the GTT.
+ */
+static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
+{
+       return 0;
+}
+
+static int intel_i830_fetch_size(void)
+{
+       u16 gmch_ctrl;
+       struct aper_size_info_fixed *values;
+
+       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
+
+       if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
+           agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
+               /* 855GM/852GM/865G has 128MB aperture size */
+               agp_bridge->current_size = (void *) values;
+               agp_bridge->aperture_size_idx = 0;
+               return values[0].size;
+       }
+
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+
+       if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
+               agp_bridge->current_size = (void *) values;
+               agp_bridge->aperture_size_idx = 0;
+               return values[0].size;
+       } else {
+               agp_bridge->current_size = (void *) (values + 1);
+               agp_bridge->aperture_size_idx = 1;
+               return values[1].size;
+       }
+
+       return 0;
+}
+
+static int intel_i830_configure(void)
+{
+       struct aper_size_info_fixed *current_size;
+       u32 temp;
+       u16 gmch_ctrl;
+       int i;
+
+       current_size = A_SIZE_FIX(agp_bridge->current_size);
+
+       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
+       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+       gmch_ctrl |= I830_GMCH_ENABLED;
+       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
+
+       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
+       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+
+       if (agp_bridge->driver->needs_scratch_page) {
+               for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
+                       writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+               }
+               readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */
+       }
+
+       global_cache_flush();
+
+       intel_i830_setup_flush();
+       return 0;
+}
+
+static void intel_i830_cleanup(void)
+{
+       iounmap(intel_private.registers);
+}
+
+static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
+{
+       int i, j, num_entries;
+       void *temp;
+       int ret = -EINVAL;
+       int mask_type;
+
+       if (mem->page_count == 0)
+               goto out;
+
+       temp = agp_bridge->current_size;
+       num_entries = A_SIZE_FIX(temp)->num_entries;
+
+       if (pg_start < intel_private.gtt_entries) {
+               dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
+                          "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
+                          pg_start, intel_private.gtt_entries);
+
+               dev_info(&intel_private.pcidev->dev,
+                        "trying to insert into local/stolen memory\n");
+               goto out_err;
+       }
+
+       if ((pg_start + mem->page_count) > num_entries)
+               goto out_err;
+
+       /* The i830 can't check the GTT for entries since its read only,
+        * depend on the caller to make the correct offset decisions.
+        */
+
+       if (type != mem->type)
+               goto out_err;
+
+       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+
+       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
+           mask_type != INTEL_AGP_CACHED_MEMORY)
+               goto out_err;
+
+       if (!mem->is_flushed)
+               global_cache_flush();
+
+       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+               writel(agp_bridge->driver->mask_memory(agp_bridge,
+                               page_to_phys(mem->pages[i]), mask_type),
+                      intel_private.registers+I810_PTE_BASE+(j*4));
+       }
+       readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
+
+out:
+       ret = 0;
+out_err:
+       mem->is_flushed = true;
+       return ret;
+}
+
+static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
+{
+       int i;
+
+       if (mem->page_count == 0)
+               return 0;
+
+       if (pg_start < intel_private.gtt_entries) {
+               dev_info(&intel_private.pcidev->dev,
+                        "trying to disable local/stolen memory\n");
+               return -EINVAL;
+       }
+
+       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+               writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+       }
+       readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+
+       return 0;
+}
+
+static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
+{
+       if (type == AGP_PHYS_MEMORY)
+               return alloc_agpphysmem_i8xx(pg_count, type);
+       /* always return NULL for other allocation types for now */
+       return NULL;
+}
+
+static int intel_alloc_chipset_flush_resource(void)
+{
+       int ret;
+       ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
+                                    PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
+                                    pcibios_align_resource, agp_bridge->dev);
+
+       return ret;
+}
+
+static void intel_i915_setup_chipset_flush(void)
+{
+       int ret;
+       u32 temp;
+
+       pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
+       if (!(temp & 0x1)) {
+               intel_alloc_chipset_flush_resource();
+               intel_private.resource_valid = 1;
+               pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+       } else {
+               temp &= ~1;
+
+               intel_private.resource_valid = 1;
+               intel_private.ifp_resource.start = temp;
+               intel_private.ifp_resource.end = temp + PAGE_SIZE;
+               ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
+               /* some BIOSes reserve this area in a pnp some don't */
+               if (ret)
+                       intel_private.resource_valid = 0;
+       }
+}
+
+static void intel_i965_g33_setup_chipset_flush(void)
+{
+       u32 temp_hi, temp_lo;
+       int ret;
+
+       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
+       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
+
+       if (!(temp_lo & 0x1)) {
+
+               intel_alloc_chipset_flush_resource();
+
+               intel_private.resource_valid = 1;
+               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
+                       upper_32_bits(intel_private.ifp_resource.start));
+               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+       } else {
+               u64 l64;
+
+               temp_lo &= ~0x1;
+               l64 = ((u64)temp_hi << 32) | temp_lo;
+
+               intel_private.resource_valid = 1;
+               intel_private.ifp_resource.start = l64;
+               intel_private.ifp_resource.end = l64 + PAGE_SIZE;
+               ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
+               /* some BIOSes reserve this area in a pnp some don't */
+               if (ret)
+                       intel_private.resource_valid = 0;
+       }
+}
+
+static void intel_i9xx_setup_flush(void)
+{
+       /* return if already configured */
+       if (intel_private.ifp_resource.start)
+               return;
+
+       if (IS_SNB)
+               return;
+
+       /* setup a resource for this object */
+       intel_private.ifp_resource.name = "Intel Flush Page";
+       intel_private.ifp_resource.flags = IORESOURCE_MEM;
+
+       /* Setup chipset flush for 915 */
+       if (IS_I965 || IS_G33 || IS_G4X) {
+               intel_i965_g33_setup_chipset_flush();
+       } else {
+               intel_i915_setup_chipset_flush();
+       }
+
+       if (intel_private.ifp_resource.start) {
+               intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE);
+               if (!intel_private.i9xx_flush_page)
+                       dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing");
+       }
+}
+
+static int intel_i915_configure(void)
+{
+       struct aper_size_info_fixed *current_size;
+       u32 temp;
+       u16 gmch_ctrl;
+       int i;
+
+       current_size = A_SIZE_FIX(agp_bridge->current_size);
+
+       pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp);
+
+       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+       gmch_ctrl |= I830_GMCH_ENABLED;
+       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
+
+       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
+       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+
+       if (agp_bridge->driver->needs_scratch_page) {
+               for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
+                       writel(agp_bridge->scratch_page, intel_private.gtt+i);
+               }
+               readl(intel_private.gtt+i-1);   /* PCI Posting. */
+       }
+
+       global_cache_flush();
+
+       intel_i9xx_setup_flush();
+
+       return 0;
+}
+
+static void intel_i915_cleanup(void)
+{
+       if (intel_private.i9xx_flush_page)
+               iounmap(intel_private.i9xx_flush_page);
+       if (intel_private.resource_valid)
+               release_resource(&intel_private.ifp_resource);
+       intel_private.ifp_resource.start = 0;
+       intel_private.resource_valid = 0;
+       iounmap(intel_private.gtt);
+       iounmap(intel_private.registers);
+}
+
+static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
+{
+       if (intel_private.i9xx_flush_page)
+               writel(1, intel_private.i9xx_flush_page);
+}
+
+static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
+{
+       int num_entries;
+       void *temp;
+       int ret = -EINVAL;
+       int mask_type;
+
+       if (mem->page_count == 0)
+               goto out;
+
+       temp = agp_bridge->current_size;
+       num_entries = A_SIZE_FIX(temp)->num_entries;
+
+       if (pg_start < intel_private.gtt_entries) {
+               dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
+                          "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
+                          pg_start, intel_private.gtt_entries);
+
+               dev_info(&intel_private.pcidev->dev,
+                        "trying to insert into local/stolen memory\n");
+               goto out_err;
+       }
+
+       if ((pg_start + mem->page_count) > num_entries)
+               goto out_err;
+
+       /* The i915 can't check the GTT for entries since it's read only;
+        * depend on the caller to make the correct offset decisions.
+        */
+
+       if (type != mem->type)
+               goto out_err;
+
+       mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+
+       if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
+           mask_type != INTEL_AGP_CACHED_MEMORY)
+               goto out_err;
+
+       if (!mem->is_flushed)
+               global_cache_flush();
+
+       intel_agp_insert_sg_entries(mem, pg_start, mask_type);
+
+ out:
+       ret = 0;
+ out_err:
+       mem->is_flushed = true;
+       return ret;
+}
+
+static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
+{
+       int i;
+
+       if (mem->page_count == 0)
+               return 0;
+
+       if (pg_start < intel_private.gtt_entries) {
+               dev_info(&intel_private.pcidev->dev,
+                        "trying to disable local/stolen memory\n");
+               return -EINVAL;
+       }
+
+       for (i = pg_start; i < (mem->page_count + pg_start); i++)
+               writel(agp_bridge->scratch_page, intel_private.gtt+i);
+
+       readl(intel_private.gtt+i-1);
+
+       return 0;
+}
+
+/* Return the aperture size by just checking the resource length.  The effect
+ * described in the spec of the MSAC registers is just changing of the
+ * resource size.
+ */
+static int intel_i9xx_fetch_size(void)
+{
+       int num_sizes = ARRAY_SIZE(intel_i830_sizes);
+       int aper_size; /* size in megabytes */
+       int i;
+
+       aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1);
+
+       for (i = 0; i < num_sizes; i++) {
+               if (aper_size == intel_i830_sizes[i].size) {
+                       agp_bridge->current_size = intel_i830_sizes + i;
+                       return aper_size;
+               }
+       }
+
+       return 0;
+}
+
+/* The intel i915 automatically initializes the agp aperture during POST.
+ * Use the memory already set aside for in the GTT.
+ */
+static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
+{
+       int page_order;
+       struct aper_size_info_fixed *size;
+       int num_entries;
+       u32 temp, temp2;
+       int gtt_map_size = 256 * 1024;
+
+       size = agp_bridge->current_size;
+       page_order = size->page_order;
+       num_entries = size->num_entries;
+       agp_bridge->gatt_table_real = NULL;
+
+       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
+       pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
+
+       if (IS_G33)
+           gtt_map_size = 1024 * 1024; /* 1M on G33 */
+       intel_private.gtt = ioremap(temp2, gtt_map_size);
+       if (!intel_private.gtt)
+               return -ENOMEM;
+
+       intel_private.gtt_total_size = gtt_map_size / 4;
+
+       temp &= 0xfff80000;
+
+       intel_private.registers = ioremap(temp, 128 * 4096);
+       if (!intel_private.registers) {
+               iounmap(intel_private.gtt);
+               return -ENOMEM;
+       }
+
+       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
+       global_cache_flush();   /* FIXME: ? */
+
+       /* we have to call this as early as possible after the MMIO base address is known */
+       intel_i830_init_gtt_entries();
+
+       agp_bridge->gatt_table = NULL;
+
+       agp_bridge->gatt_bus_addr = temp;
+
+       return 0;
+}
+
+/*
+ * The i965 supports 36-bit physical addresses, but to keep
+ * the format of the GTT the same, the bits that don't fit
+ * in a 32-bit word are shifted down to bits 4..7.
+ *
+ * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
+ * is always zero on 32-bit architectures, so no need to make
+ * this conditional.
+ */
+static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
+                                           dma_addr_t addr, int type)
+{
+       /* Shift high bits down */
+       addr |= (addr >> 28) & 0xf0;
+
+       /* Type checking must be done elsewhere */
+       return addr | bridge->driver->masks[type].mask;
+}
+
+static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
+{
+       u16 snb_gmch_ctl;
+
+       switch (agp_bridge->dev->device) {
+       case PCI_DEVICE_ID_INTEL_GM45_HB:
+       case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB:
+       case PCI_DEVICE_ID_INTEL_Q45_HB:
+       case PCI_DEVICE_ID_INTEL_G45_HB:
+       case PCI_DEVICE_ID_INTEL_G41_HB:
+       case PCI_DEVICE_ID_INTEL_B43_HB:
+       case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB:
+       case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
+       case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
+       case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
+               *gtt_offset = *gtt_size = MB(2);
+               break;
+       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
+       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
+               *gtt_offset = MB(2);
+
+               pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+               switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
+               default:
+               case SNB_GTT_SIZE_0M:
+                       printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
+                       *gtt_size = MB(0);
+                       break;
+               case SNB_GTT_SIZE_1M:
+                       *gtt_size = MB(1);
+                       break;
+               case SNB_GTT_SIZE_2M:
+                       *gtt_size = MB(2);
+                       break;
+               }
+               break;
+       default:
+               *gtt_offset = *gtt_size = KB(512);
+       }
+}
+
+/* The intel i965 automatically initializes the agp aperture during POST.
+ * Use the memory already set aside for in the GTT.
+ */
+static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
+{
+       int page_order;
+       struct aper_size_info_fixed *size;
+       int num_entries;
+       u32 temp;
+       int gtt_offset, gtt_size;
+
+       size = agp_bridge->current_size;
+       page_order = size->page_order;
+       num_entries = size->num_entries;
+       agp_bridge->gatt_table_real = NULL;
+
+       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
+
+       temp &= 0xfff00000;
+
+       intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
+
+       intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
+
+       if (!intel_private.gtt)
+               return -ENOMEM;
+
+       intel_private.gtt_total_size = gtt_size / 4;
+
+       intel_private.registers = ioremap(temp, 128 * 4096);
+       if (!intel_private.registers) {
+               iounmap(intel_private.gtt);
+               return -ENOMEM;
+       }
+
+       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
+       global_cache_flush();   /* FIXME: ? */
+
+       /* we have to call this as early as possible after the MMIO base address is known */
+       intel_i830_init_gtt_entries();
+
+       agp_bridge->gatt_table = NULL;
+
+       agp_bridge->gatt_bus_addr = temp;
+
+       return 0;
+}
+
+static const struct agp_bridge_driver intel_810_driver = {
+       .owner                  = THIS_MODULE,
+       .aperture_sizes         = intel_i810_sizes,
+       .size_type              = FIXED_APER_SIZE,
+       .num_aperture_sizes     = 2,
+       .needs_scratch_page     = true,
+       .configure              = intel_i810_configure,
+       .fetch_size             = intel_i810_fetch_size,
+       .cleanup                = intel_i810_cleanup,
+       .mask_memory            = intel_i810_mask_memory,
+       .masks                  = intel_i810_masks,
+       .agp_enable             = intel_i810_agp_enable,
+       .cache_flush            = global_cache_flush,
+       .create_gatt_table      = agp_generic_create_gatt_table,
+       .free_gatt_table        = agp_generic_free_gatt_table,
+       .insert_memory          = intel_i810_insert_entries,
+       .remove_memory          = intel_i810_remove_entries,
+       .alloc_by_type          = intel_i810_alloc_by_type,
+       .free_by_type           = intel_i810_free_by_type,
+       .agp_alloc_page         = agp_generic_alloc_page,
+       .agp_alloc_pages        = agp_generic_alloc_pages,
+       .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_destroy_pages      = agp_generic_destroy_pages,
+       .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
+};
+
+static const struct agp_bridge_driver intel_830_driver = {
+       .owner                  = THIS_MODULE,
+       .aperture_sizes         = intel_i830_sizes,
+       .size_type              = FIXED_APER_SIZE,
+       .num_aperture_sizes     = 4,
+       .needs_scratch_page     = true,
+       .configure              = intel_i830_configure,
+       .fetch_size             = intel_i830_fetch_size,
+       .cleanup                = intel_i830_cleanup,
+       .mask_memory            = intel_i810_mask_memory,
+       .masks                  = intel_i810_masks,
+       .agp_enable             = intel_i810_agp_enable,
+       .cache_flush            = global_cache_flush,
+       .create_gatt_table      = intel_i830_create_gatt_table,
+       .free_gatt_table        = intel_i830_free_gatt_table,
+       .insert_memory          = intel_i830_insert_entries,
+       .remove_memory          = intel_i830_remove_entries,
+       .alloc_by_type          = intel_i830_alloc_by_type,
+       .free_by_type           = intel_i810_free_by_type,
+       .agp_alloc_page         = agp_generic_alloc_page,
+       .agp_alloc_pages        = agp_generic_alloc_pages,
+       .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_destroy_pages      = agp_generic_destroy_pages,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i830_chipset_flush,
+};
+
+static const struct agp_bridge_driver intel_915_driver = {
+       .owner                  = THIS_MODULE,
+       .aperture_sizes         = intel_i830_sizes,
+       .size_type              = FIXED_APER_SIZE,
+       .num_aperture_sizes     = 4,
+       .needs_scratch_page     = true,
+       .configure              = intel_i915_configure,
+       .fetch_size             = intel_i9xx_fetch_size,
+       .cleanup                = intel_i915_cleanup,
+       .mask_memory            = intel_i810_mask_memory,
+       .masks                  = intel_i810_masks,
+       .agp_enable             = intel_i810_agp_enable,
+       .cache_flush            = global_cache_flush,
+       .create_gatt_table      = intel_i915_create_gatt_table,
+       .free_gatt_table        = intel_i830_free_gatt_table,
+       .insert_memory          = intel_i915_insert_entries,
+       .remove_memory          = intel_i915_remove_entries,
+       .alloc_by_type          = intel_i830_alloc_by_type,
+       .free_by_type           = intel_i810_free_by_type,
+       .agp_alloc_page         = agp_generic_alloc_page,
+       .agp_alloc_pages        = agp_generic_alloc_pages,
+       .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_destroy_pages      = agp_generic_destroy_pages,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+       .agp_map_page           = intel_agp_map_page,
+       .agp_unmap_page         = intel_agp_unmap_page,
+       .agp_map_memory         = intel_agp_map_memory,
+       .agp_unmap_memory       = intel_agp_unmap_memory,
+#endif
+};
+
+static const struct agp_bridge_driver intel_i965_driver = {
+       .owner                  = THIS_MODULE,
+       .aperture_sizes         = intel_i830_sizes,
+       .size_type              = FIXED_APER_SIZE,
+       .num_aperture_sizes     = 4,
+       .needs_scratch_page     = true,
+       .configure              = intel_i915_configure,
+       .fetch_size             = intel_i9xx_fetch_size,
+       .cleanup                = intel_i915_cleanup,
+       .mask_memory            = intel_i965_mask_memory,
+       .masks                  = intel_i810_masks,
+       .agp_enable             = intel_i810_agp_enable,
+       .cache_flush            = global_cache_flush,
+       .create_gatt_table      = intel_i965_create_gatt_table,
+       .free_gatt_table        = intel_i830_free_gatt_table,
+       .insert_memory          = intel_i915_insert_entries,
+       .remove_memory          = intel_i915_remove_entries,
+       .alloc_by_type          = intel_i830_alloc_by_type,
+       .free_by_type           = intel_i810_free_by_type,
+       .agp_alloc_page         = agp_generic_alloc_page,
+       .agp_alloc_pages        = agp_generic_alloc_pages,
+       .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_destroy_pages      = agp_generic_destroy_pages,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+       .agp_map_page           = intel_agp_map_page,
+       .agp_unmap_page         = intel_agp_unmap_page,
+       .agp_map_memory         = intel_agp_map_memory,
+       .agp_unmap_memory       = intel_agp_unmap_memory,
+#endif
+};
+
+static const struct agp_bridge_driver intel_g33_driver = {
+       .owner                  = THIS_MODULE,
+       .aperture_sizes         = intel_i830_sizes,
+       .size_type              = FIXED_APER_SIZE,
+       .num_aperture_sizes     = 4,
+       .needs_scratch_page     = true,
+       .configure              = intel_i915_configure,
+       .fetch_size             = intel_i9xx_fetch_size,
+       .cleanup                = intel_i915_cleanup,
+       .mask_memory            = intel_i965_mask_memory,
+       .masks                  = intel_i810_masks,
+       .agp_enable             = intel_i810_agp_enable,
+       .cache_flush            = global_cache_flush,
+       .create_gatt_table      = intel_i915_create_gatt_table,
+       .free_gatt_table        = intel_i830_free_gatt_table,
+       .insert_memory          = intel_i915_insert_entries,
+       .remove_memory          = intel_i915_remove_entries,
+       .alloc_by_type          = intel_i830_alloc_by_type,
+       .free_by_type           = intel_i810_free_by_type,
+       .agp_alloc_page         = agp_generic_alloc_page,
+       .agp_alloc_pages        = agp_generic_alloc_pages,
+       .agp_destroy_page       = agp_generic_destroy_page,
+       .agp_destroy_pages      = agp_generic_destroy_pages,
+       .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+       .agp_map_page           = intel_agp_map_page,
+       .agp_unmap_page         = intel_agp_unmap_page,
+       .agp_map_memory         = intel_agp_map_memory,
+       .agp_unmap_memory       = intel_agp_unmap_memory,
+#endif
+};
index 10f24e3..b9734a9 100644 (file)
@@ -310,6 +310,7 @@ static const struct agp_bridge_driver nvidia_driver = {
        .aperture_sizes         = nvidia_generic_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 5,
+       .needs_scratch_page     = true,
        .configure              = nvidia_configure,
        .fetch_size             = nvidia_fetch_size,
        .cleanup                = nvidia_cleanup,
index 6c3837a..29aacd8 100644 (file)
@@ -125,6 +125,7 @@ static struct agp_bridge_driver sis_driver = {
        .aperture_sizes         = sis_generic_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 7,
+       .needs_scratch_page     = true,
        .configure              = sis_configure,
        .fetch_size             = sis_fetch_size,
        .cleanup                = sis_cleanup,
@@ -415,14 +416,6 @@ static struct pci_device_id agp_sis_pci_table[] = {
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
        },
-       {
-               .class          = (PCI_CLASS_BRIDGE_HOST << 8),
-               .class_mask     = ~0,
-               .vendor         = PCI_VENDOR_ID_SI,
-               .device         = PCI_DEVICE_ID_SI_760,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-       },
        { }
 };
 
index 6f48931..95db713 100644 (file)
@@ -28,6 +28,7 @@
  */
 static int uninorth_rev;
 static int is_u3;
+static u32 scratch_value;
 
 #define DEFAULT_APERTURE_SIZE 256
 #define DEFAULT_APERTURE_STRING "256"
@@ -172,7 +173,7 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start, int ty
 
        gp = (u32 *) &agp_bridge->gatt_table[pg_start];
        for (i = 0; i < mem->page_count; ++i) {
-               if (gp[i]) {
+               if (gp[i] != scratch_value) {
                        dev_info(&agp_bridge->dev->dev,
                                 "uninorth_insert_memory: entry 0x%x occupied (%x)\n",
                                 i, gp[i]);
@@ -214,8 +215,9 @@ int uninorth_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
                return 0;
 
        gp = (u32 *) &agp_bridge->gatt_table[pg_start];
-       for (i = 0; i < mem->page_count; ++i)
-               gp[i] = 0;
+       for (i = 0; i < mem->page_count; ++i) {
+               gp[i] = scratch_value;
+       }
        mb();
        uninorth_tlbflush(mem);
 
@@ -421,8 +423,13 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
 
        bridge->gatt_bus_addr = virt_to_phys(table);
 
+       if (is_u3)
+               scratch_value = (page_to_phys(agp_bridge->scratch_page_page) >> PAGE_SHIFT) | 0x80000000UL;
+       else
+               scratch_value = cpu_to_le32((page_to_phys(agp_bridge->scratch_page_page) & 0xFFFFF000UL) |
+                               0x1UL);
        for (i = 0; i < num_entries; i++)
-               bridge->gatt_table[i] = 0;
+               bridge->gatt_table[i] = scratch_value;
 
        return 0;
 
@@ -519,6 +526,7 @@ const struct agp_bridge_driver uninorth_agp_driver = {
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
        .cant_use_aperture      = true,
+       .needs_scratch_page     = true,
 };
 
 const struct agp_bridge_driver u3_agp_driver = {
index d3bd243..df67e80 100644 (file)
@@ -175,6 +175,7 @@ static const struct agp_bridge_driver via_agp3_driver = {
        .aperture_sizes         = agp3_generic_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 10,
+       .needs_scratch_page     = true,
        .configure              = via_configure_agp3,
        .fetch_size             = via_fetch_size_agp3,
        .cleanup                = via_cleanup_agp3,
@@ -201,6 +202,7 @@ static const struct agp_bridge_driver via_driver = {
        .aperture_sizes         = via_generic_sizes,
        .size_type              = U8_APER_SIZE,
        .num_aperture_sizes     = 9,
+       .needs_scratch_page     = true,
        .configure              = via_configure,
        .fetch_size             = via_fetch_size,
        .cleanup                = via_cleanup,
index 305c590..88910e5 100644 (file)
@@ -9,6 +9,7 @@ menuconfig DRM
        depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU
        select I2C
        select I2C_ALGOBIT
+       select SLOW_WORK
        help
          Kernel-level support for the Direct Rendering Infrastructure (DRI)
          introduced in XFree86 4.0. If you say Y here, you need to select
@@ -59,6 +60,7 @@ config DRM_RADEON
        select FW_LOADER
         select DRM_KMS_HELPER
         select DRM_TTM
+       select POWER_SUPPLY
        help
          Choose this option if you have an ATI Radeon graphics card.  There
          are both PCI and AGP versions.  You don't need to choose this to
index 932b5aa..3f46772 100644 (file)
@@ -79,10 +79,9 @@ static int drm_add_magic(struct drm_master *master, struct drm_file *priv,
        struct drm_device *dev = master->minor->dev;
        DRM_DEBUG("%d\n", magic);
 
-       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
-       memset(entry, 0, sizeof(*entry));
        entry->priv = priv;
        entry->hash_item.key = (unsigned long)magic;
        mutex_lock(&dev->struct_mutex);
index 61b9bcf..994d23b 100644 (file)
@@ -34,6 +34,7 @@
 #include "drm.h"
 #include "drmP.h"
 #include "drm_crtc.h"
+#include "drm_edid.h"
 
 struct drm_prop_enum_list {
        int type;
@@ -494,7 +495,6 @@ void drm_connector_cleanup(struct drm_connector *connector)
        list_for_each_entry_safe(mode, t, &connector->user_modes, head)
                drm_mode_remove(connector, mode);
 
-       kfree(connector->fb_helper_private);
        mutex_lock(&dev->mode_config.mutex);
        drm_mode_object_put(dev, &connector->base);
        list_del(&connector->head);
@@ -858,7 +858,6 @@ void drm_mode_config_init(struct drm_device *dev)
        mutex_init(&dev->mode_config.mutex);
        mutex_init(&dev->mode_config.idr_mutex);
        INIT_LIST_HEAD(&dev->mode_config.fb_list);
-       INIT_LIST_HEAD(&dev->mode_config.fb_kernel_list);
        INIT_LIST_HEAD(&dev->mode_config.crtc_list);
        INIT_LIST_HEAD(&dev->mode_config.connector_list);
        INIT_LIST_HEAD(&dev->mode_config.encoder_list);
@@ -2350,7 +2349,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
                                            struct edid *edid)
 {
        struct drm_device *dev = connector->dev;
-       int ret = 0;
+       int ret = 0, size;
 
        if (connector->edid_blob_ptr)
                drm_property_destroy_blob(dev, connector->edid_blob_ptr);
@@ -2362,7 +2361,9 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
                return ret;
        }
 
-       connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid);
+       size = EDID_LENGTH * (1 + edid->extensions);
+       connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
+                                                           size, edid);
 
        ret = drm_connector_property_set_value(connector,
                                               dev->mode_config.edid_property,
index 51103aa..7644019 100644 (file)
@@ -55,7 +55,7 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
 }
 
 /**
- * drm_helper_probe_connector_modes - get complete set of display modes
+ * drm_helper_probe_single_connector_modes - get complete set of display modes
  * @dev: DRM device
  * @maxX: max width for modes
  * @maxY: max height for modes
@@ -154,21 +154,6 @@ prune:
 }
 EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
 
-int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
-                                     uint32_t maxY)
-{
-       struct drm_connector *connector;
-       int count = 0;
-
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               count += drm_helper_probe_single_connector_modes(connector,
-                                                                maxX, maxY);
-       }
-
-       return count;
-}
-EXPORT_SYMBOL(drm_helper_probe_connector_modes);
-
 /**
  * drm_helper_encoder_in_use - check if a given encoder is in use
  * @encoder: encoder to check
@@ -263,302 +248,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_helper_disable_unused_functions);
 
-static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height)
-{
-       struct drm_display_mode *mode;
-
-       list_for_each_entry(mode, &connector->modes, head) {
-               if (drm_mode_width(mode) > width ||
-                   drm_mode_height(mode) > height)
-                       continue;
-               if (mode->type & DRM_MODE_TYPE_PREFERRED)
-                       return mode;
-       }
-       return NULL;
-}
-
-static bool drm_has_cmdline_mode(struct drm_connector *connector)
-{
-       struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
-
-       if (!fb_help_conn)
-               return false;
-
-       cmdline_mode = &fb_help_conn->cmdline_mode;
-       return cmdline_mode->specified;
-}
-
-static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height)
-{
-       struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
-       struct drm_display_mode *mode = NULL;
-
-       if (!fb_help_conn)
-               return mode;
-
-       cmdline_mode = &fb_help_conn->cmdline_mode;
-       if (cmdline_mode->specified == false)
-               return mode;
-
-       /* attempt to find a matching mode in the list of modes
-        *  we have gotten so far, if not add a CVT mode that conforms
-        */
-       if (cmdline_mode->rb || cmdline_mode->margins)
-               goto create_mode;
-
-       list_for_each_entry(mode, &connector->modes, head) {
-               /* check width/height */
-               if (mode->hdisplay != cmdline_mode->xres ||
-                   mode->vdisplay != cmdline_mode->yres)
-                       continue;
-
-               if (cmdline_mode->refresh_specified) {
-                       if (mode->vrefresh != cmdline_mode->refresh)
-                               continue;
-               }
-
-               if (cmdline_mode->interlace) {
-                       if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
-                               continue;
-               }
-               return mode;
-       }
-
-create_mode:
-       mode = drm_cvt_mode(connector->dev, cmdline_mode->xres,
-                           cmdline_mode->yres,
-                           cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
-                           cmdline_mode->rb, cmdline_mode->interlace,
-                           cmdline_mode->margins);
-       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
-       list_add(&mode->head, &connector->modes);
-       return mode;
-}
-
-static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
-{
-       bool enable;
-
-       if (strict) {
-               enable = connector->status == connector_status_connected;
-       } else {
-               enable = connector->status != connector_status_disconnected;
-       }
-       return enable;
-}
-
-static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
-{
-       bool any_enabled = false;
-       struct drm_connector *connector;
-       int i = 0;
-
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               enabled[i] = drm_connector_enabled(connector, true);
-               DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
-                         enabled[i] ? "yes" : "no");
-               any_enabled |= enabled[i];
-               i++;
-       }
-
-       if (any_enabled)
-               return;
-
-       i = 0;
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               enabled[i] = drm_connector_enabled(connector, false);
-               i++;
-       }
-}
-
-static bool drm_target_preferred(struct drm_device *dev,
-                                struct drm_display_mode **modes,
-                                bool *enabled, int width, int height)
-{
-       struct drm_connector *connector;
-       int i = 0;
-
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-
-               if (enabled[i] == false) {
-                       i++;
-                       continue;
-               }
-
-               DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
-                             connector->base.id);
-
-               /* got for command line mode first */
-               modes[i] = drm_pick_cmdline_mode(connector, width, height);
-               if (!modes[i]) {
-                       DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
-                                     connector->base.id);
-                       modes[i] = drm_has_preferred_mode(connector, width, height);
-               }
-               /* No preferred modes, pick one off the list */
-               if (!modes[i] && !list_empty(&connector->modes)) {
-                       list_for_each_entry(modes[i], &connector->modes, head)
-                               break;
-               }
-               DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
-                         "none");
-               i++;
-       }
-       return true;
-}
-
-static int drm_pick_crtcs(struct drm_device *dev,
-                         struct drm_crtc **best_crtcs,
-                         struct drm_display_mode **modes,
-                         int n, int width, int height)
-{
-       int c, o;
-       struct drm_connector *connector;
-       struct drm_connector_helper_funcs *connector_funcs;
-       struct drm_encoder *encoder;
-       struct drm_crtc *best_crtc;
-       int my_score, best_score, score;
-       struct drm_crtc **crtcs, *crtc;
-
-       if (n == dev->mode_config.num_connector)
-               return 0;
-       c = 0;
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (c == n)
-                       break;
-               c++;
-       }
-
-       best_crtcs[n] = NULL;
-       best_crtc = NULL;
-       best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height);
-       if (modes[n] == NULL)
-               return best_score;
-
-       crtcs = kmalloc(dev->mode_config.num_connector *
-                       sizeof(struct drm_crtc *), GFP_KERNEL);
-       if (!crtcs)
-               return best_score;
-
-       my_score = 1;
-       if (connector->status == connector_status_connected)
-               my_score++;
-       if (drm_has_cmdline_mode(connector))
-               my_score++;
-       if (drm_has_preferred_mode(connector, width, height))
-               my_score++;
-
-       connector_funcs = connector->helper_private;
-       encoder = connector_funcs->best_encoder(connector);
-       if (!encoder)
-               goto out;
-
-       connector->encoder = encoder;
-
-       /* select a crtc for this connector and then attempt to configure
-          remaining connectors */
-       c = 0;
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-
-               if ((encoder->possible_crtcs & (1 << c)) == 0) {
-                       c++;
-                       continue;
-               }
-
-               for (o = 0; o < n; o++)
-                       if (best_crtcs[o] == crtc)
-                               break;
-
-               if (o < n) {
-                       /* ignore cloning for now */
-                       c++;
-                       continue;
-               }
-
-               crtcs[n] = crtc;
-               memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *));
-               score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1,
-                                                 width, height);
-               if (score > best_score) {
-                       best_crtc = crtc;
-                       best_score = score;
-                       memcpy(best_crtcs, crtcs,
-                              dev->mode_config.num_connector *
-                              sizeof(struct drm_crtc *));
-               }
-               c++;
-       }
-out:
-       kfree(crtcs);
-       return best_score;
-}
-
-static void drm_setup_crtcs(struct drm_device *dev)
-{
-       struct drm_crtc **crtcs;
-       struct drm_display_mode **modes;
-       struct drm_encoder *encoder;
-       struct drm_connector *connector;
-       bool *enabled;
-       int width, height;
-       int i, ret;
-
-       DRM_DEBUG_KMS("\n");
-
-       width = dev->mode_config.max_width;
-       height = dev->mode_config.max_height;
-
-       /* clean out all the encoder/crtc combos */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               encoder->crtc = NULL;
-       }
-
-       crtcs = kcalloc(dev->mode_config.num_connector,
-                       sizeof(struct drm_crtc *), GFP_KERNEL);
-       modes = kcalloc(dev->mode_config.num_connector,
-                       sizeof(struct drm_display_mode *), GFP_KERNEL);
-       enabled = kcalloc(dev->mode_config.num_connector,
-                         sizeof(bool), GFP_KERNEL);
-
-       drm_enable_connectors(dev, enabled);
-
-       ret = drm_target_preferred(dev, modes, enabled, width, height);
-       if (!ret)
-               DRM_ERROR("Unable to find initial modes\n");
-
-       DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
-
-       drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
-
-       i = 0;
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               struct drm_display_mode *mode = modes[i];
-               struct drm_crtc *crtc = crtcs[i];
-
-               if (connector->encoder == NULL) {
-                       i++;
-                       continue;
-               }
-
-               if (mode && crtc) {
-                       DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
-                                 mode->name, crtc->base.id);
-                       crtc->desired_mode = mode;
-                       connector->encoder->crtc = crtc;
-               } else {
-                       connector->encoder->crtc = NULL;
-                       connector->encoder = NULL;
-               }
-               i++;
-       }
-
-       kfree(crtcs);
-       kfree(modes);
-       kfree(enabled);
-}
-
 /**
  * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
  * @encoder: encoder to test
@@ -936,10 +625,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                                ret = -EINVAL;
                                goto fail;
                        }
-                       /* TODO are these needed? */
-                       set->crtc->desired_x = set->x;
-                       set->crtc->desired_y = set->y;
-                       set->crtc->desired_mode = set->mode;
                }
                drm_helper_disable_unused_functions(dev);
        } else if (fb_changed) {
@@ -984,63 +669,6 @@ fail:
 }
 EXPORT_SYMBOL(drm_crtc_helper_set_config);
 
-bool drm_helper_plugged_event(struct drm_device *dev)
-{
-       DRM_DEBUG_KMS("\n");
-
-       drm_helper_probe_connector_modes(dev, dev->mode_config.max_width,
-                                        dev->mode_config.max_height);
-
-       drm_setup_crtcs(dev);
-
-       /* alert the driver fb layer */
-       dev->mode_config.funcs->fb_changed(dev);
-
-       /* FIXME: send hotplug event */
-       return true;
-}
-/**
- * drm_initial_config - setup a sane initial connector configuration
- * @dev: DRM device
- *
- * LOCKING:
- * Called at init time, must take mode config lock.
- *
- * Scan the CRTCs and connectors and try to put together an initial setup.
- * At the moment, this is a cloned configuration across all heads with
- * a new framebuffer object as the backing store.
- *
- * RETURNS:
- * Zero if everything went ok, nonzero otherwise.
- */
-bool drm_helper_initial_config(struct drm_device *dev)
-{
-       int count = 0;
-
-       /* disable all the possible outputs/crtcs before entering KMS mode */
-       drm_helper_disable_unused_functions(dev);
-
-       drm_fb_helper_parse_command_line(dev);
-
-       count = drm_helper_probe_connector_modes(dev,
-                                                dev->mode_config.max_width,
-                                                dev->mode_config.max_height);
-
-       /*
-        * we shouldn't end up with no modes here.
-        */
-       if (count == 0)
-               printk(KERN_INFO "No connectors reported connected with modes\n");
-
-       drm_setup_crtcs(dev);
-
-       /* alert the driver fb layer */
-       dev->mode_config.funcs->fb_changed(dev);
-
-       return 0;
-}
-EXPORT_SYMBOL(drm_helper_initial_config);
-
 static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
 {
        int dpms = DRM_MODE_DPMS_OFF;
@@ -1123,27 +751,6 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
 }
 EXPORT_SYMBOL(drm_helper_connector_dpms);
 
-/**
- * drm_hotplug_stage_two
- * @dev DRM device
- * @connector hotpluged connector
- *
- * LOCKING.
- * Caller must hold mode config lock, function might grab struct lock.
- *
- * Stage two of a hotplug.
- *
- * RETURNS:
- * Zero on success, errno on failure.
- */
-int drm_helper_hotplug_stage_two(struct drm_device *dev)
-{
-       drm_helper_plugged_event(dev);
-
-       return 0;
-}
-EXPORT_SYMBOL(drm_helper_hotplug_stage_two);
-
 int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
                                   struct drm_mode_fb_cmd *mode_cmd)
 {
@@ -1200,3 +807,98 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
        return 0;
 }
 EXPORT_SYMBOL(drm_helper_resume_force_mode);
+
+static struct slow_work_ops output_poll_ops;
+
+#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
+static void output_poll_execute(struct slow_work *work)
+{
+       struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
+       struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work);
+       struct drm_connector *connector;
+       enum drm_connector_status old_status, status;
+       bool repoll = false, changed = false;
+       int ret;
+
+       mutex_lock(&dev->mode_config.mutex);
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+
+               /* if this is HPD or polled don't check it -
+                  TV out for instance */
+               if (!connector->polled)
+                       continue;
+
+               else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
+                       repoll = true;
+
+               old_status = connector->status;
+               /* if we are connected and don't want to poll for disconnect
+                  skip it */
+               if (old_status == connector_status_connected &&
+                   !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) &&
+                   !(connector->polled & DRM_CONNECTOR_POLL_HPD))
+                       continue;
+
+               status = connector->funcs->detect(connector);
+               if (old_status != status)
+                       changed = true;
+       }
+
+       mutex_unlock(&dev->mode_config.mutex);
+
+       if (changed) {
+               /* send a uevent + call fbdev */
+               drm_sysfs_hotplug_event(dev);
+               if (dev->mode_config.funcs->output_poll_changed)
+                       dev->mode_config.funcs->output_poll_changed(dev);
+       }
+
+       if (repoll) {
+               ret = delayed_slow_work_enqueue(delayed_work, DRM_OUTPUT_POLL_PERIOD);
+               if (ret)
+                       DRM_ERROR("delayed enqueue failed %d\n", ret);
+       }
+}
+
+void drm_kms_helper_poll_init(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+       bool poll = false;
+       int ret;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->polled)
+                       poll = true;
+       }
+       slow_work_register_user(THIS_MODULE);
+       delayed_slow_work_init(&dev->mode_config.output_poll_slow_work,
+                              &output_poll_ops);
+
+       if (poll) {
+               ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD);
+               if (ret)
+                       DRM_ERROR("delayed enqueue failed %d\n", ret);
+       }
+}
+EXPORT_SYMBOL(drm_kms_helper_poll_init);
+
+void drm_kms_helper_poll_fini(struct drm_device *dev)
+{
+       delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
+       slow_work_unregister_user(THIS_MODULE);
+}
+EXPORT_SYMBOL(drm_kms_helper_poll_fini);
+
+void drm_helper_hpd_irq_event(struct drm_device *dev)
+{
+       if (!dev->mode_config.poll_enabled)
+               return;
+       delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
+       /* schedule a slow work asap */
+       delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0);
+}
+EXPORT_SYMBOL(drm_helper_hpd_irq_event);
+
+static struct slow_work_ops output_poll_ops = {
+       .execute = output_poll_execute,
+};
index 13f1537..252cbd7 100644 (file)
@@ -47,12 +47,10 @@ int drm_dma_setup(struct drm_device *dev)
 {
        int i;
 
-       dev->dma = kmalloc(sizeof(*dev->dma), GFP_KERNEL);
+       dev->dma = kzalloc(sizeof(*dev->dma), GFP_KERNEL);
        if (!dev->dma)
                return -ENOMEM;
 
-       memset(dev->dma, 0, sizeof(*dev->dma));
-
        for (i = 0; i <= DRM_MAX_ORDER; i++)
                memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
 
index 18f41d7..f569ae8 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (c) 2006 Luc Verhaegen (quirks list)
  * Copyright (c) 2007-2008 Intel Corporation
  *   Jesse Barnes <jesse.barnes@intel.com>
+ * Copyright 2010 Red Hat, Inc.
  *
  * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from
  * FB layer.
 #include "drmP.h"
 #include "drm_edid.h"
 
-/*
- * TODO:
- *   - support EDID 1.4 (incl. CE blocks)
- */
+#define EDID_EST_TIMINGS 16
+#define EDID_STD_TIMINGS 8
+#define EDID_DETAILED_TIMINGS 4
 
 /*
  * EDID blocks out in the wild have a variety of bugs, try to collect
@@ -65,7 +65,8 @@
 
 #define LEVEL_DMT      0
 #define LEVEL_GTF      1
-#define LEVEL_CVT      2
+#define LEVEL_GTF2     2
+#define LEVEL_CVT      3
 
 static struct edid_quirk {
        char *vendor;
@@ -109,36 +110,38 @@ static struct edid_quirk {
        { "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 },
 };
 
+/*** DDC fetch and block validation ***/
 
-/* Valid EDID header has these bytes */
 static const u8 edid_header[] = {
        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
 };
 
-/**
- * drm_edid_is_valid - sanity check EDID data
- * @edid: EDID data
- *
- * Sanity check the EDID block by looking at the header, the version number
- * and the checksum.  Return 0 if the EDID doesn't check out, or 1 if it's
- * valid.
+/*
+ * Sanity check the EDID block (base or extension).  Return 0 if the block
+ * doesn't check out, or 1 if it's valid.
  */
-bool drm_edid_is_valid(struct edid *edid)
+static bool
+drm_edid_block_valid(u8 *raw_edid)
 {
-       int i, score = 0;
+       int i;
        u8 csum = 0;
-       u8 *raw_edid = (u8 *)edid;
+       struct edid *edid = (struct edid *)raw_edid;
 
-       for (i = 0; i < sizeof(edid_header); i++)
-               if (raw_edid[i] == edid_header[i])
-                       score++;
+       if (raw_edid[0] == 0x00) {
+               int score = 0;
 
-       if (score == 8) ;
-       else if (score >= 6) {
-               DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
-               memcpy(raw_edid, edid_header, sizeof(edid_header));
-       } else
-               goto bad;
+               for (i = 0; i < sizeof(edid_header); i++)
+                       if (raw_edid[i] == edid_header[i])
+                               score++;
+
+               if (score == 8) ;
+               else if (score >= 6) {
+                       DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
+                       memcpy(raw_edid, edid_header, sizeof(edid_header));
+               } else {
+                       goto bad;
+               }
+       }
 
        for (i = 0; i < EDID_LENGTH; i++)
                csum += raw_edid[i];
@@ -147,13 +150,21 @@ bool drm_edid_is_valid(struct edid *edid)
                goto bad;
        }
 
-       if (edid->version != 1) {
-               DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
-               goto bad;
-       }
+       /* per-block-type checks */
+       switch (raw_edid[0]) {
+       case 0: /* base */
+               if (edid->version != 1) {
+                       DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
+                       goto bad;
+               }
 
-       if (edid->revision > 4)
-               DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n");
+               if (edid->revision > 4)
+                       DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n");
+               break;
+
+       default:
+               break;
+       }
 
        return 1;
 
@@ -165,8 +176,158 @@ bad:
        }
        return 0;
 }
+
+/**
+ * drm_edid_is_valid - sanity check EDID data
+ * @edid: EDID data
+ *
+ * Sanity-check an entire EDID record (including extensions)
+ */
+bool drm_edid_is_valid(struct edid *edid)
+{
+       int i;
+       u8 *raw = (u8 *)edid;
+
+       if (!edid)
+               return false;
+
+       for (i = 0; i <= edid->extensions; i++)
+               if (!drm_edid_block_valid(raw + i * EDID_LENGTH))
+                       return false;
+
+       return true;
+}
 EXPORT_SYMBOL(drm_edid_is_valid);
 
+#define DDC_ADDR 0x50
+#define DDC_SEGMENT_ADDR 0x30
+/**
+ * Get EDID information via I2C.
+ *
+ * \param adapter : i2c device adaptor
+ * \param buf     : EDID data buffer to be filled
+ * \param len     : EDID data buffer length
+ * \return 0 on success or -1 on failure.
+ *
+ * Try to fetch EDID information by calling i2c driver function.
+ */
+static int
+drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
+                     int block, int len)
+{
+       unsigned char start = block * EDID_LENGTH;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = DDC_ADDR,
+                       .flags  = 0,
+                       .len    = 1,
+                       .buf    = &start,
+               }, {
+                       .addr   = DDC_ADDR,
+                       .flags  = I2C_M_RD,
+                       .len    = len,
+                       .buf    = buf + start,
+               }
+       };
+
+       if (i2c_transfer(adapter, msgs, 2) == 2)
+               return 0;
+
+       return -1;
+}
+
+static u8 *
+drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
+{
+       int i, j = 0;
+       u8 *block, *new;
+
+       if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
+               return NULL;
+
+       /* base block fetch */
+       for (i = 0; i < 4; i++) {
+               if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH))
+                       goto out;
+               if (drm_edid_block_valid(block))
+                       break;
+       }
+       if (i == 4)
+               goto carp;
+
+       /* if there's no extensions, we're done */
+       if (block[0x7e] == 0)
+               return block;
+
+       new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL);
+       if (!new)
+               goto out;
+       block = new;
+
+       for (j = 1; j <= block[0x7e]; j++) {
+               for (i = 0; i < 4; i++) {
+                       if (drm_do_probe_ddc_edid(adapter, block, j,
+                                                 EDID_LENGTH))
+                               goto out;
+                       if (drm_edid_block_valid(block + j * EDID_LENGTH))
+                               break;
+               }
+               if (i == 4)
+                       goto carp;
+       }
+
+       return block;
+
+carp:
+       dev_warn(&connector->dev->pdev->dev, "%s: EDID block %d invalid.\n",
+                drm_get_connector_name(connector), j);
+
+out:
+       kfree(block);
+       return NULL;
+}
+
+/**
+ * Probe DDC presence.
+ *
+ * \param adapter : i2c device adaptor
+ * \return 1 on success
+ */
+static bool
+drm_probe_ddc(struct i2c_adapter *adapter)
+{
+       unsigned char out;
+
+       return (drm_do_probe_ddc_edid(adapter, &out, 0, 1) == 0);
+}
+
+/**
+ * drm_get_edid - get EDID data, if available
+ * @connector: connector we're probing
+ * @adapter: i2c adapter to use for DDC
+ *
+ * Poke the given i2c channel to grab EDID data if possible.  If found,
+ * attach it to the connector.
+ *
+ * Return edid data or NULL if we couldn't find any.
+ */
+struct edid *drm_get_edid(struct drm_connector *connector,
+                         struct i2c_adapter *adapter)
+{
+       struct edid *edid = NULL;
+
+       if (drm_probe_ddc(adapter))
+               edid = (struct edid *)drm_do_get_edid(connector, adapter);
+
+       connector->display_info.raw_edid = (char *)edid;
+
+       return edid;
+
+}
+EXPORT_SYMBOL(drm_get_edid);
+
+/*** EDID parsing ***/
+
 /**
  * edid_vendor - match a string against EDID's obfuscated vendor field
  * @edid: EDID to match
@@ -335,7 +496,7 @@ static struct drm_display_mode drm_dmt_modes[] = {
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
        /* 1024x768@85Hz */
        { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
-                  1072, 1376, 0, 768, 769, 772, 808, 0,
+                  1168, 1376, 0, 768, 769, 772, 808, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
        /* 1152x864@75Hz */
        { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
@@ -426,7 +587,7 @@ static struct drm_display_mode drm_dmt_modes[] = {
                   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
        /* 1600x1200@75Hz */
-       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 2025000, 1600, 1664,
+       { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664,
                   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
        /* 1600x1200@85Hz */
@@ -497,8 +658,8 @@ static struct drm_display_mode drm_dmt_modes[] = {
 static const int drm_num_dmt_modes =
        sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
 
-static struct drm_display_mode *drm_find_dmt(struct drm_device *dev,
-                       int hsize, int vsize, int fresh)
+struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
+                                          int hsize, int vsize, int fresh)
 {
        int i;
        struct drm_display_mode *ptr, *mode;
@@ -516,6 +677,111 @@ static struct drm_display_mode *drm_find_dmt(struct drm_device *dev,
        }
        return mode;
 }
+EXPORT_SYMBOL(drm_mode_find_dmt);
+
+typedef void detailed_cb(struct detailed_timing *timing, void *closure);
+
+static void
+drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
+{
+       int i;
+       struct edid *edid = (struct edid *)raw_edid;
+
+       if (edid == NULL)
+               return;
+
+       for (i = 0; i < EDID_DETAILED_TIMINGS; i++)
+               cb(&(edid->detailed_timings[i]), closure);
+
+       /* XXX extension block walk */
+}
+
+static void
+is_rb(struct detailed_timing *t, void *data)
+{
+       u8 *r = (u8 *)t;
+       if (r[3] == EDID_DETAIL_MONITOR_RANGE)
+               if (r[15] & 0x10)
+                       *(bool *)data = true;
+}
+
+/* EDID 1.4 defines this explicitly.  For EDID 1.3, we guess, badly. */
+static bool
+drm_monitor_supports_rb(struct edid *edid)
+{
+       if (edid->revision >= 4) {
+               bool ret;
+               drm_for_each_detailed_block((u8 *)edid, is_rb, &ret);
+               return ret;
+       }
+
+       return ((edid->input & DRM_EDID_INPUT_DIGITAL) != 0);
+}
+
+static void
+find_gtf2(struct detailed_timing *t, void *data)
+{
+       u8 *r = (u8 *)t;
+       if (r[3] == EDID_DETAIL_MONITOR_RANGE && r[10] == 0x02)
+               *(u8 **)data = r;
+}
+
+/* Secondary GTF curve kicks in above some break frequency */
+static int
+drm_gtf2_hbreak(struct edid *edid)
+{
+       u8 *r = NULL;
+       drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
+       return r ? (r[12] * 2) : 0;
+}
+
+static int
+drm_gtf2_2c(struct edid *edid)
+{
+       u8 *r = NULL;
+       drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
+       return r ? r[13] : 0;
+}
+
+static int
+drm_gtf2_m(struct edid *edid)
+{
+       u8 *r = NULL;
+       drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
+       return r ? (r[15] << 8) + r[14] : 0;
+}
+
+static int
+drm_gtf2_k(struct edid *edid)
+{
+       u8 *r = NULL;
+       drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
+       return r ? r[16] : 0;
+}
+
+static int
+drm_gtf2_2j(struct edid *edid)
+{
+       u8 *r = NULL;
+       drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
+       return r ? r[17] : 0;
+}
+
+/**
+ * standard_timing_level - get std. timing level(CVT/GTF/DMT)
+ * @edid: EDID block to scan
+ */
+static int standard_timing_level(struct edid *edid)
+{
+       if (edid->revision >= 2) {
+               if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
+                       return LEVEL_CVT;
+               if (drm_gtf2_hbreak(edid))
+                       return LEVEL_GTF2;
+               return LEVEL_GTF;
+       }
+       return LEVEL_DMT;
+}
 
 /*
  * 0 is reserved.  The spec says 0x01 fill for unused timings.  Some old
@@ -536,22 +802,20 @@ bad_std_timing(u8 a, u8 b)
  *
  * Take the standard timing params (in this case width, aspect, and refresh)
  * and convert them into a real mode using CVT/GTF/DMT.
- *
- * Punts for now, but should eventually use the FB layer's CVT based mode
- * generation code.
  */
-struct drm_display_mode *drm_mode_std(struct drm_device *dev,
-                                     struct std_timing *t,
-                                     int revision,
-                                     int timing_level)
+static struct drm_display_mode *
+drm_mode_std(struct drm_connector *connector, struct edid *edid,
+            struct std_timing *t, int revision)
 {
-       struct drm_display_mode *mode;
+       struct drm_device *dev = connector->dev;
+       struct drm_display_mode *m, *mode = NULL;
        int hsize, vsize;
        int vrefresh_rate;
        unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK)
                >> EDID_TIMING_ASPECT_SHIFT;
        unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK)
                >> EDID_TIMING_VFREQ_SHIFT;
+       int timing_level = standard_timing_level(edid);
 
        if (bad_std_timing(t->hsize, t->vfreq_aspect))
                return NULL;
@@ -572,18 +836,38 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
                vsize = (hsize * 4) / 5;
        else
                vsize = (hsize * 9) / 16;
-       /* HDTV hack */
-       if (hsize == 1360 && vsize == 765 && vrefresh_rate == 60) {
-               mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
+
+       /* HDTV hack, part 1 */
+       if (vrefresh_rate == 60 &&
+           ((hsize == 1360 && vsize == 765) ||
+            (hsize == 1368 && vsize == 769))) {
+               hsize = 1366;
+               vsize = 768;
+       }
+
+       /*
+        * If this connector already has a mode for this size and refresh
+        * rate (because it came from detailed or CVT info), use that
+        * instead.  This way we don't have to guess at interlace or
+        * reduced blanking.
+        */
+       list_for_each_entry(m, &connector->probed_modes, head)
+               if (m->hdisplay == hsize && m->vdisplay == vsize &&
+                   drm_mode_vrefresh(m) == vrefresh_rate)
+                       return NULL;
+
+       /* HDTV hack, part 2 */
+       if (hsize == 1366 && vsize == 768 && vrefresh_rate == 60) {
+               mode = drm_cvt_mode(dev, 1366, 768, vrefresh_rate, 0, 0,
                                    false);
                mode->hdisplay = 1366;
                mode->vsync_start = mode->vsync_start - 1;
                mode->vsync_end = mode->vsync_end - 1;
                return mode;
        }
-       mode = NULL;
+
        /* check whether it can be found in default mode table */
-       mode = drm_find_dmt(dev, hsize, vsize, vrefresh_rate);
+       mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate);
        if (mode)
                return mode;
 
@@ -593,6 +877,23 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
        case LEVEL_GTF:
                mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
                break;
+       case LEVEL_GTF2:
+               /*
+                * This is potentially wrong if there's ever a monitor with
+                * more than one ranges section, each claiming a different
+                * secondary GTF curve.  Please don't do that.
+                */
+               mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+               if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) {
+                       kfree(mode);
+                       mode = drm_gtf_mode_complex(dev, hsize, vsize,
+                                                   vrefresh_rate, 0, 0,
+                                                   drm_gtf2_m(edid),
+                                                   drm_gtf2_2c(edid),
+                                                   drm_gtf2_k(edid),
+                                                   drm_gtf2_2j(edid));
+               }
+               break;
        case LEVEL_CVT:
                mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
                                    false);
@@ -716,10 +1017,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        if (mode->vsync_end > mode->vtotal)
                mode->vtotal = mode->vsync_end + 1;
 
-       drm_mode_set_name(mode);
-
        drm_mode_do_interlace_quirk(mode, pt);
 
+       drm_mode_set_name(mode);
+
        if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
                pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE;
        }
@@ -802,10 +1103,6 @@ static struct drm_display_mode edid_est_modes[] = {
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
 };
 
-#define EDID_EST_TIMINGS 16
-#define EDID_STD_TIMINGS 8
-#define EDID_DETAILED_TIMINGS 4
-
 /**
  * add_established_modes - get est. modes from EDID and add them
  * @edid: EDID block to scan
@@ -833,19 +1130,6 @@ static int add_established_modes(struct drm_connector *connector, struct edid *e
 
        return modes;
 }
-/**
- * stanard_timing_level - get std. timing level(CVT/GTF/DMT)
- * @edid: EDID block to scan
- */
-static int standard_timing_level(struct edid *edid)
-{
-       if (edid->revision >= 2) {
-               if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
-                       return LEVEL_CVT;
-               return LEVEL_GTF;
-       }
-       return LEVEL_DMT;
-}
 
 /**
  * add_standard_modes - get std. modes from EDID and add them
@@ -856,22 +1140,14 @@ static int standard_timing_level(struct edid *edid)
  */
 static int add_standard_modes(struct drm_connector *connector, struct edid *edid)
 {
-       struct drm_device *dev = connector->dev;
        int i, modes = 0;
-       int timing_level;
-
-       timing_level = standard_timing_level(edid);
 
        for (i = 0; i < EDID_STD_TIMINGS; i++) {
-               struct std_timing *t = &edid->standard_timings[i];
                struct drm_display_mode *newmode;
 
-               /* If std timings bytes are 1, 1 it's empty */
-               if (t->hsize == 1 && t->vfreq_aspect == 1)
-                       continue;
-
-               newmode = drm_mode_std(dev, &edid->standard_timings[i],
-                                      edid->revision, timing_level);
+               newmode = drm_mode_std(connector, edid,
+                                      &edid->standard_timings[i],
+                                      edid->revision);
                if (newmode) {
                        drm_mode_probed_add(connector, newmode);
                        modes++;
@@ -881,36 +1157,86 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
        return modes;
 }
 
-/*
- * XXX fix this for:
- * - GTF secondary curve formula
- * - EDID 1.4 range offsets
- * - CVT extended bits
- */
 static bool
-mode_in_range(struct drm_display_mode *mode, struct detailed_timing *timing)
+mode_is_rb(struct drm_display_mode *mode)
 {
-       struct detailed_data_monitor_range *range;
-       int hsync, vrefresh;
-
-       range = &timing->data.other_data.data.range;
+       return (mode->htotal - mode->hdisplay == 160) &&
+              (mode->hsync_end - mode->hdisplay == 80) &&
+              (mode->hsync_end - mode->hsync_start == 32) &&
+              (mode->vsync_start - mode->vdisplay == 3);
+}
 
+static bool
+mode_in_hsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t)
+{
+       int hsync, hmin, hmax;
+
+       hmin = t[7];
+       if (edid->revision >= 4)
+           hmin += ((t[4] & 0x04) ? 255 : 0);
+       hmax = t[8];
+       if (edid->revision >= 4)
+           hmax += ((t[4] & 0x08) ? 255 : 0);
        hsync = drm_mode_hsync(mode);
-       vrefresh = drm_mode_vrefresh(mode);
 
-       if (hsync < range->min_hfreq_khz || hsync > range->max_hfreq_khz)
+       return (hsync <= hmax && hsync >= hmin);
+}
+
+static bool
+mode_in_vsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t)
+{
+       int vsync, vmin, vmax;
+
+       vmin = t[5];
+       if (edid->revision >= 4)
+           vmin += ((t[4] & 0x01) ? 255 : 0);
+       vmax = t[6];
+       if (edid->revision >= 4)
+           vmax += ((t[4] & 0x02) ? 255 : 0);
+       vsync = drm_mode_vrefresh(mode);
+
+       return (vsync <= vmax && vsync >= vmin);
+}
+
+static u32
+range_pixel_clock(struct edid *edid, u8 *t)
+{
+       /* unspecified */
+       if (t[9] == 0 || t[9] == 255)
+               return 0;
+
+       /* 1.4 with CVT support gives us real precision, yay */
+       if (edid->revision >= 4 && t[10] == 0x04)
+               return (t[9] * 10000) - ((t[12] >> 2) * 250);
+
+       /* 1.3 is pathetic, so fuzz up a bit */
+       return t[9] * 10000 + 5001;
+}
+
+static bool
+mode_in_range(struct drm_display_mode *mode, struct edid *edid,
+             struct detailed_timing *timing)
+{
+       u32 max_clock;
+       u8 *t = (u8 *)timing;
+
+       if (!mode_in_hsync_range(mode, edid, t))
                return false;
 
-       if (vrefresh < range->min_vfreq || vrefresh > range->max_vfreq)
+       if (!mode_in_vsync_range(mode, edid, t))
                return false;
 
-       if (range->pixel_clock_mhz && range->pixel_clock_mhz != 0xff) {
-               /* be forgiving since it's in units of 10MHz */
-               int max_clock = range->pixel_clock_mhz * 10 + 9;
-               max_clock *= 1000;
+       if ((max_clock = range_pixel_clock(edid, t)))
                if (mode->clock > max_clock)
                        return false;
-       }
+
+       /* 1.4 max horizontal check */
+       if (edid->revision >= 4 && t[10] == 0x04)
+               if (t[13] && mode->hdisplay > 8 * (t[13] + (256 * (t[12]&0x3))))
+                       return false;
+
+       if (mode_is_rb(mode) && !drm_monitor_supports_rb(edid))
+               return false;
 
        return true;
 }
@@ -919,15 +1245,16 @@ mode_in_range(struct drm_display_mode *mode, struct detailed_timing *timing)
  * XXX If drm_dmt_modes ever regrows the CVT-R modes (and it will) this will
  * need to account for them.
  */
-static int drm_gtf_modes_for_range(struct drm_connector *connector,
-                                  struct detailed_timing *timing)
+static int
+drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
+                       struct detailed_timing *timing)
 {
        int i, modes = 0;
        struct drm_display_mode *newmode;
        struct drm_device *dev = connector->dev;
 
        for (i = 0; i < drm_num_dmt_modes; i++) {
-               if (mode_in_range(drm_dmt_modes + i, timing)) {
+               if (mode_in_range(drm_dmt_modes + i, edid, timing)) {
                        newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]);
                        if (newmode) {
                                drm_mode_probed_add(connector, newmode);
@@ -988,13 +1315,100 @@ static int drm_cvt_modes(struct drm_connector *connector,
        return modes;
 }
 
+static const struct {
+       short w;
+       short h;
+       short r;
+       short rb;
+} est3_modes[] = {
+       /* byte 6 */
+       { 640, 350, 85, 0 },
+       { 640, 400, 85, 0 },
+       { 720, 400, 85, 0 },
+       { 640, 480, 85, 0 },
+       { 848, 480, 60, 0 },
+       { 800, 600, 85, 0 },
+       { 1024, 768, 85, 0 },
+       { 1152, 864, 75, 0 },
+       /* byte 7 */
+       { 1280, 768, 60, 1 },
+       { 1280, 768, 60, 0 },
+       { 1280, 768, 75, 0 },
+       { 1280, 768, 85, 0 },
+       { 1280, 960, 60, 0 },
+       { 1280, 960, 85, 0 },
+       { 1280, 1024, 60, 0 },
+       { 1280, 1024, 85, 0 },
+       /* byte 8 */
+       { 1360, 768, 60, 0 },
+       { 1440, 900, 60, 1 },
+       { 1440, 900, 60, 0 },
+       { 1440, 900, 75, 0 },
+       { 1440, 900, 85, 0 },
+       { 1400, 1050, 60, 1 },
+       { 1400, 1050, 60, 0 },
+       { 1400, 1050, 75, 0 },
+       /* byte 9 */
+       { 1400, 1050, 85, 0 },
+       { 1680, 1050, 60, 1 },
+       { 1680, 1050, 60, 0 },
+       { 1680, 1050, 75, 0 },
+       { 1680, 1050, 85, 0 },
+       { 1600, 1200, 60, 0 },
+       { 1600, 1200, 65, 0 },
+       { 1600, 1200, 70, 0 },
+       /* byte 10 */
+       { 1600, 1200, 75, 0 },
+       { 1600, 1200, 85, 0 },
+       { 1792, 1344, 60, 0 },
+       { 1792, 1344, 85, 0 },
+       { 1856, 1392, 60, 0 },
+       { 1856, 1392, 75, 0 },
+       { 1920, 1200, 60, 1 },
+       { 1920, 1200, 60, 0 },
+       /* byte 11 */
+       { 1920, 1200, 75, 0 },
+       { 1920, 1200, 85, 0 },
+       { 1920, 1440, 60, 0 },
+       { 1920, 1440, 75, 0 },
+};
+static const int num_est3_modes = sizeof(est3_modes) / sizeof(est3_modes[0]);
+
+static int
+drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
+{
+       int i, j, m, modes = 0;
+       struct drm_display_mode *mode;
+       u8 *est = ((u8 *)timing) + 5;
+
+       for (i = 0; i < 6; i++) {
+               for (j = 7; j > 0; j--) {
+                       m = (i * 8) + (7 - j);
+                       if (m >= num_est3_modes)
+                               break;
+                       if (est[i] & (1 << j)) {
+                               mode = drm_mode_find_dmt(connector->dev,
+                                                        est3_modes[m].w,
+                                                        est3_modes[m].h,
+                                                        est3_modes[m].r
+                                                        /*, est3_modes[m].rb */);
+                               if (mode) {
+                                       drm_mode_probed_add(connector, mode);
+                                       modes++;
+                               }
+                       }
+               }
+       }
+
+       return modes;
+}
+
 static int add_detailed_modes(struct drm_connector *connector,
                              struct detailed_timing *timing,
                              struct edid *edid, u32 quirks, int preferred)
 {
        int i, modes = 0;
        struct detailed_non_pixel *data = &timing->data.other_data;
-       int timing_level = standard_timing_level(edid);
        int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
        struct drm_display_mode *newmode;
        struct drm_device *dev = connector->dev;
@@ -1015,7 +1429,8 @@ static int add_detailed_modes(struct drm_connector *connector,
        switch (data->type) {
        case EDID_DETAIL_MONITOR_RANGE:
                if (gtf)
-                       modes += drm_gtf_modes_for_range(connector, timing);
+                       modes += drm_gtf_modes_for_range(connector, edid,
+                                                        timing);
                break;
        case EDID_DETAIL_STD_MODES:
                /* Six modes per detailed section */
@@ -1024,8 +1439,8 @@ static int add_detailed_modes(struct drm_connector *connector,
                        struct drm_display_mode *newmode;
 
                        std = &data->data.timings[i];
-                       newmode = drm_mode_std(dev, std, edid->revision,
-                                              timing_level);
+                       newmode = drm_mode_std(connector, edid, std,
+                                              edid->revision);
                        if (newmode) {
                                drm_mode_probed_add(connector, newmode);
                                modes++;
@@ -1035,6 +1450,9 @@ static int add_detailed_modes(struct drm_connector *connector,
        case EDID_DETAIL_CVT_3BYTE:
                modes += drm_cvt_modes(connector, timing);
                break;
+       case EDID_DETAIL_EST_TIMINGS:
+               modes += drm_est3_modes(connector, timing);
+               break;
        default:
                break;
        }
@@ -1058,7 +1476,10 @@ static int add_detailed_info(struct drm_connector *connector,
 
        for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
                struct detailed_timing *timing = &edid->detailed_timings[i];
-               int preferred = (i == 0) && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
+               int preferred = (i == 0);
+
+               if (preferred && edid->version == 1 && edid->revision < 4)
+                       preferred = (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
 
                /* In 1.0, only timings are allowed */
                if (!timing->pixel_clock && edid->version == 1 &&
@@ -1088,39 +1509,22 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
        int i, modes = 0;
        char *edid_ext = NULL;
        struct detailed_timing *timing;
-       int edid_ext_num;
        int start_offset, end_offset;
-       int timing_level;
 
-       if (edid->version == 1 && edid->revision < 3) {
-               /* If the EDID version is less than 1.3, there is no
-                * extension EDID.
-                */
+       if (edid->version == 1 && edid->revision < 3)
                return 0;
-       }
-       if (!edid->extensions) {
-               /* if there is no extension EDID, it is unnecessary to
-                * parse the E-EDID to get detailed info
-                */
+       if (!edid->extensions)
                return 0;
-       }
-
-       /* Chose real EDID extension number */
-       edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ?
-               DRM_MAX_EDID_EXT_NUM : edid->extensions;
 
        /* Find CEA extension */
-       for (i = 0; i < edid_ext_num; i++) {
+       for (i = 0; i < edid->extensions; i++) {
                edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
-               /* This block is CEA extension */
                if (edid_ext[0] == 0x02)
                        break;
        }
 
-       if (i == edid_ext_num) {
-               /* if there is no additional timing EDID block, return */
+       if (i == edid->extensions)
                return 0;
-       }
 
        /* Get the start offset of detailed timing block */
        start_offset = edid_ext[2];
@@ -1132,7 +1536,6 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
                return 0;
        }
 
-       timing_level = standard_timing_level(edid);
        end_offset = EDID_LENGTH;
        end_offset -= sizeof(struct detailed_timing);
        for (i = start_offset; i < end_offset;
@@ -1144,123 +1547,6 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
        return modes;
 }
 
-#define DDC_ADDR 0x50
-/**
- * Get EDID information via I2C.
- *
- * \param adapter : i2c device adaptor
- * \param buf     : EDID data buffer to be filled
- * \param len     : EDID data buffer length
- * \return 0 on success or -1 on failure.
- *
- * Try to fetch EDID information by calling i2c driver function.
- */
-int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
-                         unsigned char *buf, int len)
-{
-       unsigned char start = 0x0;
-       struct i2c_msg msgs[] = {
-               {
-                       .addr   = DDC_ADDR,
-                       .flags  = 0,
-                       .len    = 1,
-                       .buf    = &start,
-               }, {
-                       .addr   = DDC_ADDR,
-                       .flags  = I2C_M_RD,
-                       .len    = len,
-                       .buf    = buf,
-               }
-       };
-
-       if (i2c_transfer(adapter, msgs, 2) == 2)
-               return 0;
-
-       return -1;
-}
-EXPORT_SYMBOL(drm_do_probe_ddc_edid);
-
-static int drm_ddc_read_edid(struct drm_connector *connector,
-                            struct i2c_adapter *adapter,
-                            char *buf, int len)
-{
-       int i;
-
-       for (i = 0; i < 4; i++) {
-               if (drm_do_probe_ddc_edid(adapter, buf, len))
-                       return -1;
-               if (drm_edid_is_valid((struct edid *)buf))
-                       return 0;
-       }
-
-       /* repeated checksum failures; warn, but carry on */
-       dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
-                drm_get_connector_name(connector));
-       return -1;
-}
-
-/**
- * drm_get_edid - get EDID data, if available
- * @connector: connector we're probing
- * @adapter: i2c adapter to use for DDC
- *
- * Poke the given connector's i2c channel to grab EDID data if possible.
- *
- * Return edid data or NULL if we couldn't find any.
- */
-struct edid *drm_get_edid(struct drm_connector *connector,
-                         struct i2c_adapter *adapter)
-{
-       int ret;
-       struct edid *edid;
-
-       edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1),
-                      GFP_KERNEL);
-       if (edid == NULL) {
-               dev_warn(&connector->dev->pdev->dev,
-                        "Failed to allocate EDID\n");
-               goto end;
-       }
-
-       /* Read first EDID block */
-       ret = drm_ddc_read_edid(connector, adapter,
-                               (unsigned char *)edid, EDID_LENGTH);
-       if (ret != 0)
-               goto clean_up;
-
-       /* There are EDID extensions to be read */
-       if (edid->extensions != 0) {
-               int edid_ext_num = edid->extensions;
-
-               if (edid_ext_num > DRM_MAX_EDID_EXT_NUM) {
-                       dev_warn(&connector->dev->pdev->dev,
-                                "The number of extension(%d) is "
-                                "over max (%d), actually read number (%d)\n",
-                                edid_ext_num, DRM_MAX_EDID_EXT_NUM,
-                                DRM_MAX_EDID_EXT_NUM);
-                       /* Reset EDID extension number to be read */
-                       edid_ext_num = DRM_MAX_EDID_EXT_NUM;
-               }
-               /* Read EDID including extensions too */
-               ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
-                                       EDID_LENGTH * (edid_ext_num + 1));
-               if (ret != 0)
-                       goto clean_up;
-
-       }
-
-       connector->display_info.raw_edid = (char *)edid;
-       goto end;
-
-clean_up:
-       kfree(edid);
-       edid = NULL;
-end:
-       return edid;
-
-}
-EXPORT_SYMBOL(drm_get_edid);
-
 #define HDMI_IDENTIFIER 0x000C03
 #define VENDOR_BLOCK    0x03
 /**
@@ -1273,7 +1559,7 @@ EXPORT_SYMBOL(drm_get_edid);
 bool drm_detect_hdmi_monitor(struct edid *edid)
 {
        char *edid_ext = NULL;
-       int i, hdmi_id, edid_ext_num;
+       int i, hdmi_id;
        int start_offset, end_offset;
        bool is_hdmi = false;
 
@@ -1281,19 +1567,15 @@ bool drm_detect_hdmi_monitor(struct edid *edid)
        if (edid == NULL || edid->extensions == 0)
                goto end;
 
-       /* Chose real EDID extension number */
-       edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ?
-                      DRM_MAX_EDID_EXT_NUM : edid->extensions;
-
        /* Find CEA extension */
-       for (i = 0; i < edid_ext_num; i++) {
+       for (i = 0; i < edid->extensions; i++) {
                edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
                /* This block is CEA extension */
                if (edid_ext[0] == 0x02)
                        break;
        }
 
-       if (i == edid_ext_num)
+       if (i == edid->extensions)
                goto end;
 
        /* Data block offset in CEA extension block */
@@ -1348,10 +1630,24 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 
        quirks = edid_get_quirks(edid);
 
-       num_modes += add_established_modes(connector, edid);
-       num_modes += add_standard_modes(connector, edid);
+       /*
+        * EDID spec says modes should be preferred in this order:
+        * - preferred detailed mode
+        * - other detailed modes from base block
+        * - detailed modes from extension blocks
+        * - CVT 3-byte code modes
+        * - standard timing codes
+        * - established timing codes
+        * - modes inferred from GTF or CVT range information
+        *
+        * We don't quite implement this yet, but we're close.
+        *
+        * XXX order for additional mode types in extension blocks?
+        */
        num_modes += add_detailed_info(connector, edid, quirks);
        num_modes += add_detailed_info_eedid(connector, edid, quirks);
+       num_modes += add_standard_modes(connector, edid);
+       num_modes += add_established_modes(connector, edid);
 
        if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
                edid_fixup_preferred(connector, quirks);
index 288ea2f..b3779d2 100644 (file)
@@ -42,15 +42,33 @@ MODULE_LICENSE("GPL and additional rights");
 
 static LIST_HEAD(kernel_fb_helper_list);
 
-int drm_fb_helper_add_connector(struct drm_connector *connector)
+/* simple single crtc case helper function */
+int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
 {
-       connector->fb_helper_private = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
-       if (!connector->fb_helper_private)
-               return -ENOMEM;
+       struct drm_device *dev = fb_helper->dev;
+       struct drm_connector *connector;
+       int i;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct drm_fb_helper_connector *fb_helper_connector;
+
+               fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
+               if (!fb_helper_connector)
+                       goto fail;
 
+               fb_helper_connector->connector = connector;
+               fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
+       }
        return 0;
+fail:
+       for (i = 0; i < fb_helper->connector_count; i++) {
+               kfree(fb_helper->connector_info[i]);
+               fb_helper->connector_info[i] = NULL;
+       }
+       fb_helper->connector_count = 0;
+       return -ENOMEM;
 }
-EXPORT_SYMBOL(drm_fb_helper_add_connector);
+EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
 
 /**
  * drm_fb_helper_connector_parse_command_line - parse command line for connector
@@ -65,7 +83,7 @@ EXPORT_SYMBOL(drm_fb_helper_add_connector);
  *
  * enable/enable Digital/disable bit at the end
  */
-static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *connector,
+static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
                                                       const char *mode_option)
 {
        const char *name;
@@ -75,13 +93,13 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
        int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
        int i;
        enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
-       struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
        struct drm_fb_helper_cmdline_mode *cmdline_mode;
+       struct drm_connector *connector = fb_helper_conn->connector;
 
-       if (!fb_help_conn)
+       if (!fb_helper_conn)
                return false;
 
-       cmdline_mode = &fb_help_conn->cmdline_mode;
+       cmdline_mode = &fb_helper_conn->cmdline_mode;
        if (!mode_option)
                mode_option = fb_mode_option;
 
@@ -204,18 +222,21 @@ done:
        return true;
 }
 
-int drm_fb_helper_parse_command_line(struct drm_device *dev)
+static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
 {
-       struct drm_connector *connector;
+       struct drm_fb_helper_connector *fb_helper_conn;
+       int i;
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+       for (i = 0; i < fb_helper->connector_count; i++) {
                char *option = NULL;
 
+               fb_helper_conn = fb_helper->connector_info[i];
+
                /* do something on return - turn off connector maybe */
-               if (fb_get_options(drm_get_connector_name(connector), &option))
+               if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
                        continue;
 
-               drm_fb_helper_connector_parse_command_line(connector, option);
+               drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
        }
        return 0;
 }
@@ -293,6 +314,7 @@ static void drm_fb_helper_on(struct fb_info *info)
        struct drm_fb_helper *fb_helper = info->par;
        struct drm_device *dev = fb_helper->dev;
        struct drm_crtc *crtc;
+       struct drm_crtc_helper_funcs *crtc_funcs;
        struct drm_encoder *encoder;
        int i;
 
@@ -300,33 +322,28 @@ static void drm_fb_helper_on(struct fb_info *info)
         * For each CRTC in this fb, turn the crtc on then,
         * find all associated encoders and turn them on.
         */
+       mutex_lock(&dev->mode_config.mutex);
        for (i = 0; i < fb_helper->crtc_count; i++) {
-               list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-                       struct drm_crtc_helper_funcs *crtc_funcs =
-                               crtc->helper_private;
+               crtc = fb_helper->crtc_info[i].mode_set.crtc;
+               crtc_funcs = crtc->helper_private;
 
-                       /* Only mess with CRTCs in this fb */
-                       if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
-                           !crtc->enabled)
-                          &nb