]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge remote branch 'nouveau/for-airlied' of ../drm-nouveau-next into drm-core-next
authorDave Airlie <airlied@redhat.com>
Wed, 6 Oct 2010 02:38:04 +0000 (12:38 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 6 Oct 2010 02:57:11 +0000 (12:57 +1000)
[airlied - add fix for vmwgfx build]

* 'nouveau/for-airlied' of ../drm-nouveau-next: (93 commits)
  drm/ttm: restructure to allow driver to plug in alternate memory manager
  drm/ttm: introduce utility function to free an allocated memory node
  drm/nouveau: fix thinkos in mem timing table recordlen check
  drm/nouveau: parse voltage from perf 0x40 entires
  drm/nouveau: don't use the default pll limits in table v2.1 on nv50+ cards
  drm/nv50: Fix large 3D performance regression caused by the interchannel sync patches.
  drm/nouveau: Synchronize buffer object moves in hardware.
  drm/nouveau: Use semaphores to handle inter-channel sync in hardware.
  drm/nouveau: Provide a means to have arbitrary work run on fence completion.
  drm/nouveau: Minor refactoring/cleanup of the fence code.
  drm/nouveau: Add a module option to force card POST.
  drm/nv50: prevent (IB_PUT == IB_GET) for occurring unless idle
  drm/nv0x-nv4x: Leave the 0x40 bit untouched when changing CRE_LCD.
  drm/nv30-nv40: Fix postdivider mask when writing engine/memory PLLs.
  drm/nouveau: Fix perf table parsing on BMP v5.25.
  drm/nouveau: fix required mode bandwidth calculation for DP
  drm/nouveau: fix typo in c2aa91afea5f7e7ae4530fabd37414a79c03328c
  drm/nva3: split pm backend out from nv50
  drm/nouveau: run perflvl and M table scripts on mem clock change
  drm/nouveau: pass perflvl struct to clock_pre()
  ...

130 files changed:
MAINTAINERS
arch/alpha/kernel/entry.S
arch/alpha/kernel/process.c
arch/m32r/include/asm/signal.h
arch/m32r/include/asm/unistd.h
arch/m32r/kernel/entry.S
arch/m32r/kernel/ptrace.c
arch/m32r/kernel/signal.c
arch/tile/kernel/intvec_32.S
arch/x86/include/asm/cpufeature.h
arch/x86/kernel/cpu/scattered.c
block/blk-merge.c
drivers/char/agp/Makefile
drivers/char/agp/agp.h
drivers/char/agp/backend.c
drivers/char/agp/generic.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-agp.h
drivers/char/agp/intel-gtt.c
drivers/gpu/drm/drm_buffer.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_lock.c
drivers/gpu/drm/drm_proc.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/i810/i810_dma.c
drivers/gpu/drm/i830/i830_dma.c
drivers/gpu/drm/i915/Makefile
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_evict.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/intel_bios.c
drivers/gpu/drm/i915/intel_bios.h
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_i2c.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_opregion.c [moved from drivers/gpu/drm/i915/i915_opregion.c with 81% similarity]
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_notifier.c
drivers/gpu/drm/radeon/atombios.h
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_page_alloc.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/vga/vgaarb.c
drivers/hwmon/Kconfig
drivers/hwmon/coretemp.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/pkgtemp.c
drivers/staging/ti-st/st.h
drivers/staging/ti-st/st_core.c
drivers/staging/ti-st/st_core.h
drivers/staging/ti-st/st_kim.c
drivers/usb/core/Kconfig
drivers/usb/core/file.c
drivers/usb/core/message.c
drivers/usb/musb/cppi_dma.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_gadget.h
drivers/usb/musb/musb_gadget_ep0.c
drivers/usb/musb/musb_host.c
fs/ocfs2/acl.c
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dir.c
fs/ocfs2/dlm/dlmcommon.h
fs/ocfs2/dlm/dlmdebug.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/dlmglue.h
fs/ocfs2/ocfs2_fs.h
fs/ocfs2/ocfs2_ioctl.h
fs/ocfs2/refcounttree.c
fs/ocfs2/reservations.c
fs/ocfs2/suballoc.c
fs/ocfs2/xattr.c
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_pciids.h
include/drm/intel-gtt.h [new file with mode: 0644]
include/drm/vmwgfx_drm.h
mm/fremap.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_realtek.c
sound/pci/oxygen/oxygen.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/soc/sh/migor.c
sound/soc/soc-cache.c

index df342839b8c1466c9ca69799340457975154d108..5e1169df8c1f7aa67ef8eca21053d657b88c6798 100644 (file)
@@ -2051,6 +2051,15 @@ S:       Maintained
 F:     drivers/gpu/drm/
 F:     include/drm/
 
+INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
+M:     Chris Wilson <chris@chris-wilson.co.uk>
+L:     intel-gfx@lists.freedesktop.org
+L:     dri-devel@lists.freedesktop.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git
+S:     Supported
+F:     drivers/gpu/drm/i915
+F:     include/drm/i915*
+
 DSCC4 DRIVER
 M:     Francois Romieu <romieu@fr.zoreil.com>
 L:     netdev@vger.kernel.org
@@ -2668,6 +2677,8 @@ M:        Guenter Roeck <guenter.roeck@ericsson.com>
 L:     lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.org/
 T:     quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-hwmon/
+T:     quilt kernel.org/pub/linux/kernel/people/groeck/linux-staging/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:     Maintained
 F:     Documentation/hwmon/
 F:     drivers/hwmon/
index ab1ee0ab082b996fd0d656b62baa2fcccab7b0b8..d1273c1a136420474ff7250414316ca511746b54 100644 (file)
@@ -73,8 +73,6 @@
        ldq     $20, HAE_REG($19);      \
        stq     $21, HAE_CACHE($19);    \
        stq     $21, 0($20);            \
-       ldq     $0, 0($sp);             \
-       ldq     $1, 8($sp);             \
 99:;                                   \
        ldq     $19, 72($sp);           \
        ldq     $20, 80($sp);           \
@@ -316,7 +314,7 @@ ret_from_sys_call:
        cmovne  $26, 0, $19             /* $19 = 0 => non-restartable */
        ldq     $0, SP_OFF($sp)
        and     $0, 8, $0
-       beq     $0, restore_all
+       beq     $0, ret_to_kernel
 ret_to_user:
        /* Make sure need_resched and sigpending don't change between
                sampling and the rti.  */
@@ -329,6 +327,11 @@ restore_all:
        RESTORE_ALL
        call_pal PAL_rti
 
+ret_to_kernel:
+       lda     $16, 7
+       call_pal PAL_swpipl
+       br restore_all
+
        .align 3
 $syscall_error:
        /*
@@ -657,7 +660,7 @@ kernel_thread:
        /* We don't actually care for a3 success widgetry in the kernel.
           Not for positive errno values.  */
        stq     $0, 0($sp)              /* $0 */
-       br      restore_all
+       br      ret_to_kernel
 .end kernel_thread
 
 /*
index 842dba308eab3065510857e50312496c674c1097..3ec35066f1dc51c09367c32bea106453a109953d 100644 (file)
@@ -356,7 +356,7 @@ dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt, struct thread_info *ti)
        dest[27] = pt->r27;
        dest[28] = pt->r28;
        dest[29] = pt->gp;
-       dest[30] = rdusp();
+       dest[30] = ti == current_thread_info() ? rdusp() : ti->pcb.usp;
        dest[31] = pt->pc;
 
        /* Once upon a time this was the PS value.  Which is stupid
index 9c1acb2b1a928984c8f62ce4a5cd91a25329dc21..b2eeb0de1c8d337a6d7ab5abef363b4797ab7e9a 100644 (file)
@@ -157,7 +157,6 @@ typedef struct sigaltstack {
 #undef __HAVE_ARCH_SIG_BITOPS
 
 struct pt_regs;
-extern int do_signal(struct pt_regs *regs, sigset_t *oldset);
 
 #define ptrace_signal_deliver(regs, cookie)    do { } while (0)
 
index 76125777483ccda07d9d31d55c2f8f3b3201ea05..c70545689da83ef2ffaef987b2c3374fadca04fc 100644 (file)
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT /*will be unused*/
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 
 #define __IGNORE_lchown
 #define __IGNORE_setuid
index 403869833b98fe6c95fd360d80cd762f3a5008e2..225412bc227e690bcb313743dd16f58fca5c4115 100644 (file)
@@ -235,10 +235,9 @@ work_resched:
 work_notifysig:                                ; deal with pending signals and
                                        ; notify-resume requests
        mv      r0, sp                  ; arg1 : struct pt_regs *regs
-       ldi     r1, #0                  ; arg2 : sigset_t *oldset
-       mv      r2, r9                  ; arg3 : __u32 thread_info_flags
+       mv      r1, r9                  ; arg2 : __u32 thread_info_flags
        bl      do_notify_resume
-       bra     restore_all
+       bra     resume_userspace
 
        ; perform syscall exit tracing
        ALIGN
index e555091eb97cbcf8bbe261851be3b72e90e6075e..0021ade4cba8c86bf1d2fd348b283d8cac591955 100644 (file)
@@ -592,16 +592,17 @@ void user_enable_single_step(struct task_struct *child)
 
        if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0)
            != sizeof(insn))
-               break;
+               return -EIO;
 
        compute_next_pc(insn, pc, &next_pc, child);
        if (next_pc & 0x80000000)
-               break;
+               return -EIO;
 
        if (embed_debug_trap(child, next_pc))
-               break;
+               return -EIO;
 
        invalidate_cache();
+       return 0;
 }
 
 void user_disable_single_step(struct task_struct *child)
index 144b0f124fc72f08b20f93336f96da81327fe61c..7bbe38645ed5559395f85c5b5fce93eb3f4992e3 100644 (file)
 
 #define DEBUG_SIG 0
 
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
-int do_signal(struct pt_regs *, sigset_t *);
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
-                 unsigned long r2, unsigned long r3, unsigned long r4,
-                 unsigned long r5, unsigned long r6, struct pt_regs *regs)
-{
-       sigset_t newset;
-
-       /* XXX: Don't preclude handling different sized sigset_t's.  */
-       if (sigsetsize != sizeof(sigset_t))
-               return -EINVAL;
-
-       if (copy_from_user(&newset, unewset, sizeof(newset)))
-               return -EFAULT;
-       sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
-
-       spin_lock_irq(&current->sighand->siglock);
-       current->saved_sigmask = current->blocked;
-       current->blocked = newset;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       current->state = TASK_INTERRUPTIBLE;
-       schedule();
-       set_thread_flag(TIF_RESTORE_SIGMASK);
-       return -ERESTARTNOHAND;
-}
-
 asmlinkage int
 sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
                unsigned long r2, unsigned long r3, unsigned long r4,
@@ -218,7 +187,7 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
        return (void __user *)((sp - frame_size) & -8ul);
 }
 
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                           sigset_t *set, struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
@@ -275,22 +244,34 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                current->comm, current->pid, frame, regs->pc);
 #endif
 
-       return;
+       return 0;
 
 give_sigsegv:
        force_sigsegv(sig, current);
+       return -EFAULT;
+}
+
+static int prev_insn(struct pt_regs *regs)
+{
+       u16 inst;
+       if (get_user(&inst, (u16 __user *)(regs->bpc - 2)))
+               return -EFAULT;
+       if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
+               regs->bpc -= 2;
+       else
+               regs->bpc -= 4;
+       regs->syscall_nr = -1;
+       return 0;
 }
 
 /*
  * OK, we're invoking a handler
  */
 
-static void
+static int
 handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
              sigset_t *oldset, struct pt_regs *regs)
 {
-       unsigned short inst;
-
        /* Are we from a system call? */
        if (regs->syscall_nr >= 0) {
                /* If so, check system call restarting.. */
@@ -308,16 +289,14 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
                        /* fallthrough */
                        case -ERESTARTNOINTR:
                                regs->r0 = regs->orig_r0;
-                               inst = *(unsigned short *)(regs->bpc - 2);
-                               if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
-                                       regs->bpc -= 2;
-                               else
-                                       regs->bpc -= 4;
+                               if (prev_insn(regs) < 0)
+                                       return -EFAULT;
                }
        }
 
        /* Set up the stack frame */
-       setup_rt_frame(sig, ka, info, oldset, regs);
+       if (setup_rt_frame(sig, ka, info, oldset, regs))
+               return -EFAULT;
 
        spin_lock_irq(&current->sighand->siglock);
        sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -325,6 +304,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
                sigaddset(&current->blocked,sig);
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
+       return 0;
 }
 
 /*
@@ -332,12 +312,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-int do_signal(struct pt_regs *regs, sigset_t *oldset)
+static void do_signal(struct pt_regs *regs)
 {
        siginfo_t info;
        int signr;
        struct k_sigaction ka;
-       unsigned short inst;
+       sigset_t *oldset;
 
        /*
         * We want the common case to go fast, which
@@ -346,12 +326,14 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
         * if so.
         */
        if (!user_mode(regs))
-               return 1;
+               return;
 
        if (try_to_freeze()) 
                goto no_signal;
 
-       if (!oldset)
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
                oldset = &current->blocked;
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
@@ -363,8 +345,10 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
                 */
 
                /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &ka, &info, oldset, regs);
-               return 1;
+               if (handle_signal(signr, &ka, &info, oldset, regs) == 0)
+                       clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+               return;
        }
 
  no_signal:
@@ -375,31 +359,24 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
                    regs->r0 == -ERESTARTSYS ||
                    regs->r0 == -ERESTARTNOINTR) {
                        regs->r0 = regs->orig_r0;
-                       inst = *(unsigned short *)(regs->bpc - 2);
-                       if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
-                               regs->bpc -= 2;
-                       else
-                               regs->bpc -= 4;
-               }
-               if (regs->r0 == -ERESTART_RESTARTBLOCK){
+                       prev_insn(regs);
+               } else if (regs->r0 == -ERESTART_RESTARTBLOCK){
                        regs->r0 = regs->orig_r0;
                        regs->r7 = __NR_restart_syscall;
-                       inst = *(unsigned short *)(regs->bpc - 2);
-                       if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
-                               regs->bpc -= 2;
-                       else
-                               regs->bpc -= 4;
+                       prev_insn(regs);
                }
        }
-       return 0;
+       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
 }
 
 /*
  * notification of userspace execution resumption
  * - triggered by current->work.notify_resume
  */
-void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
-                     __u32 thread_info_flags)
+void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags)
 {
        /* Pending single-step? */
        if (thread_info_flags & _TIF_SINGLESTEP)
@@ -407,7 +384,7 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
 
        /* deal with pending signal delivery */
        if (thread_info_flags & _TIF_SIGPENDING)
-               do_signal(regs,oldset);
+               do_signal(regs);
 
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
index 84f296ca9e63c85da528ee9a8d403cc8362c4097..8f58bdff20d7f7dd9b77d16a6901eb9db82f056b 100644 (file)
@@ -1506,13 +1506,6 @@ handle_ill:
        }
        STD_ENDPROC(handle_ill)
 
-       .pushsection .rodata, "a"
-       .align  8
-bpt_code:
-       bpt
-       ENDPROC(bpt_code)
-       .popsection
-
 /* Various stub interrupt handlers and syscall handlers */
 
 STD_ENTRY_LOCAL(_kernel_double_fault)
index c6fbb7b430d167c7663f99901b2c653ec6556911..3f76523589afa8b9f30abcb6841962b6344d603e 100644 (file)
 #define X86_FEATURE_XSAVEOPT   (7*32+ 4) /* Optimized Xsave */
 #define X86_FEATURE_PLN                (7*32+ 5) /* Intel Power Limit Notification */
 #define X86_FEATURE_PTS                (7*32+ 6) /* Intel Package Thermal Status */
+#define X86_FEATURE_DTS                (7*32+ 7) /* Digital Thermal Sensor */
 
 /* Virtualization flags: Linux defined, word 8 */
 #define X86_FEATURE_TPR_SHADOW  (8*32+ 0) /* Intel TPR Shadow */
index 34b4dad6f0b8e35a0fe80d01f8708c230592144d..d49079515122a6f47d2731cb1d2ac2f03efaf6e0 100644 (file)
@@ -31,6 +31,7 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
        const struct cpuid_bit *cb;
 
        static const struct cpuid_bit __cpuinitconst cpuid_bits[] = {
+               { X86_FEATURE_DTS,              CR_EAX, 0, 0x00000006, 0 },
                { X86_FEATURE_IDA,              CR_EAX, 1, 0x00000006, 0 },
                { X86_FEATURE_ARAT,             CR_EAX, 2, 0x00000006, 0 },
                { X86_FEATURE_PLN,              CR_EAX, 4, 0x00000006, 0 },
index 3b0cd4249671d9826b42ea10473a11486c403368..eafc94f68d79f2ceb1c0a89fce8e449c3a5ff3f6 100644 (file)
@@ -361,6 +361,18 @@ static int attempt_merge(struct request_queue *q, struct request *req,
        if (!rq_mergeable(req) || !rq_mergeable(next))
                return 0;
 
+       /*
+        * Don't merge file system requests and discard requests
+        */
+       if ((req->cmd_flags & REQ_DISCARD) != (next->cmd_flags & REQ_DISCARD))
+               return 0;
+
+       /*
+        * Don't merge discard requests and secure discard requests
+        */
+       if ((req->cmd_flags & REQ_SECURE) != (next->cmd_flags & REQ_SECURE))
+               return 0;
+
        /*
         * not contiguous
         */
index 627f542827c7069b4352bb1692d0baae2af63d38..8eb56e273e75719f51d617fe3a2ed5c4b9cc06f2 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_AGP_HP_ZX1)      += hp-agp.o
 obj-$(CONFIG_AGP_PARISC)       += parisc-agp.o
 obj-$(CONFIG_AGP_I460)         += i460-agp.o
 obj-$(CONFIG_AGP_INTEL)                += intel-agp.o
+obj-$(CONFIG_AGP_INTEL)                += intel-gtt.o
 obj-$(CONFIG_AGP_NVIDIA)       += nvidia-agp.o
 obj-$(CONFIG_AGP_SGI_TIOCA)    += sgi-agp.o
 obj-$(CONFIG_AGP_SIS)          += sis-agp.o
index 120490949997b71c86785d3af5156ea63b3c2330..5259065f3c792b16829b00c6200e73938250d74a 100644 (file)
@@ -121,11 +121,6 @@ struct agp_bridge_driver {
        void (*agp_destroy_pages)(struct agp_memory *);
        int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
        void (*chipset_flush)(struct agp_bridge_data *);
-
-       int (*agp_map_page)(struct page *page, dma_addr_t *ret);
-       void (*agp_unmap_page)(struct page *page, dma_addr_t dma);
-       int (*agp_map_memory)(struct agp_memory *mem);
-       void (*agp_unmap_memory)(struct agp_memory *mem);
 };
 
 struct agp_bridge_data {
index ee4f855611b676b589046fad44f1e934bd615896..f27d0d0816d3ce5371a9948bc9841e74ba0f533b 100644 (file)
@@ -151,17 +151,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
                }
 
                bridge->scratch_page_page = page;
-               if (bridge->driver->agp_map_page) {
-                       if (bridge->driver->agp_map_page(page,
-                                                        &bridge->scratch_page_dma)) {
-                               dev_err(&bridge->dev->dev,
-                                       "unable to dma-map scratch page\n");
-                               rc = -ENOMEM;
-                               goto err_out_nounmap;
-                       }
-               } else {
-                       bridge->scratch_page_dma = page_to_phys(page);
-               }
+               bridge->scratch_page_dma = page_to_phys(page);
 
                bridge->scratch_page = bridge->driver->mask_memory(bridge,
                                                   bridge->scratch_page_dma, 0);
@@ -204,12 +194,6 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
        return 0;
 
 err_out:
-       if (bridge->driver->needs_scratch_page &&
-           bridge->driver->agp_unmap_page) {
-               bridge->driver->agp_unmap_page(bridge->scratch_page_page,
-                                              bridge->scratch_page_dma);
-       }
-err_out_nounmap:
        if (bridge->driver->needs_scratch_page) {
                void *va = page_address(bridge->scratch_page_page);
 
@@ -240,10 +224,6 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
            bridge->driver->needs_scratch_page) {
                void *va = page_address(bridge->scratch_page_page);
 
-               if (bridge->driver->agp_unmap_page)
-                       bridge->driver->agp_unmap_page(bridge->scratch_page_page,
-                                                      bridge->scratch_page_dma);
-
                bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
                bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
        }
index d2abf51439836383fd9b03612a44bdf1779448fa..78235ceccfa199c274c32e46abc52fdae3d2d197 100644 (file)
@@ -437,11 +437,6 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start)
                curr->is_flushed = true;
        }
 
-       if (curr->bridge->driver->agp_map_memory) {
-               ret_val = curr->bridge->driver->agp_map_memory(curr);
-               if (ret_val)
-                       return ret_val;
-       }
        ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type);
 
        if (ret_val != 0)
@@ -483,9 +478,6 @@ int agp_unbind_memory(struct agp_memory *curr)
        if (ret_val != 0)
                return ret_val;
 
-       if (curr->bridge->driver->agp_unmap_memory)
-               curr->bridge->driver->agp_unmap_memory(curr);
-
        curr->is_bound = false;
        curr->pg_start = 0;
        spin_lock(&curr->bridge->mapped_lock);
index cd18493c952795317904229197016e40d7c408cd..5cd2221ab472a629da3429bea0aeb08f1f217382 100644 (file)
@@ -12,9 +12,6 @@
 #include <asm/smp.h>
 #include "agp.h"
 #include "intel-agp.h"
-#include <linux/intel-gtt.h>
-
-#include "intel-gtt.c"
 
 int intel_agp_enabled;
 EXPORT_SYMBOL(intel_agp_enabled);
@@ -703,179 +700,37 @@ static const struct agp_bridge_driver intel_7505_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static int find_gmch(u16 device)
-{
-       struct pci_dev *gmch_device;
-
-       gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
-       if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
-               gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                            device, gmch_device);
-       }
-
-       if (!gmch_device)
-               return 0;
-
-       intel_private.pcidev = gmch_device;
-       return 1;
-}
-
 /* Table to describe Intel GMCH and AGP/PCIE GART drivers.  At least one of
  * driver and gmch_driver must be non-null, and find_gmch will determine
  * which one should be used if a gmch_chip_id is present.
  */
-static const struct intel_driver_description {
+static const struct intel_agp_driver_description {
        unsigned int chip_id;
-       unsigned int gmch_chip_id;
        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, "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, "i810",
-               NULL, &intel_810_driver },
-       { 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, "i815",
-               &intel_815_driver, &intel_810_driver },
-       { 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, "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, "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, "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, "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, "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, "915G",
-               NULL, &intel_915_driver },
-       { 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, "945G",
-               NULL, &intel_915_driver },
-       { 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, "945GME",
-               NULL, &intel_915_driver },
-       { 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, "G35",
-               NULL, &intel_i965_driver },
-       { 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, "965G",
-               NULL, &intel_i965_driver },
-       { 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, "965GME/GLE",
-               NULL, &intel_i965_driver },
-       { 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, "Q35",
-               NULL, &intel_g33_driver },
-       { 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, "GMA3150",
-               NULL, &intel_g33_driver },
-       { 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,
-           "GM45", NULL, &intel_i965_driver },
-       { 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,
-           "Q45/Q43", NULL, &intel_i965_driver },
-       { 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,
-           "B43", NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_B43_1_HB, PCI_DEVICE_ID_INTEL_B43_1_IG,
-           "B43", NULL, &intel_i965_driver },
-       { 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,
-           "HD Graphics", NULL, &intel_i965_driver },
-       { 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,
-           "HD Graphics", NULL, &intel_i965_driver },
-       { 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_GT1_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
-           "Sandybridge", NULL, &intel_gen6_driver },
-       { 0, 0, NULL, NULL, NULL }
+       { PCI_DEVICE_ID_INTEL_82443LX_0, "440LX", &intel_generic_driver },
+       { PCI_DEVICE_ID_INTEL_82443BX_0, "440BX", &intel_generic_driver },
+       { PCI_DEVICE_ID_INTEL_82443GX_0, "440GX", &intel_generic_driver },
+       { PCI_DEVICE_ID_INTEL_82815_MC, "i815", &intel_815_driver },
+       { PCI_DEVICE_ID_INTEL_82820_HB, "i820", &intel_820_driver },
+       { PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver },
+       { PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver },
+       { PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver },
+       { PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver },
+       { PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82855GM_HB, "855GM", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82860_HB, "i860", &intel_860_driver },
+       { PCI_DEVICE_ID_INTEL_82865_HB, "865", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82875_HB, "i875", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_7505_0, "E7505", &intel_7505_driver },
+       { PCI_DEVICE_ID_INTEL_7205_0, "E7205", &intel_7505_driver },
+       { 0, NULL, NULL }
 };
 
-static int __devinit intel_gmch_probe(struct pci_dev *pdev,
-                                     struct agp_bridge_data *bridge)
-{
-       int i, mask;
-
-       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_gen6_mask_memory)
-               mask = 40;
-       else if (bridge->driver->mask_memory == intel_i965_mask_memory)
-               mask = 36;
-       else
-               mask = 32;
-
-       if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
-               dev_err(&intel_private.pcidev->dev,
-                       "set gfx device dma mask %d-bit failed!\n", mask);
-       else
-               pci_set_consistent_dma_mask(intel_private.pcidev,
-                                           DMA_BIT_MASK(mask));
-
-       return 1;
-}
-
 static int __devinit agp_intel_probe(struct pci_dev *pdev,
                                     const struct pci_device_id *ent)
 {
@@ -905,7 +760,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                }
        }
 
-       if (intel_agp_chipsets[i].name == NULL) {
+       if (!bridge->driver) {
                if (cap_ptr)
                        dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n",
                                 pdev->vendor, pdev->device);
@@ -913,14 +768,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                return -ENODEV;
        }
 
-       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);
-               agp_put_bridge(bridge);
-               return -ENODEV;
-       }
-
        bridge->dev = pdev;
        bridge->dev_private_data = NULL;
 
@@ -972,8 +819,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev)
 
        agp_remove_bridge(bridge);
 
-       if (intel_private.pcidev)
-               pci_dev_put(intel_private.pcidev);
+       intel_gmch_remove(pdev);
 
        agp_put_bridge(bridge);
 }
index d09b1ab7e8abeac5bbdf0cc8a8dd5f333f9c22a3..90539df02504ca0ee75ebf1923fd814a50a738bc 100644 (file)
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB           0x0108  /* Server */
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG           0x010A
 
-/* 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 || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_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)
-
+int intel_gmch_probe(struct pci_dev *pdev,
+                              struct agp_bridge_data *bridge);
+void intel_gmch_remove(struct pci_dev *pdev);
 #endif
index 75e0a3497888d295d25dd414bda8a2ce69eee724..0c8ff6d8824bdbe3e37e9d7e337a23735b4227b8 100644 (file)
  * /fairy-tale-mode off
  */
 
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pagemap.h>
+#include <linux/agp_backend.h>
+#include <asm/smp.h>
+#include "agp.h"
+#include "intel-agp.h"
+#include <linux/intel-gtt.h>
+#include <drm/intel-gtt.h>
+
 /*
  * 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
  */
 #ifdef CONFIG_DMAR
 #define USE_PCI_DMA_API 1
+#else
+#define USE_PCI_DMA_API 0
 #endif
 
 /* Max amount of stolen space, anything above will be returned to Linux */
 int intel_max_stolen = 32 * 1024 * 1024;
-EXPORT_SYMBOL(intel_max_stolen);
 
 static const struct aper_size_info_fixed intel_i810_sizes[] =
 {
@@ -55,32 +68,36 @@ static struct gatt_mask intel_i810_masks[] =
 #define INTEL_AGP_CACHED_MEMORY_LLC_MLC        3
 #define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT   4
 
-static struct gatt_mask intel_gen6_masks[] =
-{
-       {.mask = I810_PTE_VALID | GEN6_PTE_UNCACHED,
-        .type = INTEL_AGP_UNCACHED_MEMORY },
-       {.mask = I810_PTE_VALID | GEN6_PTE_LLC,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC },
-       {.mask = I810_PTE_VALID | GEN6_PTE_LLC | GEN6_PTE_GFDT,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_GFDT },
-       {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC },
-       {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC | GEN6_PTE_GFDT,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT },
+struct intel_gtt_driver {
+       unsigned int gen : 8;
+       unsigned int is_g33 : 1;
+       unsigned int is_pineview : 1;
+       unsigned int is_ironlake : 1;
+       unsigned int dma_mask_size : 8;
+       /* Chipset specific GTT setup */
+       int (*setup)(void);
+       /* This should undo anything done in ->setup() save the unmapping
+        * of the mmio register file, that's done in the generic code. */
+       void (*cleanup)(void);
+       void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags);
+       /* Flags is a more or less chipset specific opaque value.
+        * For chipsets that need to support old ums (non-gem) code, this
+        * needs to be identical to the various supported agp memory types! */
+       bool (*check_flags)(unsigned int flags);
+       void (*chipset_flush)(void);
 };
 
 static struct _intel_private {
+       struct intel_gtt base;
+       const struct intel_gtt_driver *driver;
        struct pci_dev *pcidev; /* device one */
+       struct pci_dev *bridge_dev;
        u8 __iomem *registers;
+       phys_addr_t gtt_bus_addr;
+       phys_addr_t gma_bus_addr;
+       phys_addr_t pte_bus_addr;
        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;
@@ -88,23 +105,14 @@ static struct _intel_private {
        struct page *i8xx_page;
        struct resource ifp_resource;
        int resource_valid;
+       struct page *scratch_page;
+       dma_addr_t scratch_page_dma;
 } 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);
-}
+#define INTEL_GTT_GEN  intel_private.driver->gen
+#define IS_G33         intel_private.driver->is_g33
+#define IS_PINEVIEW    intel_private.driver->is_pineview
+#define IS_IRONLAKE    intel_private.driver->is_ironlake
 
 static void intel_agp_free_sglist(struct agp_memory *mem)
 {
@@ -125,6 +133,9 @@ static int intel_agp_map_memory(struct agp_memory *mem)
        struct scatterlist *sg;
        int i;
 
+       if (mem->sg_list)
+               return 0; /* already mapped (for e.g. resume */
+
        DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
 
        if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
@@ -156,70 +167,17 @@ static void intel_agp_unmap_memory(struct agp_memory *mem)
        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;
-
-       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);
+       pci_read_config_dword(intel_private.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");
+               dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n");
                return 0;
        }
        if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
@@ -284,7 +242,7 @@ static void intel_i810_cleanup(void)
        iounmap(intel_private.registers);
 }
 
-static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 {
        return;
 }
@@ -319,34 +277,6 @@ static void i8xx_destroy_pages(struct page *page)
        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_gen6_type_to_mask_type(struct agp_bridge_data *bridge,
-                                       int type)
-{
-       unsigned int type_mask = type & ~AGP_USER_CACHED_MEMORY_GFDT;
-       unsigned int gfdt = type & AGP_USER_CACHED_MEMORY_GFDT;
-
-       if (type_mask == AGP_USER_UNCACHED_MEMORY)
-               return INTEL_AGP_UNCACHED_MEMORY;
-       else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC)
-               return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT :
-                             INTEL_AGP_CACHED_MEMORY_LLC_MLC;
-       else /* set 'normal'/'cached' to LLC by default */
-               return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_GFDT :
-                             INTEL_AGP_CACHED_MEMORY_LLC;
-}
-
-
 static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
                                int type)
 {
@@ -514,8 +444,33 @@ static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
        return addr | bridge->driver->masks[type].mask;
 }
 
-static struct aper_size_info_fixed intel_i830_sizes[] =
+static int intel_gtt_setup_scratch_page(void)
 {
+       struct page *page;
+       dma_addr_t dma_addr;
+
+       page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+       if (page == NULL)
+               return -ENOMEM;
+       get_page(page);
+       set_pages_uc(page, 1);
+
+       if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+               dma_addr = pci_map_page(intel_private.pcidev, page, 0,
+                                   PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+               if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
+                       return -EINVAL;
+
+               intel_private.scratch_page_dma = dma_addr;
+       } else
+               intel_private.scratch_page_dma = page_to_phys(page);
+
+       intel_private.scratch_page = page;
+
+       return 0;
+}
+
+static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = {
        {128, 32768, 5},
        /* The 64M mode still requires a 128k gatt */
        {64, 16384, 5},
@@ -523,102 +478,49 @@ static struct aper_size_info_fixed intel_i830_sizes[] =
        {512, 131072, 7},
 };
 
-static void intel_i830_init_gtt_entries(void)
+static unsigned int intel_gtt_stolen_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 */
+       unsigned int overhead_entries, stolen_entries;
+       unsigned int stolen_size = 0;
 
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+       pci_read_config_word(intel_private.bridge_dev,
+                            I830_GMCH_CTRL, &gmch_ctrl);
 
-       if (IS_I965) {
-               u32 pgetbl_ctl;
-               pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+       if (INTEL_GTT_GEN > 4 || IS_PINEVIEW)
+               overhead_entries = 0;
+       else
+               overhead_entries = intel_private.base.gtt_mappable_entries
+                       / 1024;
 
-               /* 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;
-       }
+       overhead_entries += 1; /* BIOS popup */
 
-       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
-           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
+       if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
+           intel_private.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);
+                       stolen_size = KB(512);
                        break;
                case I830_GMCH_GMS_STOLEN_1024:
-                       gtt_entries = MB(1) - KB(size);
+                       stolen_size = MB(1);
                        break;
                case I830_GMCH_GMS_STOLEN_8192:
-                       gtt_entries = MB(8) - KB(size);
+                       stolen_size = MB(8);
                        break;
                case I830_GMCH_GMS_LOCAL:
                        rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
-                       gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
+                       stolen_size = (I830_RDRAM_ND(rdct) + 1) *
                                        MB(ddt[I830_RDRAM_DDT(rdct)]);
                        local = 1;
                        break;
                default:
-                       gtt_entries = 0;
+                       stolen_size = 0;
                        break;
                }
-       } else if (IS_SNB) {
+       } else if (INTEL_GTT_GEN == 6) {
                /*
                 * SandyBridge has new memory control reg at 0x50.w
                 */
@@ -626,149 +528,292 @@ static void intel_i830_init_gtt_entries(void)
                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);
+                       stolen_size = MB(32);
                        break;
                case SNB_GMCH_GMS_STOLEN_64M:
-                       gtt_entries = MB(64) - KB(size);
+                       stolen_size = MB(64);
                        break;
                case SNB_GMCH_GMS_STOLEN_96M:
-                       gtt_entries = MB(96) - KB(size);
+                       stolen_size = MB(96);
                        break;
                case SNB_GMCH_GMS_STOLEN_128M:
-                       gtt_entries = MB(128) - KB(size);
+                       stolen_size = MB(128);
                        break;
                case SNB_GMCH_GMS_STOLEN_160M:
-                       gtt_entries = MB(160) - KB(size);
+                       stolen_size = MB(160);
                        break;
                case SNB_GMCH_GMS_STOLEN_192M:
-                       gtt_entries = MB(192) - KB(size);
+                       stolen_size = MB(192);
                        break;
                case SNB_GMCH_GMS_STOLEN_224M:
-                       gtt_entries = MB(224) - KB(size);
+                       stolen_size = MB(224);
                        break;
                case SNB_GMCH_GMS_STOLEN_256M:
-                       gtt_entries = MB(256) - KB(size);
+                       stolen_size = MB(256);
                        break;
                case SNB_GMCH_GMS_STOLEN_288M:
-                       gtt_entries = MB(288) - KB(size);
+                       stolen_size = MB(288);
                        break;
                case SNB_GMCH_GMS_STOLEN_320M:
-                       gtt_entries = MB(320) - KB(size);
+                       stolen_size = MB(320);
                        break;
                case SNB_GMCH_GMS_STOLEN_352M:
-                       gtt_entries = MB(352) - KB(size);
+                       stolen_size = MB(352);
                        break;
                case SNB_GMCH_GMS_STOLEN_384M:
-                       gtt_entries = MB(384) - KB(size);
+                       stolen_size = MB(384);
                        break;
                case SNB_GMCH_GMS_STOLEN_416M:
-                       gtt_entries = MB(416) - KB(size);
+                       stolen_size = MB(416);
                        break;
                case SNB_GMCH_GMS_STOLEN_448M:
-                       gtt_entries = MB(448) - KB(size);
+                       stolen_size = MB(448);
                        break;
                case SNB_GMCH_GMS_STOLEN_480M:
-                       gtt_entries = MB(480) - KB(size);
+                       stolen_size = MB(480);
                        break;
                case SNB_GMCH_GMS_STOLEN_512M:
-                       gtt_entries = MB(512) - KB(size);
+                       stolen_size = MB(512);
                        break;
                }
        } else {
                switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
                case I855_GMCH_GMS_STOLEN_1M:
-                       gtt_entries = MB(1) - KB(size);
+                       stolen_size = MB(1);
                        break;
                case I855_GMCH_GMS_STOLEN_4M:
-                       gtt_entries = MB(4) - KB(size);
+                       stolen_size = MB(4);
                        break;
                case I855_GMCH_GMS_STOLEN_8M:
-                       gtt_entries = MB(8) - KB(size);
+                       stolen_size = MB(8);
                        break;
                case I855_GMCH_GMS_STOLEN_16M:
-                       gtt_entries = MB(16) - KB(size);
+                       stolen_size = MB(16);
                        break;
                case I855_GMCH_GMS_STOLEN_32M:
-                       gtt_entries = MB(32) - KB(size);
+                       stolen_size = MB(32);
                        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;
+                       stolen_size = MB(48);
                        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;
+                       stolen_size = MB(64);
                        break;
                case G33_GMCH_GMS_STOLEN_128M:
-                       if (IS_G33 || IS_I965 || IS_G4X)
-                               gtt_entries = MB(128) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(128);
                        break;
                case G33_GMCH_GMS_STOLEN_256M:
-                       if (IS_G33 || IS_I965 || IS_G4X)
-                               gtt_entries = MB(256) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(256);
                        break;
                case INTEL_GMCH_GMS_STOLEN_96M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(96) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(96);
                        break;
                case INTEL_GMCH_GMS_STOLEN_160M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(160) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(160);
                        break;
                case INTEL_GMCH_GMS_STOLEN_224M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(224) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(224);
                        break;
                case INTEL_GMCH_GMS_STOLEN_352M:
-                       if (IS_I965 || IS_G4X)
-                               gtt_entries = MB(352) - KB(size);
-                       else
-                               gtt_entries = 0;
+                       stolen_size = MB(352);
                        break;
                default:
-                       gtt_entries = 0;
+                       stolen_size = 0;
                        break;
                }
        }
-       if (!local && gtt_entries > intel_max_stolen) {
-               dev_info(&agp_bridge->dev->dev,
+
+       if (!local && stolen_size > intel_max_stolen) {
+               dev_info(&intel_private.bridge_dev->dev,
                         "detected %dK stolen memory, trimming to %dK\n",
-                        gtt_entries / KB(1), intel_max_stolen / KB(1));
-               gtt_entries = intel_max_stolen / KB(4);
-       } else 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);
+                        stolen_size / KB(1), intel_max_stolen / KB(1));
+               stolen_size = intel_max_stolen;
+       } else if (stolen_size > 0) {
+               dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n",
+                      stolen_size / KB(1), local ? "local" : "stolen");
        } else {
-               dev_info(&agp_bridge->dev->dev,
+               dev_info(&intel_private.bridge_dev->dev,
                       "no pre-allocated video memory detected\n");
-               gtt_entries = 0;
+               stolen_size = 0;
+       }
+
+       stolen_entries = stolen_size/KB(4) - overhead_entries;
+
+       return stolen_entries;
+}
+
+static unsigned int intel_gtt_total_entries(void)
+{
+       int size;
+
+       if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) {
+               u32 pgetbl_ctl;
+               pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+
+               switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+               case I965_PGETBL_SIZE_128KB:
+                       size = KB(128);
+                       break;
+               case I965_PGETBL_SIZE_256KB:
+                       size = KB(256);
+                       break;
+               case I965_PGETBL_SIZE_512KB:
+                       size = KB(512);
+                       break;
+               case I965_PGETBL_SIZE_1MB:
+                       size = KB(1024);
+                       break;
+               case I965_PGETBL_SIZE_2MB:
+                       size = KB(2048);
+                       break;
+               case I965_PGETBL_SIZE_1_5MB:
+                       size = KB(1024 + 512);
+                       break;
+               default:
+                       dev_info(&intel_private.pcidev->dev,
+                                "unknown page table size, assuming 512KB\n");
+                       size = KB(512);
+               }
+
+               return size/4;
+       } else if (INTEL_GTT_GEN == 6) {
+               u16 snb_gmch_ctl;
+
+               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);
+                       size = MB(0);
+                       break;
+               case SNB_GTT_SIZE_1M:
+                       size = MB(1);
+                       break;
+               case SNB_GTT_SIZE_2M:
+                       size = MB(2);
+                       break;
+               }
+               return size/4;
+       } else {
+               /* On previous hardware, the GTT size was just what was
+                * required to map the aperture.
+                */
+               return intel_private.base.gtt_mappable_entries;
+       }
+}
+
+static unsigned int intel_gtt_mappable_entries(void)
+{
+       unsigned int aperture_size;
+
+       if (INTEL_GTT_GEN == 2) {
+               u16 gmch_ctrl;
+
+               pci_read_config_word(intel_private.bridge_dev,
+                                    I830_GMCH_CTRL, &gmch_ctrl);
+
+               if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M)
+                       aperture_size = MB(64);
+               else
+                       aperture_size = MB(128);
+       } else {
+               /* 9xx supports large sizes, just look at the length */
+               aperture_size = pci_resource_len(intel_private.pcidev, 2);
+       }
+
+       return aperture_size >> PAGE_SHIFT;
+}
+
+static void intel_gtt_teardown_scratch_page(void)
+{
+       set_pages_wb(intel_private.scratch_page, 1);
+       pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma,
+                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+       put_page(intel_private.scratch_page);
+       __free_page(intel_private.scratch_page);
+}
+
+static void intel_gtt_cleanup(void)
+{
+       intel_private.driver->cleanup();
+
+       iounmap(intel_private.gtt);
+       iounmap(intel_private.registers);
+       
+       intel_gtt_teardown_scratch_page();
+}
+
+static int intel_gtt_init(void)
+{
+       u32 gtt_map_size;
+       int ret;
+
+       ret = intel_private.driver->setup();
+       if (ret != 0)
+               return ret;
+
+       intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries();
+       intel_private.base.gtt_total_entries = intel_gtt_total_entries();
+
+       dev_info(&intel_private.bridge_dev->dev,
+                       "detected gtt size: %dK total, %dK mappable\n",
+                       intel_private.base.gtt_total_entries * 4,
+                       intel_private.base.gtt_mappable_entries * 4);
+
+       gtt_map_size = intel_private.base.gtt_total_entries * 4;
+
+       intel_private.gtt = ioremap(intel_private.gtt_bus_addr,
+                                   gtt_map_size);
+       if (!intel_private.gtt) {
+               intel_private.driver->cleanup();
+               iounmap(intel_private.registers);
+               return -ENOMEM;
+       }
+
+       global_cache_flush();   /* FIXME: ? */
+
+       /* we have to call this as early as possible after the MMIO base address is known */
+       intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries();
+       if (intel_private.base.gtt_stolen_entries == 0) {
+               intel_private.driver->cleanup();
+               iounmap(intel_private.registers);
+               iounmap(intel_private.gtt);
+               return -ENOMEM;
+       }
+
+       ret = intel_gtt_setup_scratch_page();
+       if (ret != 0) {
+               intel_gtt_cleanup();
+               return ret;
+       }
+
+       return 0;
+}
+
+static int intel_fake_agp_fetch_size(void)
+{
+       int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes);
+       unsigned int aper_size;
+       int i;
+
+       aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT)
+                   / MB(1);
+
+       for (i = 0; i < num_sizes; i++) {
+               if (aper_size == intel_fake_agp_sizes[i].size) {
+                       agp_bridge->current_size =
+                               (void *) (intel_fake_agp_sizes + i);
+                       return aper_size;
+               }
        }
 
-       intel_private.gtt_entries = gtt_entries;
+       return 0;
 }
 
-static void intel_i830_fini_flush(void)
+static void i830_cleanup(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;
@@ -780,13 +825,13 @@ static void intel_i830_setup_flush(void)
        if (intel_private.i8xx_page)
                return;
 
-       intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
+       intel_private.i8xx_page = alloc_page(GFP_KERNEL);
        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();
+               i830_cleanup();
 }
 
 /* The chipset_flush interface needs to get data that has already been
@@ -799,7 +844,7 @@ static void intel_i830_setup_flush(void)
  * 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)
+static void i830_chipset_flush(void)
 {
        unsigned int *pg = intel_private.i8xx_flush_page;
 
@@ -811,169 +856,184 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
                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)
+static void i830_write_entry(dma_addr_t addr, unsigned int entry,
+                            unsigned int flags)
 {
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp;
+       u32 pte_flags = I810_PTE_VALID;
+       
+       switch (flags) {
+       case AGP_DCACHE_MEMORY:
+               pte_flags |= I810_PTE_LOCAL;
+               break;
+       case AGP_USER_CACHED_MEMORY:
+               pte_flags |= I830_PTE_SYSTEM_CACHED;
+               break;
+       }
 
-       size = agp_bridge->current_size;
-       page_order = size->page_order;
-       num_entries = size->num_entries;
-       agp_bridge->gatt_table_real = NULL;
+       writel(addr | pte_flags, intel_private.gtt + entry);
+}
 
-       pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
-       temp &= 0xfff80000;
+static void intel_enable_gtt(void)
+{
+       u32 gma_addr;
+       u16 gmch_ctrl;
 
-       intel_private.registers = ioremap(temp, 128 * 4096);
-       if (!intel_private.registers)
-               return -ENOMEM;
+       if (INTEL_GTT_GEN == 2)
+               pci_read_config_dword(intel_private.pcidev, I810_GMADDR,
+                                     &gma_addr);
+       else
+               pci_read_config_dword(intel_private.pcidev, I915_GMADDR,
+                                     &gma_addr);
 
-       temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-       global_cache_flush();   /* FIXME: ?? */
+       intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
 
-       /* we have to call this as early as possible after the MMIO base address is known */
-       intel_i830_init_gtt_entries();
-       if (intel_private.gtt_entries == 0) {
-               iounmap(intel_private.registers);
+       pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl);
+       gmch_ctrl |= I830_GMCH_ENABLED;
+       pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl);
+
+       writel(intel_private.pte_bus_addr|I810_PGETBL_ENABLED,
+              intel_private.registers+I810_PGETBL_CTL);
+       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+}
+
+static int i830_setup(void)
+{
+       u32 reg_addr;
+
+       pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr);
+       reg_addr &= 0xfff80000;
+
+       intel_private.registers = ioremap(reg_addr, KB(64));
+       if (!intel_private.registers)
                return -ENOMEM;
-       }
 
-       agp_bridge->gatt_table = NULL;
+       intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
+       intel_private.pte_bus_addr =
+               readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
 
-       agp_bridge->gatt_bus_addr = temp;
+       intel_i830_setup_flush();
 
        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)
+static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge)
 {
+       agp_bridge->gatt_table_real = NULL;
+       agp_bridge->gatt_table = NULL;
+       agp_bridge->gatt_bus_addr = 0;
+
        return 0;
 }
 
-static int intel_i830_fetch_size(void)
+static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge)
 {
-       u16 gmch_ctrl;
-       struct aper_size_info_fixed *values;
+       return 0;
+}
 
-       values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
+static int intel_fake_agp_configure(void)
+{
+       int i;
 
-       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;
-       }
+       intel_enable_gtt();
 
-       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+       agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
 
-       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;
+       for (i = intel_private.base.gtt_stolen_entries;
+                       i < intel_private.base.gtt_total_entries; i++) {
+               intel_private.driver->write_entry(intel_private.scratch_page_dma,
+                                                 i, 0);
        }
+       readl(intel_private.gtt+i-1);   /* PCI Posting. */
+
+       global_cache_flush();
 
        return 0;
 }
 
-static int intel_i830_configure(void)
+static bool i830_check_flags(unsigned int flags)
 {
-       struct aper_size_info_fixed *current_size;
-       u32 temp;
-       u16 gmch_ctrl;
-       int i;
-
-       current_size = A_SIZE_FIX(agp_bridge->current_size);
+       switch (flags) {
+       case 0:
+       case AGP_PHYS_MEMORY:
+       case AGP_USER_CACHED_MEMORY:
+       case AGP_USER_MEMORY:
+               return true;
+       }
 
-       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
-       agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+       return false;
+}
 
-       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);
+static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
+                                       unsigned int sg_len,
+                                       unsigned int pg_start,
+                                       unsigned int flags)
+{
+       struct scatterlist *sg;
+       unsigned int len, m;
+       int i, j;
 
-       writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-       readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
+       j = pg_start;
 
-       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));
+       /* sg may merge pages, but we have to separate
+        * per-page addr for GTT */
+       for_each_sg(sg_list, sg, sg_len, i) {
+               len = sg_dma_len(sg) >> PAGE_SHIFT;
+               for (m = 0; m < len; m++) {
+                       dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+                       intel_private.driver->write_entry(addr,
+                                                         j, flags);
+                       j++;
                }
-               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);
+       readl(intel_private.gtt+j-1);
 }
 
-static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
+static int intel_fake_agp_insert_entries(struct agp_memory *mem,
+                                        off_t pg_start, int type)
 {
-       int i, j, num_entries;
-       void *temp;
+       int i, j;
        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) {
+       if (pg_start < intel_private.base.gtt_stolen_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);
+                          "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n",
+                          pg_start, intel_private.base.gtt_stolen_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)
+       if ((pg_start + mem->page_count) > intel_private.base.gtt_total_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)
+       if (!intel_private.driver->check_flags(type))
                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));
+       if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+               ret = intel_agp_map_memory(mem);
+               if (ret != 0)
+                       return ret;
+
+               intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg,
+                                           pg_start, type);
+       } else {
+               for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+                       dma_addr_t addr = page_to_phys(mem->pages[i]);
+                       intel_private.driver->write_entry(addr,
+                                                         j, type);
+               }
+               readl(intel_private.gtt+j-1);
        }
-       readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
 
 out:
        ret = 0;
@@ -982,29 +1042,39 @@ out_err:
        return ret;
 }
 
-static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
+static int intel_fake_agp_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) {
+       if (pg_start < intel_private.base.gtt_stolen_entries) {
                dev_info(&intel_private.pcidev->dev,
                         "trying to disable local/stolen memory\n");
                return -EINVAL;
        }
 
+       if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2)
+               intel_agp_unmap_memory(mem);
+
        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-               writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+               intel_private.driver->write_entry(intel_private.scratch_page_dma,
+                                                 i, 0);
        }
-       readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+       readl(intel_private.gtt+i-1);
 
        return 0;
 }
 
-static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
+static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge)
+{
+       intel_private.driver->chipset_flush();
+}
+
+static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count,
+                                                      int type)
 {
        if (type == AGP_PHYS_MEMORY)
                return alloc_agpphysmem_i8xx(pg_count, type);
@@ -1015,9 +1085,9 @@ static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
 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,
+       ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
                                     PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
-                                    pcibios_align_resource, agp_bridge->dev);
+                                    pcibios_align_resource, intel_private.bridge_dev);
 
        return ret;
 }
@@ -1027,11 +1097,11 @@ static void intel_i915_setup_chipset_flush(void)
        int ret;
        u32 temp;
 
-       pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
+       pci_read_config_dword(intel_private.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);
+               pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
        } else {
                temp &= ~1;
 
@@ -1050,17 +1120,17 @@ 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);
+       pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi);
+       pci_read_config_dword(intel_private.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,
+               pci_write_config_dword(intel_private.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);
+               pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
        } else {
                u64 l64;
 
@@ -1083,7 +1153,7 @@ static void intel_i9xx_setup_flush(void)
        if (intel_private.ifp_resource.start)
                return;
 
-       if (IS_SNB)
+       if (INTEL_GTT_GEN == 6)
                return;
 
        /* setup a resource for this object */
@@ -1091,7 +1161,7 @@ static void intel_i9xx_setup_flush(void)
        intel_private.ifp_resource.flags = IORESOURCE_MEM;
 
        /* Setup chipset flush for 915 */
-       if (IS_I965 || IS_G33 || IS_G4X) {
+       if (IS_G33 || INTEL_GTT_GEN >= 4) {
                intel_i965_g33_setup_chipset_flush();
        } else {
                intel_i915_setup_chipset_flush();
@@ -1104,41 +1174,7 @@ static void intel_i9xx_setup_flush(void)
                        "can't ioremap flush page - no chipset flushing\n");
 }
 
-static int intel_i9xx_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)
+static void i9xx_cleanup(void)
 {
        if (intel_private.i9xx_flush_page)
                iounmap(intel_private.i9xx_flush_page);
@@ -1146,320 +1182,93 @@ static void intel_i915_cleanup(void)
                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)
+static void i9xx_chipset_flush(void)
 {
        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)
+static void i965_write_entry(dma_addr_t addr, unsigned int entry,
+                            unsigned int flags)
 {
-       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 (!IS_SNB && 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;
+       /* Shift high bits down */
+       addr |= (addr >> 28) & 0xf0;
+       writel(addr | I810_PTE_VALID, intel_private.gtt + entry);
 }
 
-static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
-                                    int type)
+static bool gen6_check_flags(unsigned int flags)
 {
-       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 true;
 }
 
-/* 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)
+static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
+                            unsigned int flags)
 {
-       int num_sizes = ARRAY_SIZE(intel_i830_sizes);
-       int aper_size; /* size in megabytes */
-       int i;
+       unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT;
+       unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
+       u32 pte_flags;
 
-       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;
-               }
+       if (type_mask == AGP_USER_UNCACHED_MEMORY)
+               pte_flags = GEN6_PTE_UNCACHED;
+       else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
+               pte_flags = GEN6_PTE_LLC;
+               if (gfdt)
+                       pte_flags |= GEN6_PTE_GFDT;
+       } else { /* set 'normal'/'cached' to LLC by default */
+               pte_flags = GEN6_PTE_LLC_MLC;
+               if (gfdt)
+                       pte_flags |= GEN6_PTE_GFDT;
        }
 
-       return 0;
+       /* gen6 has bit11-4 for physical addr bit39-32 */
+       addr |= (addr >> 28) & 0xff0;
+       writel(addr | pte_flags, intel_private.gtt + entry);
 }
 
-static int intel_i915_get_gtt_size(void)
+static void gen6_cleanup(void)
 {
-       int size;
-
-       if (IS_G33) {
-               u16 gmch_ctrl;
-
-               /* G33's GTT size defined in gmch_ctrl */
-               pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-               switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
-               case I830_GMCH_GMS_STOLEN_512:
-                       size = 512;
-                       break;
-               case I830_GMCH_GMS_STOLEN_1024:
-                       size = 1024;
-                       break;
-               case I830_GMCH_GMS_STOLEN_8192:
-                       size = 8*1024;
-                       break;
-               default:
-                       dev_info(&agp_bridge->dev->dev,
-                                "unknown page table size 0x%x, assuming 512KB\n",
-                               (gmch_ctrl & I830_GMCH_GMS_MASK));
-                       size = 512;
-               }
-       } else {
-               /* On previous hardware, the GTT size was just what was
-                * required to map the aperture.
-                */
-               size = agp_bridge->driver->fetch_size();
-       }
-
-       return KB(size);
 }
 
-/* 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)
+static int i9xx_setup(void)
 {
-       int page_order;
-       struct aper_size_info_fixed *size;
-       int num_entries;
-       u32 temp, temp2;
-       int gtt_map_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);
-       pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
+       u32 reg_addr;
 
-       gtt_map_size = intel_i915_get_gtt_size();
+       pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &reg_addr);
 
-       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;
-       }
+       reg_addr &= 0xfff80000;
 
-       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();
-       if (intel_private.gtt_entries == 0) {
-               iounmap(intel_private.gtt);
-               iounmap(intel_private.registers);
+       intel_private.registers = ioremap(reg_addr, 128 * 4096);
+       if (!intel_private.registers)
                return -ENOMEM;
-       }
-
-       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;
-}
+       if (INTEL_GTT_GEN == 3) {
+               u32 gtt_addr;
 
-static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge,
-                                           dma_addr_t addr, int type)
-{
-       /* gen6 has bit11-4 for physical addr bit39-32 */
-       addr |= (addr >> 28) & 0xff0;
-
-       /* 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:
-       case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB:
-               *gtt_offset = MB(2);
+               pci_read_config_dword(intel_private.pcidev,
+                                     I915_PTEADDR, &gtt_addr);
+               intel_private.gtt_bus_addr = gtt_addr;
+       } else {
+               u32 gtt_offset;
 
-               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);
+               switch (INTEL_GTT_GEN) {
+               case 5:
+               case 6:
+                       gtt_offset = MB(2);
                        break;
-               case SNB_GTT_SIZE_1M:
-                       *gtt_size = MB(1);
-                       break;
-               case SNB_GTT_SIZE_2M:
-                       *gtt_size = MB(2);
+               case 4:
+               default:
+                       gtt_offset =  KB(512);
                        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();
-       if (intel_private.gtt_entries == 0) {
-               iounmap(intel_private.gtt);
-               iounmap(intel_private.registers);
-               return -ENOMEM;
+               intel_private.gtt_bus_addr = reg_addr + gtt_offset;
        }
 
-       agp_bridge->gatt_table = NULL;
+       intel_private.pte_bus_addr =
+               readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
 
-       agp_bridge->gatt_bus_addr = temp;
+       intel_i9xx_setup_flush();
 
        return 0;
 }
@@ -1475,7 +1284,7 @@ static const struct agp_bridge_driver intel_810_driver = {
        .cleanup                = intel_i810_cleanup,
        .mask_memory            = intel_i810_mask_memory,
        .masks                  = intel_i810_masks,
-       .agp_enable             = intel_i810_agp_enable,
+       .agp_enable             = intel_fake_agp_enable,
        .cache_flush            = global_cache_flush,
        .create_gatt_table      = agp_generic_create_gatt_table,
        .free_gatt_table        = agp_generic_free_gatt_table,
@@ -1490,161 +1299,282 @@ static const struct agp_bridge_driver intel_810_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_830_driver = {
+static const struct agp_bridge_driver intel_fake_agp_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,
+       .aperture_sizes         = intel_fake_agp_sizes,
+       .num_aperture_sizes     = ARRAY_SIZE(intel_fake_agp_sizes),
+       .configure              = intel_fake_agp_configure,
+       .fetch_size             = intel_fake_agp_fetch_size,
+       .cleanup                = intel_gtt_cleanup,
+       .agp_enable             = intel_fake_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,
+       .create_gatt_table      = intel_fake_agp_create_gatt_table,
+       .free_gatt_table        = intel_fake_agp_free_gatt_table,
+       .insert_memory          = intel_fake_agp_insert_entries,
+       .remove_memory          = intel_fake_agp_remove_entries,
+       .alloc_by_type          = intel_fake_agp_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,
+       .chipset_flush          = intel_fake_agp_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_i9xx_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 intel_gtt_driver i81x_gtt_driver = {
+       .gen = 1,
+       .dma_mask_size = 32,
 };
-
-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_i9xx_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 intel_gtt_driver i8xx_gtt_driver = {
+       .gen = 2,
+       .setup = i830_setup,
+       .cleanup = i830_cleanup,
+       .write_entry = i830_write_entry,
+       .dma_mask_size = 32,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i830_chipset_flush,
 };
-
-static const struct agp_bridge_driver intel_gen6_driver = {
-       .owner                  = THIS_MODULE,
-       .aperture_sizes         = intel_i830_sizes,
-       .size_type              = FIXED_APER_SIZE,
-       .num_aperture_sizes     = 4,
-       .needs_scratch_page     = true,
-       .configure              = intel_i9xx_configure,
-       .fetch_size             = intel_i9xx_fetch_size,
-       .cleanup                = intel_i915_cleanup,
-       .mask_memory            = intel_gen6_mask_memory,
-       .masks                  = intel_gen6_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_gen6_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 intel_gtt_driver i915_gtt_driver = {
+       .gen = 3,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       /* i945 is the last gpu to need phys mem (for overlay and cursors). */
+       .write_entry = i830_write_entry, 
+       .dma_mask_size = 32,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver g33_gtt_driver = {
+       .gen = 3,
+       .is_g33 = 1,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       .write_entry = i965_write_entry,
+       .dma_mask_size = 36,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver pineview_gtt_driver = {
+       .gen = 3,
+       .is_pineview = 1, .is_g33 = 1,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       .write_entry = i965_write_entry,
+       .dma_mask_size = 36,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver i965_gtt_driver = {
+       .gen = 4,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       .write_entry = i965_write_entry,
+       .dma_mask_size = 36,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver g4x_gtt_driver = {
+       .gen = 5,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       .write_entry = i965_write_entry,
+       .dma_mask_size = 36,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver ironlake_gtt_driver = {
+       .gen = 5,
+       .is_ironlake = 1,
+       .setup = i9xx_setup,
+       .cleanup = i9xx_cleanup,
+       .write_entry = i965_write_entry,
+       .dma_mask_size = 36,
+       .check_flags = i830_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver sandybridge_gtt_driver = {
+       .gen = 6,
+       .setup = i9xx_setup,
+       .cleanup = gen6_cleanup,
+       .write_entry = gen6_write_entry,
+       .dma_mask_size = 40,
+       .check_flags = gen6_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
 };
 
-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_i9xx_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
+/* Table to describe Intel GMCH and AGP/PCIE GART drivers.  At least one of
+ * driver and gmch_driver must be non-null, and find_gmch will determine
+ * which one should be used if a gmch_chip_id is present.
+ */
+static const struct intel_gtt_driver_description {
+       unsigned int gmch_chip_id;
+       char *name;
+       const struct agp_bridge_driver *gmch_driver;
+       const struct intel_gtt_driver *gtt_driver;
+} intel_gtt_chipsets[] = {
+       { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver,
+               &i81x_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver,
+               &i81x_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver,
+               &i81x_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver,
+               &i81x_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
+               &intel_fake_agp_driver, &i8xx_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
+               &intel_fake_agp_driver, &i8xx_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82854_IG, "854",
+               &intel_fake_agp_driver, &i8xx_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
+               &intel_fake_agp_driver, &i8xx_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_82865_IG, "865",
+               &intel_fake_agp_driver, &i8xx_gtt_driver},
+       { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
+               &intel_fake_agp_driver, &i915_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
+               &intel_fake_agp_driver, &i965_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_G33_IG, "G33",
+               &intel_fake_agp_driver, &g33_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
+               &intel_fake_agp_driver, &g33_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
+               &intel_fake_agp_driver, &g33_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
+               &intel_fake_agp_driver, &pineview_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
+               &intel_fake_agp_driver, &pineview_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_B43_IG, "B43",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_G41_IG, "G41",
+               &intel_fake_agp_driver, &g4x_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
+           "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
+           "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
+           "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+       { 0, NULL, NULL }
 };
+
+static int find_gmch(u16 device)
+{
+       struct pci_dev *gmch_device;
+
+       gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
+       if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
+               gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                            device, gmch_device);
+       }
+
+       if (!gmch_device)
+               return 0;
+
+       intel_private.pcidev = gmch_device;
+       return 1;
+}
+
+int intel_gmch_probe(struct pci_dev *pdev,
+                                     struct agp_bridge_data *bridge)
+{
+       int i, mask;
+       bridge->driver = NULL;
+
+       for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) {
+               if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) {
+                       bridge->driver =
+                               intel_gtt_chipsets[i].gmch_driver;
+                       intel_private.driver = 
+                               intel_gtt_chipsets[i].gtt_driver;
+                       break;
+               }
+       }
+
+       if (!bridge->driver)
+               return 0;
+
+       bridge->dev_private_data = &intel_private;
+       bridge->dev = pdev;
+
+       intel_private.bridge_dev = pci_dev_get(pdev);
+
+       dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name);
+
+       mask = intel_private.driver->dma_mask_size;
+       if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
+               dev_err(&intel_private.pcidev->dev,
+                       "set gfx device dma mask %d-bit failed!\n", mask);
+       else
+               pci_set_consistent_dma_mask(intel_private.pcidev,
+                                           DMA_BIT_MASK(mask));
+
+       if (bridge->driver == &intel_810_driver)
+               return 1;
+
+       if (intel_gtt_init() != 0)
+               return 0;
+
+       return 1;
+}
+EXPORT_SYMBOL(intel_gmch_probe);
+
+struct intel_gtt *intel_gtt_get(void)
+{
+       return &intel_private.base;
+}
+EXPORT_SYMBOL(intel_gtt_get);
+
+void intel_gmch_remove(struct pci_dev *pdev)
+{
+       if (intel_private.pcidev)
+               pci_dev_put(intel_private.pcidev);
+       if (intel_private.bridge_dev)
+               pci_dev_put(intel_private.bridge_dev);
+}
+EXPORT_SYMBOL(intel_gmch_remove);
+
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_LICENSE("GPL and additional rights");
index 55d03ed050006c3de3a2b7470c4ededeafbc8871..529a0dbe9fc65960e62bc7840320754fb61393e8 100644 (file)
@@ -98,8 +98,8 @@ EXPORT_SYMBOL(drm_buffer_alloc);
  *   user_data: A pointer the data that is copied to the buffer.
  *   size: The Number of bytes to copy.
  */
-extern int drm_buffer_copy_from_user(struct drm_buffer *buf,
-               void __user *user_data, int size)
+int drm_buffer_copy_from_user(struct drm_buffer *buf,
+                             void __user *user_data, int size)
 {
        int nr_pages = size / PAGE_SIZE + 1;
        int idx;
@@ -163,7 +163,7 @@ void *drm_buffer_read_object(struct drm_buffer *buf,
 {
        int idx = drm_buffer_index(buf);
        int page = drm_buffer_page(buf);
-       void *obj = 0;
+       void *obj = NULL;
 
        if (idx + objsize <= PAGE_SIZE) {
                obj = &buf->data[page][idx];
index 37e0b4fa482a810afc9eded6fda136a90bcc5cc0..6985cb1da72cbc232919ab2bb93a52f26304a345 100644 (file)
@@ -1854,7 +1854,8 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
        }
 
        if (fb->funcs->dirty) {
-               ret = fb->funcs->dirty(fb, flags, r->color, clips, num_clips);
+               ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
+                                      clips, num_clips);
        } else {
                ret = -ENOSYS;
                goto out_err2;
index 677b275fa721affe2fec2508e780c1b1970f4f73..9d8c892d07c93b1d4e855adc839e28bea5959aab 100644 (file)
@@ -48,7 +48,6 @@ static struct drm_info_list drm_debugfs_list[] = {
        {"queues", drm_queues_info, 0},
        {"bufs", drm_bufs_info, 0},
        {"gem_names", drm_gem_name_info, DRIVER_GEM},
-       {"gem_objects", drm_gem_object_info, DRIVER_GEM},
 #if DRM_DEBUG_CODE
        {"vma", drm_vma_info, 0},
 #endif
index 96e96310822513bfd9c984054a913eac7b5acc50..fd033ebbdf84c1f731b1935a6e3fbad352a24a0b 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
 #include "drmP.h"
 #include "drm_edid.h"
 #include "drm_edid_modes.h"
index cff7317d3830e5f8df8c58ef7c8e61cc37301ccc..ea1c4b019ebf96290c0768202d7277cda47ba0f9 100644 (file)
@@ -92,12 +92,6 @@ drm_gem_init(struct drm_device *dev)
 
        spin_lock_init(&dev->object_name_lock);
        idr_init(&dev->object_name_idr);
-       atomic_set(&dev->object_count, 0);
-       atomic_set(&dev->object_memory, 0);
-       atomic_set(&dev->pin_count, 0);
-       atomic_set(&dev->pin_memory, 0);
-       atomic_set(&dev->gtt_count, 0);
-       atomic_set(&dev->gtt_memory, 0);
 
        mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL);
        if (!mm) {
@@ -148,12 +142,9 @@ int drm_gem_object_init(struct drm_device *dev,
                return -ENOMEM;
 
        kref_init(&obj->refcount);
-       kref_init(&obj->handlecount);
+       atomic_set(&obj->handle_count, 0);
        obj->size = size;
 
-       atomic_inc(&dev->object_count);
-       atomic_add(obj->size, &dev->object_memory);
-
        return 0;
 }
 EXPORT_SYMBOL(drm_gem_object_init);
@@ -180,8 +171,6 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
        return obj;
 fput:
        /* Object_init mangles the global counters - readjust them. */
-       atomic_dec(&dev->object_count);
-       atomic_sub(obj->size, &dev->object_memory);
        fput(obj->filp);
 free:
        kfree(obj);
@@ -436,10 +425,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
 void
 drm_gem_object_release(struct drm_gem_object *obj)
 {
-       struct drm_device *dev = obj->dev;
        fput(obj->filp);
-       atomic_dec(&dev->object_count);
-       atomic_sub(obj->size, &dev->object_memory);
 }
 EXPORT_SYMBOL(drm_gem_object_release);
 
@@ -462,26 +448,6 @@ drm_gem_object_free(struct kref *kref)
 }
 EXPORT_SYMBOL(drm_gem_object_free);
 
-/**
- * Called after the last reference to the object has been lost.
- * Must be called without holding struct_mutex
- *
- * Frees the object
- */
-void
-drm_gem_object_free_unlocked(struct kref *kref)
-{
-       struct drm_gem_object *obj = (struct drm_gem_object *) kref;
-       struct drm_device *dev = obj->dev;
-
-       if (dev->driver->gem_free_object != NULL) {
-               mutex_lock(&dev->struct_mutex);
-               dev->driver->gem_free_object(obj);
-               mutex_unlock(&dev->struct_mutex);
-       }
-}
-EXPORT_SYMBOL(drm_gem_object_free_unlocked);
-
 static void drm_gem_object_ref_bug(struct kref *list_kref)
 {
        BUG();
@@ -494,12 +460,8 @@ static void drm_gem_object_ref_bug(struct kref *list_kref)
  * called before drm_gem_object_free or we'll be touching
  * freed memory
  */
-void
-drm_gem_object_handle_free(struct kref *kref)
+void drm_gem_object_handle_free(struct drm_gem_object *obj)
 {
-       struct drm_gem_object *obj = container_of(kref,
-                                                 struct drm_gem_object,
-                                                 handlecount);
        struct drm_device *dev = obj->dev;
 
        /* Remove any name for this object */
@@ -526,6 +488,10 @@ void drm_gem_vm_open(struct vm_area_struct *vma)
        struct drm_gem_object *obj = vma->vm_private_data;
 
        drm_gem_object_reference(obj);
+
+       mutex_lock(&obj->dev->struct_mutex);
+       drm_vm_open_locked(vma);
+       mutex_unlock(&obj->dev->struct_mutex);
 }
 EXPORT_SYMBOL(drm_gem_vm_open);
 
@@ -533,7 +499,10 @@ void drm_gem_vm_close(struct vm_area_struct *vma)
 {
        struct drm_gem_object *obj = vma->vm_private_data;
 
-       drm_gem_object_unreference_unlocked(obj);
+       mutex_lock(&obj->dev->struct_mutex);
+       drm_vm_close_locked(vma);
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&obj->dev->struct_mutex);
 }
 EXPORT_SYMBOL(drm_gem_vm_close);
 
index 2ef2c78272434dcb6b32dc17fd96e34dd7a8d959..3cdbaf379bb51324110d5d0ace0c9dc2dd24059e 100644 (file)
@@ -255,7 +255,7 @@ int drm_gem_one_name_info(int id, void *ptr, void *data)
 
        seq_printf(m, "%6d %8zd %7d %8d\n",
                   obj->name, obj->size,
-                  atomic_read(&obj->handlecount.refcount),
+                  atomic_read(&obj->handle_count),
                   atomic_read(&obj->refcount.refcount));
        return 0;
 }
@@ -270,20 +270,6 @@ int drm_gem_name_info(struct seq_file *m, void *data)
        return 0;
 }
 
-int drm_gem_object_info(struct seq_file *m, void* data)
-{
-       struct drm_info_node *node = (struct drm_info_node *) m->private;
-       struct drm_device *dev = node->minor->dev;
-
-       seq_printf(m, "%d objects\n", atomic_read(&dev->object_count));
-       seq_printf(m, "%d object bytes\n", atomic_read(&dev->object_memory));
-       seq_printf(m, "%d pinned\n", atomic_read(&dev->pin_count));
-       seq_printf(m, "%d pin bytes\n", atomic_read(&dev->pin_memory));
-       seq_printf(m, "%d gtt bytes\n", atomic_read(&dev->gtt_memory));
-       seq_printf(m, "%d gtt total\n", dev->gtt_total);
-       return 0;
-}
-
 #if DRM_DEBUG_CODE
 
 int drm_vma_info(struct seq_file *m, void *data)
index 1e28b9072068e5ff06d456b9a8defd9c893efe0d..632ae243ede0b9f1df4b42f2e96b30479be4e05a 100644 (file)
@@ -152,6 +152,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_lock *lock = data;
+       struct drm_master *master = file_priv->master;
 
        if (lock->context == DRM_KERNEL_CONTEXT) {
                DRM_ERROR("Process %d using kernel context %d\n",
@@ -161,6 +162,10 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
        atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
 
+       if (drm_lock_free(&master->lock, lock->context)) {
+               /* FIXME: Should really bail out here. */
+       }
+
        unblock_all_signals();
        return 0;
 }
index e571de536dc5d6f5ecb8749cd6efdb0afc8e23cd..9e5b07efebb72172ef97894ec2fa42a7548bd896 100644 (file)
@@ -55,7 +55,6 @@ static struct drm_info_list drm_proc_list[] = {
        {"queues", drm_queues_info, 0},
        {"bufs", drm_bufs_info, 0},
        {"gem_names", drm_gem_name_info, DRIVER_GEM},
-       {"gem_objects", drm_gem_object_info, DRIVER_GEM},
 #if DRM_DEBUG_CODE
        {"vma", drm_vma_info, 0},
 #endif
index ee879d6bb5225b5c7eeab06d4c6ece819b5f414a..2c3fcbdfd8ff64f8c5a53ff35884f59ce51bd621 100644 (file)
@@ -433,15 +433,7 @@ static void drm_vm_open(struct vm_area_struct *vma)
        mutex_unlock(&dev->struct_mutex);
 }
 
-/**
- * \c close method for all virtual memory types.
- *
- * \param vma virtual memory area.
- *
- * Search the \p vma private data entry in drm_device::vmalist, unlink it, and
- * free it.
- */
-static void drm_vm_close(struct vm_area_struct *vma)
+void drm_vm_close_locked(struct vm_area_struct *vma)
 {
        struct drm_file *priv = vma->vm_file->private_data;
        struct drm_device *dev = priv->minor->dev;
@@ -451,7 +443,6 @@ static void drm_vm_close(struct vm_area_struct *vma)
                  vma->vm_start, vma->vm_end - vma->vm_start);
        atomic_dec(&dev->vma_count);
 
-       mutex_lock(&dev->struct_mutex);
        list_for_each_entry_safe(pt, temp, &dev->vmalist, head) {
                if (pt->vma == vma) {
                        list_del(&pt->head);
@@ -459,6 +450,23 @@ static void drm_vm_close(struct vm_area_struct *vma)
                        break;
                }
        }
+}
+
+/**
+ * \c close method for all virtual memory types.
+ *
+ * \param vma virtual memory area.
+ *
+ * Search the \p vma private data entry in drm_device::vmalist, unlink it, and
+ * free it.
+ */
+static void drm_vm_close(struct vm_area_struct *vma)
+{
+       struct drm_file *priv = vma->vm_file->private_data;
+       struct drm_device *dev = priv->minor->dev;
+
+       mutex_lock(&dev->struct_mutex);
+       drm_vm_close_locked(vma);
        mutex_unlock(&dev->struct_mutex);
 }
 
index 61b4caf220fa83bd15815ea0f82b627f2d773727..fb07e73581e84467ab59ebe744e21ff6f712d2ce 100644 (file)
@@ -116,7 +116,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
 static const struct file_operations i810_buffer_fops = {
        .open = drm_open,
        .release = drm_release,
-       .unlocked_ioctl = drm_ioctl,
+       .unlocked_ioctl = i810_ioctl,
        .mmap = i810_mmap_buffers,
        .fasync = drm_fasync,
 };
index 671aa18415ac52d17164e79b4c2a9f287b02da0d..cc92c7e6236fbdffb86078290b5b93dffad2cbad 100644 (file)
@@ -118,7 +118,7 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
 static const struct file_operations i830_buffer_fops = {
        .open = drm_open,
        .release = drm_release,
-       .unlocked_ioctl = drm_ioctl,
+       .unlocked_ioctl = i830_ioctl,
        .mmap = i830_mmap_buffers,
        .fasync = drm_fasync,
 };
index 5c8e53458edbfee1c37e54b7b982d49e747d563e..f6e98dd416c9085d662042fd14655b66f03c4880 100644 (file)
@@ -26,13 +26,13 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
          intel_dvo.o \
          intel_ringbuffer.o \
          intel_overlay.o \
+         intel_opregion.o \
          dvo_ch7xxx.o \
          dvo_ch7017.o \
          dvo_ivch.o \
          dvo_tfp410.o \
          dvo_sil164.o
 
-i915-$(CONFIG_ACPI)    += i915_opregion.o
 i915-$(CONFIG_COMPAT)   += i915_ioc32.o
 
 obj-$(CONFIG_DRM_I915)  += i915.o
index 14d59804acd77b00637ee68c0662a1183cdbca87..af70337567ce35a0167ffb193d8b1ffae769fedd 100644 (file)
@@ -165,67 +165,44 @@ struct ch7017_priv {
 static void ch7017_dump_regs(struct intel_dvo_device *dvo);
 static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
 
-static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
+static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val)
 {
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
-       u8 out_buf[2];
-       u8 in_buf[2];
-
        struct i2c_msg msgs[] = {
                {
                        .addr = dvo->slave_addr,
                        .flags = 0,
                        .len = 1,
-                       .buf = out_buf,
+                       .buf = &addr,
                },
                {
                        .addr = dvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
-                       .buf = in_buf,
+                       .buf = val,
                }
        };
-
-       out_buf[0] = addr;
-       out_buf[1] = 0;
-
-       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
-               *val= in_buf[0];
-               return true;
-       };
-
-       return false;
+       return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2;
 }
 
-static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
+static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val)
 {
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
-       uint8_t out_buf[2];
+       uint8_t buf[2] = { addr, val };
        struct i2c_msg msg = {
                .addr = dvo->slave_addr,
                .flags = 0,
                .len = 2,
-               .buf = out_buf,
+               .buf = buf,
        };
-
-       out_buf[0] = addr;
-       out_buf[1] = val;
-
-       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
-               return true;
-
-       return false;
+       return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1;
 }
 
 /** Probes for a CH7017 on the given bus and slave address. */
 static bool ch7017_init(struct intel_dvo_device *dvo,
                        struct i2c_adapter *adapter)
 {
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        struct ch7017_priv *priv;
-       uint8_t val;
+       const char *str;
+       u8 val;
 
        priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
        if (priv == NULL)
@@ -237,16 +214,27 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
        if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
                goto fail;
 
-       if (val != CH7017_DEVICE_ID_VALUE &&
-           val != CH7018_DEVICE_ID_VALUE &&
-           val != CH7019_DEVICE_ID_VALUE) {
+       switch (val) {
+       case CH7017_DEVICE_ID_VALUE:
+               str = "ch7017";
+               break;
+       case CH7018_DEVICE_ID_VALUE:
+               str = "ch7018";
+               break;
+       case CH7019_DEVICE_ID_VALUE:
+               str = "ch7019";
+               break;
+       default:
                DRM_DEBUG_KMS("ch701x not detected, got %d: from %s "
-                               "Slave %d.\n",
-                         val, i2cbus->adapter.name,dvo->slave_addr);
+                             "slave %d.\n",
+                             val, adapter->name,dvo->slave_addr);
                goto fail;
        }
 
+       DRM_DEBUG_KMS("%s detected on %s, addr %d\n",
+                     str, adapter->name, dvo->slave_addr);
        return true;
+
 fail:
        kfree(priv);
        return false;
@@ -368,7 +356,7 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode)
        }
 
        /* XXX: Should actually wait for update power status somehow */
-       udelay(20000);
+       msleep(20);
 }
 
 static void ch7017_dump_regs(struct intel_dvo_device *dvo)
index 6f1944b244416c03475e8883a94a4c358fe8d881..7eaa94e4ff061b5450c9d769f70f02fb6459db2a 100644 (file)
@@ -113,7 +113,6 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
@@ -135,14 +134,14 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
        out_buf[0] = addr;
        out_buf[1] = 0;
 
-       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+       if (i2c_transfer(adapter, msgs, 2) == 2) {
                *ch = in_buf[0];
                return true;
        };
 
        if (!ch7xxx->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
        return false;
 }
@@ -152,7 +151,6 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
                .addr = dvo->slave_addr,
@@ -164,12 +162,12 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
        out_buf[0] = addr;
        out_buf[1] = ch;
 
-       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+       if (i2c_transfer(adapter, &msg, 1) == 1)
                return true;
 
        if (!ch7xxx->quiet) {
                DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
 
        return false;
index a2ec3f4872023fbe3510ce0bc54c673c5e4ec56b..a12ed9414cc7358e462dfa78766fe6f16948eacd 100644 (file)
@@ -167,7 +167,6 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 {
        struct ivch_priv *priv = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[1];
        u8 in_buf[2];
 
@@ -193,7 +192,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 
        out_buf[0] = addr;
 
-       if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) {
+       if (i2c_transfer(adapter, msgs, 3) == 3) {
                *data = (in_buf[1] << 8) | in_buf[0];
                return true;
        };
@@ -201,7 +200,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
        if (!priv->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from "
                                "%s:%02x.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
        return false;
 }
@@ -211,7 +210,6 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 {
        struct ivch_priv *priv = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[3];
        struct i2c_msg msg = {
                .addr = dvo->slave_addr,
@@ -224,12 +222,12 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
        out_buf[1] = data & 0xff;
        out_buf[2] = data >> 8;
 
-       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+       if (i2c_transfer(adapter, &msg, 1) == 1)
                return true;
 
        if (!priv->quiet) {
                DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
 
        return false;
index 9b8e6765cf260fa8f91f2fa1a9f4432fce2b0287..e4b4091df942faf1196e4c32c057dff77e4a467e 100644 (file)
@@ -69,7 +69,6 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct sil164_priv *sil = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
@@ -91,14 +90,14 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
        out_buf[0] = addr;
        out_buf[1] = 0;
 
-       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+       if (i2c_transfer(adapter, msgs, 2) == 2) {
                *ch = in_buf[0];
                return true;
        };
 
        if (!sil->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
        return false;
 }
@@ -107,7 +106,6 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct sil164_priv *sil= dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
                .addr = dvo->slave_addr,
@@ -119,12 +117,12 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
        out_buf[0] = addr;
        out_buf[1] = ch;
 
-       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+       if (i2c_transfer(adapter, &msg, 1) == 1)
                return true;
 
        if (!sil->quiet) {
                DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
 
        return false;
index 56f66426207f0a1a293dcb073360985d328fd85e..8ab2855bb544ae88851e4d90ce107382165e5442 100644 (file)
@@ -94,7 +94,6 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
 {
        struct tfp410_priv *tfp = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        u8 out_buf[2];
        u8 in_buf[2];
 
@@ -116,14 +115,14 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
        out_buf[0] = addr;
        out_buf[1] = 0;
 
-       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+       if (i2c_transfer(adapter, msgs, 2) == 2) {
                *ch = in_buf[0];
                return true;
        };
 
        if (!tfp->quiet) {
                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
        return false;
 }
@@ -132,7 +131,6 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
 {
        struct tfp410_priv *tfp = dvo->dev_priv;
        struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
        uint8_t out_buf[2];
        struct i2c_msg msg = {
                .addr = dvo->slave_addr,
@@ -144,12 +142,12 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
        out_buf[0] = addr;
        out_buf[1] = ch;
 
-       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+       if (i2c_transfer(adapter, &msg, 1) == 1)
                return true;
 
        if (!tfp->quiet) {
                DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-                         addr, i2cbus->adapter.name, dvo->slave_addr);
+                         addr, adapter->name, dvo->slave_addr);
        }
 
        return false;
index 5e43d70767896e80400c96c628f2960270e1f2c4..d598070fb2794419ec099e38e7196271818c7c45 100644 (file)
 
 #if defined(CONFIG_DEBUG_FS)
 
-#define ACTIVE_LIST    1
-#define FLUSHING_LIST  2
-#define INACTIVE_LIST  3
+enum {
+       RENDER_LIST,
+       BSD_LIST,
+       FLUSHING_LIST,
+       INACTIVE_LIST,
+       PINNED_LIST,
+       DEFERRED_FREE_LIST,
+};
+
+static const char *yesno(int v)
+{
+       return v ? "yes" : "no";
+}
+
+static int i915_capabilities(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       const struct intel_device_info *info = INTEL_INFO(dev);
+
+       seq_printf(m, "gen: %d\n", info->gen);
+#define B(x) seq_printf(m, #x ": %s\n", yesno(info->x))
+       B(is_mobile);
+       B(is_i85x);
+       B(is_i915g);
+       B(is_i945gm);
+       B(is_g33);
+       B(need_gfx_hws);
+       B(is_g4x);
+       B(is_pineview);
+       B(is_broadwater);
+       B(is_crestline);
+       B(is_ironlake);
+       B(has_fbc);
+       B(has_rc6);
+       B(has_pipe_cxsr);
+       B(has_hotplug);
+       B(cursor_needs_physical);
+       B(has_overlay);
+       B(overlay_needs_physical);
+       B(supports_tv);
+#undef B
+
+       return 0;
+}
 
 static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv)
 {
@@ -64,6 +106,27 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj_priv)
     }
 }
 
+static void
+describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
+{
+       seq_printf(m, "%p: %s%s %8zd %08x %08x %d%s%s",
+                  &obj->base,
+                  get_pin_flag(obj),
+                  get_tiling_flag(obj),
+                  obj->base.size,
+                  obj->base.read_domains,
+                  obj->base.write_domain,
+                  obj->last_rendering_seqno,
+                  obj->dirty ? " dirty" : "",
+                  obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
+       if (obj->base.name)
+               seq_printf(m, " (name: %d)", obj->base.name);
+       if (obj->fence_reg != I915_FENCE_REG_NONE)
+               seq_printf(m, " (fence: %d)", obj->fence_reg);
+       if (obj->gtt_space != NULL)
+               seq_printf(m, " (gtt_offset: %08x)", obj->gtt_offset);
+}
+
 static int i915_gem_object_list_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -72,56 +135,84 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv;
-       spinlock_t *lock = NULL;
+       size_t total_obj_size, total_gtt_size;
+       int count, ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        switch (list) {
-       case ACTIVE_LIST:
-               seq_printf(m, "Active:\n");
-               lock = &dev_priv->mm.active_list_lock;
+       case RENDER_LIST:
+               seq_printf(m, "Render:\n");
                head = &dev_priv->render_ring.active_list;
                break;
+       case BSD_LIST:
+               seq_printf(m, "BSD:\n");
+               head = &dev_priv->bsd_ring.active_list;
+               break;
        case INACTIVE_LIST:
                seq_printf(m, "Inactive:\n");
                head = &dev_priv->mm.inactive_list;
                break;
+       case PINNED_LIST:
+               seq_printf(m, "Pinned:\n");
+               head = &dev_priv->mm.pinned_list;
+               break;
        case FLUSHING_LIST:
                seq_printf(m, "Flushing:\n");
                head = &dev_priv->mm.flushing_list;
                break;
+       case DEFERRED_FREE_LIST:
+               seq_printf(m, "Deferred free:\n");
+               head = &dev_priv->mm.deferred_free_list;
+               break;
        default:
-               DRM_INFO("Ooops, unexpected list\n");
-               return 0;
+               mutex_unlock(&dev->struct_mutex);
+               return -EINVAL;
        }
 
-       if (lock)
-               spin_lock(lock);
-       list_for_each_entry(obj_priv, head, list)
-       {
-               seq_printf(m, "    %p: %s %8zd %08x %08x %d%s%s",
-                          &obj_priv->base,
-                          get_pin_flag(obj_priv),
-                          obj_priv->base.size,
-                          obj_priv->base.read_domains,
-                          obj_priv->base.write_domain,
-                          obj_priv->last_rendering_seqno,
-                          obj_priv->dirty ? " dirty" : "",
-                          obj_priv->madv == I915_MADV_DONTNEED ? " purgeable" : "");
-
-               if (obj_priv->base.name)
-                       seq_printf(m, " (name: %d)", obj_priv->base.name);
-               if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
-                       seq_printf(m, " (fence: %d)", obj_priv->fence_reg);
-               if (obj_priv->gtt_space != NULL)
-                       seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset);
-
+       total_obj_size = total_gtt_size = count = 0;
+       list_for_each_entry(obj_priv, head, list) {
+               seq_printf(m, "   ");
+               describe_obj(m, obj_priv);
                seq_printf(m, "\n");
+               total_obj_size += obj_priv->base.size;
+               total_gtt_size += obj_priv->gtt_space->size;
+               count++;
        }
+       mutex_unlock(&dev->struct_mutex);
 
-       if (lock)
-           spin_unlock(lock);
+       seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n",
+                  count, total_obj_size, total_gtt_size);
        return 0;
 }
 
+static int i915_gem_object_info(struct seq_file *m, void* data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       seq_printf(m, "%u objects\n", dev_priv->mm.object_count);
+       seq_printf(m, "%zu object bytes\n", dev_priv->mm.object_memory);
+       seq_printf(m, "%u pinned\n", dev_priv->mm.pin_count);
+       seq_printf(m, "%zu pin bytes\n", dev_priv->mm.pin_memory);
+       seq_printf(m, "%u objects in gtt\n", dev_priv->mm.gtt_count);
+       seq_printf(m, "%zu gtt bytes\n", dev_priv->mm.gtt_memory);
+       seq_printf(m, "%zu gtt total\n", dev_priv->mm.gtt_total);
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+
 static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -176,6 +267,11 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_request *gem_request;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        seq_printf(m, "Request:\n");
        list_for_each_entry(gem_request, &dev_priv->render_ring.request_list,
@@ -184,6 +280,8 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
                           gem_request->seqno,
                           (int) (jiffies - gem_request->emitted_jiffies));
        }
+       mutex_unlock(&dev->struct_mutex);
+
        return 0;
 }
 
@@ -192,16 +290,24 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        if (dev_priv->render_ring.status_page.page_addr != NULL) {
                seq_printf(m, "Current sequence: %d\n",
-                          i915_get_gem_seqno(dev,  &dev_priv->render_ring));
+                          dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
        } else {
                seq_printf(m, "Current sequence: hws uninitialized\n");
        }
        seq_printf(m, "Waiter sequence:  %d\n",
                        dev_priv->mm.waiting_gem_seqno);
        seq_printf(m, "IRQ sequence:     %d\n", dev_priv->mm.irq_gem_seqno);
+
+       mutex_unlock(&dev->struct_mutex);
+
        return 0;
 }
 
@@ -211,6 +317,11 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        if (!HAS_PCH_SPLIT(dev)) {
                seq_printf(m, "Interrupt enable:    %08x\n",
@@ -247,7 +358,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                   atomic_read(&dev_priv->irq_received));
        if (dev_priv->render_ring.status_page.page_addr != NULL) {
                seq_printf(m, "Current sequence:    %d\n",
-                          i915_get_gem_seqno(dev,  &dev_priv->render_ring));
+                          dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
        } else {
                seq_printf(m, "Current sequence:    hws uninitialized\n");
        }
@@ -255,6 +366,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                   dev_priv->mm.waiting_gem_seqno);
        seq_printf(m, "IRQ sequence:        %d\n",
                   dev_priv->mm.irq_gem_seqno);
+       mutex_unlock(&dev->struct_mutex);
+
        return 0;
 }
 
@@ -263,7 +376,11 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int i;
+       int i, ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start);
        seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
@@ -289,6 +406,7 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
                        seq_printf(m, "\n");
                }
        }
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
@@ -313,16 +431,19 @@ static int i915_hws_info(struct seq_file *m, void *data)
        return 0;
 }
 
-static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_count)
+static void i915_dump_object(struct seq_file *m,
+                            struct io_mapping *mapping,
+                            struct drm_i915_gem_object *obj_priv)
 {
-       int page, i;
-       uint32_t *mem;
+       int page, page_count, i;
 
+       page_count = obj_priv->base.size / PAGE_SIZE;
        for (page = 0; page < page_count; page++) {
-               mem = kmap_atomic(pages[page], KM_USER0);
+               u32 *mem = io_mapping_map_wc(mapping,
+                                            obj_priv->gtt_offset + page * PAGE_SIZE);
                for (i = 0; i < PAGE_SIZE; i += 4)
                        seq_printf(m, "%08x :  %08x\n", i, mem[i / 4]);
-               kunmap_atomic(mem, KM_USER0);
+               io_mapping_unmap(mem);
        }
 }
 
@@ -335,27 +456,21 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data)
        struct drm_i915_gem_object *obj_priv;
        int ret;
 
-       spin_lock(&dev_priv->mm.active_list_lock);
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        list_for_each_entry(obj_priv, &dev_priv->render_ring.active_list,
                        list) {
                obj = &obj_priv->base;
                if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
-                   ret = i915_gem_object_get_pages(obj, 0);
-                   if (ret) {
-                           DRM_ERROR("Failed to get pages: %d\n", ret);
-                           spin_unlock(&dev_priv->mm.active_list_lock);
-                           return ret;
-                   }
-
-                   seq_printf(m, "--- gtt_offset = 0x%08x\n", obj_priv->gtt_offset);
-                   i915_dump_pages(m, obj_priv->pages, obj->size / PAGE_SIZE);
-
-                   i915_gem_object_put_pages(obj);
+                   seq_printf(m, "--- gtt_offset = 0x%08x\n",
+                              obj_priv->gtt_offset);
+                   i915_dump_object(m, dev_priv->mm.gtt_mapping, obj_priv);
                }
        }
 
-       spin_unlock(&dev_priv->mm.active_list_lock);
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
@@ -365,20 +480,24 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       u8 *virt;
-       uint32_t *ptr, off;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        if (!dev_priv->render_ring.gem_object) {
                seq_printf(m, "No ringbuffer setup\n");
-               return 0;
-       }
-
-       virt = dev_priv->render_ring.virtual_start;
+       } else {
+               u8 *virt = dev_priv->render_ring.virtual_start;
+               uint32_t off;
 
-       for (off = 0; off < dev_priv->render_ring.size; off += 4) {
-               ptr = (uint32_t *)(virt + off);
-               seq_printf(m, "%08x :  %08x\n", off, *ptr);
+               for (off = 0; off < dev_priv->render_ring.size; off += 4) {
+                       uint32_t *ptr = (uint32_t *)(virt + off);
+                       seq_printf(m, "%08x :  %08x\n", off, *ptr);
+               }
        }
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
@@ -396,7 +515,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
        seq_printf(m, "RingHead :  %08x\n", head);
        seq_printf(m, "RingTail :  %08x\n", tail);
        seq_printf(m, "RingSize :  %08lx\n", dev_priv->render_ring.size);
-       seq_printf(m, "Acthd :     %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD));
+       seq_printf(m, "Acthd :     %08x\n", I915_READ(INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD));
 
        return 0;
 }
@@ -458,7 +577,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
        seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr);
        seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone);
        seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd);
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                seq_printf(m, "  INSTPS: 0x%08x\n", error->instps);
                seq_printf(m, "  INSTDONE1: 0x%08x\n", error->instdone1);
        }
@@ -642,6 +761,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
        } else {
                seq_printf(m, "FBC disabled: ");
                switch (dev_priv->no_fbc_reason) {
+               case FBC_NO_OUTPUT:
+                       seq_printf(m, "no outputs");
+                       break;
                case FBC_STOLEN_TOO_SMALL:
                        seq_printf(m, "not enough stolen memory");
                        break;
@@ -675,15 +797,17 @@ static int i915_sr_status(struct seq_file *m, void *unused)
        drm_i915_private_t *dev_priv = dev->dev_private;
        bool sr_enabled = false;
 
-       if (IS_I965GM(dev) || IS_I945G(dev) || IS_I945GM(dev))
+       if (IS_IRONLAKE(dev))
+               sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN;
+       else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev))
                sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
        else if (IS_I915GM(dev))
                sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
        else if (IS_PINEVIEW(dev))
                sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
 
-       seq_printf(m, "self-refresh: %s\n", sr_enabled ? "enabled" :
-                  "disabled");
+       seq_printf(m, "self-refresh: %s\n",
+                  sr_enabled ? "enabled" : "disabled");
 
        return 0;
 }
@@ -694,10 +818,16 @@ static int i915_emon_status(struct seq_file *m, void *unused)
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        unsigned long temp, chipset, gfx;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
 
        temp = i915_mch_val(dev_priv);
        chipset = i915_chipset_val(dev_priv);
        gfx = i915_gfx_val(dev_priv);
+       mutex_unlock(&dev->struct_mutex);
 
        seq_printf(m, "GMCH temp: %ld\n", temp);
        seq_printf(m, "Chipset power: %ld\n", chipset);
@@ -718,6 +848,68 @@ static int i915_gfxec(struct seq_file *m, void *unused)
        return 0;
 }
 
+static int i915_opregion(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       if (opregion->header)
+               seq_write(m, opregion->header, OPREGION_SIZE);
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_fbdev *ifbdev;
+       struct intel_framebuffer *fb;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+       if (ret)
+               return ret;
+
+       ifbdev = dev_priv->fbdev;
+       fb = to_intel_framebuffer(ifbdev->helper.fb);
+
+       seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ",
+                  fb->base.width,
+                  fb->base.height,
+                  fb->base.depth,
+                  fb->base.bits_per_pixel);
+       describe_obj(m, to_intel_bo(fb->obj));
+       seq_printf(m, "\n");
+
+       list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) {
+               if (&fb->base == ifbdev->helper.fb)
+                       continue;
+
+               seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ",
+                          fb->base.width,
+                          fb->base.height,
+                          fb->base.depth,
+                          fb->base.bits_per_pixel);
+               describe_obj(m, to_intel_bo(fb->obj));
+               seq_printf(m, "\n");
+       }
+
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return 0;
+}
+
 static int
 i915_wedged_open(struct inode *inode,
                 struct file *filp)
@@ -741,6 +933,9 @@ i915_wedged_read(struct file *filp,
                       "wedged :  %d\n",
                       atomic_read(&dev_priv->mm.wedged));
 
+       if (len > sizeof (buf))
+               len = sizeof (buf);
+
        return simple_read_from_buffer(ubuf, max, ppos, buf, len);
 }
 
@@ -770,7 +965,7 @@ i915_wedged_write(struct file *filp,
 
        atomic_set(&dev_priv->mm.wedged, val);
        if (val) {
-               DRM_WAKEUP(&dev_priv->irq_queue);
+               wake_up_all(&dev_priv->irq_queue);
                queue_work(dev_priv->wq, &dev_priv->error_work);
        }
 
@@ -823,9 +1018,14 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
 }
 
 static struct drm_info_list i915_debugfs_list[] = {
-       {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
+       {"i915_capabilities", i915_capabilities, 0, 0},
+       {"i915_gem_objects", i915_gem_object_info, 0},
+       {"i915_gem_render_active", i915_gem_object_list_info, 0, (void *) RENDER_LIST},
+       {"i915_gem_bsd_active", i915_gem_object_list_info, 0, (void *) BSD_LIST},
        {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
        {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
+       {"i915_gem_pinned", i915_gem_object_list_info, 0, (void *) PINNED_LIST},
+       {"i915_gem_deferred_free", i915_gem_object_list_info, 0, (void *) DEFERRED_FREE_LIST},
        {"i915_gem_pageflip", i915_gem_pageflip_info, 0},
        {"i915_gem_request", i915_gem_request_info, 0},
        {"i915_gem_seqno", i915_gem_seqno_info, 0},
@@ -845,6 +1045,8 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_gfxec", i915_gfxec, 0},
        {"i915_fbc_status", i915_fbc_status, 0},
        {"i915_sr_status", i915_sr_status, 0},
+       {"i915_opregion", i915_opregion, 0},
+       {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
index 9d67b485303005771a090ea7a3c1e1c6f8b74e9e..726c3736082ff0ceb57dc952b671a95109267dde 100644 (file)
@@ -40,8 +40,7 @@
 #include <linux/pnp.h>
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
-
-extern int intel_max_stolen; /* from AGP driver */
+#include <acpi/video.h>
 
 /**
  * Sets up the hardware status page for devices that need a physical address
@@ -64,7 +63,7 @@ static int i915_init_phys_hws(struct drm_device *dev)
 
        memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE);
 
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
                                             0xf0;
 
@@ -222,7 +221,7 @@ static int i915_dma_resume(struct drm_device * dev)
        DRM_DEBUG_DRIVER("hw status page @ %p\n",
                                ring->status_page.page_addr);
        if (ring->status_page.gfx_addr != 0)
-               ring->setup_status_page(dev, ring);
+               intel_ring_setup_status_page(dev, ring);
        else
                I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
 
@@ -377,7 +376,7 @@ i915_emit_box(struct drm_device *dev,
                return -EINVAL;
        }
 
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                BEGIN_LP_RING(4);
                OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
                OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
@@ -481,7 +480,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
 
                if (!IS_I830(dev) && !IS_845G(dev)) {
                        BEGIN_LP_RING(2);
-                       if (IS_I965G(dev)) {
+                       if (INTEL_INFO(dev)->gen >= 4) {
                                OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
                                OUT_RING(batch->start);
                        } else {
@@ -888,12 +887,12 @@ static int
 intel_alloc_mchbar_resource(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+       int reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp_lo, temp_hi = 0;
        u64 mchbar_addr;
        int ret;
 
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
        pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
        mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
@@ -920,7 +919,7 @@ intel_alloc_mchbar_resource(struct drm_device *dev)
                return ret;
        }
 
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
                                       upper_32_bits(dev_priv->mch_res.start));
 
@@ -934,7 +933,7 @@ static void
 intel_setup_mchbar(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+       int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp;
        bool enabled;
 
@@ -971,7 +970,7 @@ static void
 intel_teardown_mchbar(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+       int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp;
 
        if (dev_priv->mchbar_need_disable) {
@@ -990,174 +989,6 @@ intel_teardown_mchbar(struct drm_device *dev)
                release_resource(&dev_priv->mch_res);
 }
 
-/**
- * i915_probe_agp - get AGP bootup configuration
- * @pdev: PCI device
- * @aperture_size: returns AGP aperture configured size
- * @preallocated_size: returns size of BIOS preallocated AGP space
- *
- * Since Intel integrated graphics are UMA, the BIOS has to set aside
- * some RAM for the framebuffer at early boot.  This code figures out
- * how much was set aside so we can use it for our own purposes.
- */
-static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
-                         uint32_t *preallocated_size,
-                         uint32_t *start)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u16 tmp = 0;
-       unsigned long overhead;
-       unsigned long stolen;
-
-       /* Get the fb aperture size and "stolen" memory amount. */
-       pci_read_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, &tmp);
-
-       *aperture_size = 1024 * 1024;
-       *preallocated_size = 1024 * 1024;
-
-       switch (dev->pdev->device) {
-       case PCI_DEVICE_ID_INTEL_82830_CGC:
-       case PCI_DEVICE_ID_INTEL_82845G_IG:
-       case PCI_DEVICE_ID_INTEL_82855GM_IG:
-       case PCI_DEVICE_ID_INTEL_82865_IG:
-               if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
-                       *aperture_size *= 64;
-               else
-                       *aperture_size *= 128;
-               break;
-       default:
-               /* 9xx supports large sizes, just look at the length */
-               *aperture_size = pci_resource_len(dev->pdev, 2);
-               break;
-       }
-
-       /*
-        * Some of the preallocated space is taken by the GTT
-        * and popup.  GTT is 1K per MB of aperture size, and popup is 4K.
-        */
-       if (IS_G4X(dev) || IS_PINEVIEW(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev))
-               overhead = 4096;
-       else
-               overhead = (*aperture_size / 1024) + 4096;
-
-       if (IS_GEN6(dev)) {
-               /* SNB has memory control reg at 0x50.w */
-               pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &tmp);
-
-               switch (tmp & SNB_GMCH_GMS_STOLEN_MASK) {
-               case INTEL_855_GMCH_GMS_DISABLED:
-                       DRM_ERROR("video memory is disabled\n");
-                       return -1;
-               case SNB_GMCH_GMS_STOLEN_32M:
-                       stolen = 32 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_64M:
-                       stolen = 64 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_96M:
-                       stolen = 96 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_128M:
-                       stolen = 128 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_160M:
-                       stolen = 160 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_192M:
-                       stolen = 192 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_224M:
-                       stolen = 224 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_256M:
-                       stolen = 256 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_288M:
-                       stolen = 288 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_320M:
-                       stolen = 320 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_352M:
-                       stolen = 352 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_384M:
-                       stolen = 384 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_416M:
-                       stolen = 416 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_448M:
-                       stolen = 448 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_480M:
-                       stolen = 480 * 1024 * 1024;
-                       break;
-               case SNB_GMCH_GMS_STOLEN_512M:
-                       stolen = 512 * 1024 * 1024;
-                       break;
-               default:
-                       DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
-                                 tmp & SNB_GMCH_GMS_STOLEN_MASK);
-                       return -1;
-               }
-       } else {
-               switch (tmp & INTEL_GMCH_GMS_MASK) {
-               case INTEL_855_GMCH_GMS_DISABLED:
-                       DRM_ERROR("video memory is disabled\n");
-                       return -1;
-               case INTEL_855_GMCH_GMS_STOLEN_1M:
-                       stolen = 1 * 1024 * 1024;
-                       break;
-               case INTEL_855_GMCH_GMS_STOLEN_4M:
-                       stolen = 4 * 1024 * 1024;
-                       break;
-               case INTEL_855_GMCH_GMS_STOLEN_8M:
-                       stolen = 8 * 1024 * 1024;
-                       break;
-               case INTEL_855_GMCH_GMS_STOLEN_16M:
-                       stolen = 16 * 1024 * 1024;
-                       break;
-               case INTEL_855_GMCH_GMS_STOLEN_32M:
-                       stolen = 32 * 1024 * 1024;
-                       break;
-               case INTEL_915G_GMCH_GMS_STOLEN_48M:
-                       stolen = 48 * 1024 * 1024;
-                       break;
-               case INTEL_915G_GMCH_GMS_STOLEN_64M:
-                       stolen = 64 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_128M:
-                       stolen = 128 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_256M:
-                       stolen = 256 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_96M:
-                       stolen = 96 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_160M:
-                       stolen = 160 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_224M:
-                       stolen = 224 * 1024 * 1024;
-                       break;
-               case INTEL_GMCH_GMS_STOLEN_352M:
-                       stolen = 352 * 1024 * 1024;
-                       break;
-               default:
-                       DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
-                                 tmp & INTEL_GMCH_GMS_MASK);
-                       return -1;
-               }
-       }
-
-       *preallocated_size = stolen - overhead;
-       *start = overhead;
-
-       return 0;
-}
-
 #define PTE_ADDRESS_MASK               0xfffff000
 #define PTE_ADDRESS_MASK_HIGH          0x000000f0 /* i915+ */
 #define PTE_MAPPING_TYPE_UNCACHED      (0 << 1)
@@ -1181,11 +1012,11 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev,
 {
        unsigned long *gtt;
        unsigned long entry, phys;
-       int gtt_bar = IS_I9XX(dev) ? 0 : 1;
+       int gtt_bar = IS_GEN2(dev) ? 1 : 0;
        int gtt_offset, gtt_size;
 
-       if (IS_I965G(dev)) {
-               if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
+               if (IS_G4X(dev) || INTEL_INFO(dev)->gen > 4) {
                        gtt_offset = 2*1024*1024;
                        gtt_size = 2*1024*1024;
                } else {
@@ -1210,10 +1041,8 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev,
        DRM_DEBUG_DRIVER("GTT addr: 0x%08lx, PTE: 0x%08lx\n", gtt_addr, entry);
 
        /* Mask out these reserved bits on this hardware. */
-       if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev) ||
-           IS_I945G(dev) || IS_I945GM(dev)) {
+       if (INTEL_INFO(dev)->gen < 4 && !IS_G33(dev))
                entry &= ~PTE_ADDRESS_MASK_HIGH;
-       }
 
        /* If it's not a mapping type we know, then bail. */
        if ((entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED &&
@@ -1252,7 +1081,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
        unsigned long ll_base = 0;
 
        /* Leave 1M for line length buffer & misc. */
-       compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0);
+       compressed_fb = drm_mm_search_free(&dev_priv->mm.vram, size, 4096, 0);
        if (!compressed_fb) {
                dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
                i915_warn_stolen(dev);
@@ -1273,7 +1102,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
        }
 
        if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) {
-               compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096,
+               compressed_llb = drm_mm_search_free(&dev_priv->mm.vram, 4096,
                                                    4096, 0);
                if (!compressed_llb) {
                        i915_warn_stolen(dev);
@@ -1343,10 +1172,8 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
                /* i915 resume handler doesn't set to D0 */
                pci_set_power_state(dev->pdev, PCI_D0);
                i915_resume(dev);
-               drm_kms_helper_poll_enable(dev);
        } else {
                printk(KERN_ERR "i915: switched off\n");
-               drm_kms_helper_poll_disable(dev);
                i915_suspend(dev, pmm);
        }
 }
@@ -1363,20 +1190,14 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
 }
 
 static int i915_load_modeset_init(struct drm_device *dev,
-                                 unsigned long prealloc_start,
                                  unsigned long prealloc_size,
                                  unsigned long agp_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int fb_bar = IS_I9XX(dev) ? 2 : 0;
        int ret = 0;
 
-       dev->mode_config.fb_base = pci_resource_start(dev->pdev, fb_bar) &
-               0xff000000;
-
-       /* Basic memrange allocator for stolen space (aka vram) */
-       drm_mm_init(&dev_priv->vram, 0, prealloc_size);
-       DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024));
+       /* Basic memrange allocator for stolen space (aka mm.vram) */
+       drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size);
 
        /* We're off and running w/KMS */
        dev_priv->mm.suspended = 0;
@@ -1443,12 +1264,6 @@ static int i915_load_modeset_init(struct drm_device *dev,
        /* FIXME: do pre/post-mode set stuff in core KMS code */
        dev->vblank_disable_allowed = 1;
 
-       /*
-        * Initialize the hardware status page IRQ location.
-        */
-
-       I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
-
        ret = intel_fbdev_init(dev);
        if (ret)
                goto cleanup_irq;
@@ -1787,9 +1602,9 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
                }
        }
 
-       div_u64(diff, diff1);
+       diff = div_u64(diff, diff1);
        ret = ((m * diff) + c);
-       div_u64(ret, 10);
+       ret = div_u64(ret, 10);
 
        dev_priv->last_count1 = total_count;
        dev_priv->last_time1 = now;
@@ -1858,7 +1673,7 @@ void i915_update_gfx_val(struct drm_i915_private *dev_priv)
 
        /* More magic constants... */
        diff = diff * 1181;
-       div_u64(diff, diffms * 10);
+       diff = div_u64(diff, diffms * 10);
        dev_priv->gfx_power = diff;
 }
 
@@ -1907,7 +1722,7 @@ static struct drm_i915_private *i915_mch_dev;
  *   - dev_priv->fmax
  *   - dev_priv->gpu_busy
  */
-DEFINE_SPINLOCK(mchdev_lock);
+static DEFINE_SPINLOCK(mchdev_lock);
 
 /**
  * i915_read_mch_val - return value for IPS use
@@ -2062,7 +1877,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        struct drm_i915_private *dev_priv;
        resource_size_t base, size;
        int ret = 0, mmio_bar;
-       uint32_t agp_size, prealloc_size, prealloc_start;
+       uint32_t agp_size, prealloc_size;
        /* i915 has 4 more counters */
        dev->counters += 4;
        dev->types[6] = _DRM_STAT_IRQ;
@@ -2079,7 +1894,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev_priv->info = (struct intel_device_info *) flags;
 
        /* Add register map (needed for suspend/resume) */
-       mmio_bar = IS_I9XX(dev) ? 0 : 1;
+       mmio_bar = IS_GEN2(dev) ? 1 : 0;
        base = pci_resource_start(dev->pdev, mmio_bar);
        size = pci_resource_len(dev->pdev, mmio_bar);
 
@@ -2121,17 +1936,32 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                         "performance may suffer.\n");
        }
 
-       ret = i915_probe_agp(dev, &agp_size, &prealloc_size, &prealloc_start);
-       if (ret)
+       dev_priv->mm.gtt = intel_gtt_get();
+       if (!dev_priv->mm.gtt) {
+               DRM_ERROR("Failed to initialize GTT\n");
+               ret = -ENODEV;
                goto out_iomapfree;
-
-       if (prealloc_size > intel_max_stolen) {
-               DRM_INFO("detected %dM stolen memory, trimming to %dM\n",
-                        prealloc_size >> 20, intel_max_stolen >> 20);
-               prealloc_size = intel_max_stolen;
        }
 
-       dev_priv->wq = create_singlethread_workqueue("i915");
+       prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT;
+       agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+
+       /* The i915 workqueue is primarily used for batched retirement of
+        * requests (and thus managing bo) once the task has been completed
+        * by the GPU. i915_gem_retire_requests() is called directly when we
+        * need high-priority retirement, such as waiting for an explicit
+        * bo.
+        *
+        * It is also used for periodic low-priority events, such as
+        * idle-timers and hangcheck.
+        *
+        * All tasks on the workqueue are expected to acquire the dev mutex
+        * so there is no point in running more than one instance of the
+        * workqueue at any time: max_active = 1 and NON_REENTRANT.
+        */
+       dev_priv->wq = alloc_workqueue("i915",
+                                      WQ_UNBOUND | WQ_NON_REENTRANT,
+                                      1);
        if (dev_priv->wq == NULL) {
                DRM_ERROR("Failed to create our workqueue.\n");
                ret = -ENOMEM;
@@ -2166,6 +1996,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        /* Try to make sure MCHBAR is enabled before poking at it */
        intel_setup_mchbar(dev);
+       intel_setup_gmbus(dev);
+       intel_opregion_setup(dev);
 
        i915_gem_load(dev);
 
@@ -2212,8 +2044,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        intel_detect_pch(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               ret = i915_load_modeset_init(dev, prealloc_start,
-                                            prealloc_size, agp_size);
+               ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
                if (ret < 0) {
                        DRM_ERROR("failed to init modeset\n");
                        goto out_workqueue_free;
@@ -2221,7 +2052,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        }
 
        /* Must be done after probing outputs */
-       intel_opregion_init(dev, 0);
+       intel_opregion_init(dev);
+       acpi_video_register();
 
        setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
                    (unsigned long) dev);
@@ -2249,15 +2081,20 @@ free_priv:
 int i915_driver_unload(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-
-       i915_destroy_error_state(dev);
+       int ret;
 
        spin_lock(&mchdev_lock);
        i915_mch_dev = NULL;
        spin_unlock(&mchdev_lock);
 
-       destroy_workqueue(dev_priv->wq);
-       del_timer_sync(&dev_priv->hangcheck_timer);
+       mutex_lock(&dev->struct_mutex);
+       ret = i915_gpu_idle(dev);
+       if (ret)
+               DRM_ERROR("failed to idle hardware: %d\n", ret);
+       mutex_unlock(&dev->struct_mutex);
+
+       /* Cancel the retire work handler, which should be idle now. */
+       cancel_delayed_work_sync(&dev_priv->mm.retire_work);
 
        io_mapping_free(dev_priv->mm.gtt_mapping);
        if (dev_priv->mm.gtt_mtrr >= 0) {
@@ -2266,7 +2103,10 @@ int i915_driver_unload(struct drm_device *dev)
                dev_priv->mm.gtt_mtrr = -1;
        }
 
+       acpi_video_unregister();
+
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               intel_fbdev_fini(dev);
                intel_modeset_cleanup(dev);
 
                /*
@@ -2278,20 +2118,28 @@ int i915_driver_unload(struct drm_device *dev)
                        dev_priv->child_dev = NULL;
                        dev_priv->child_dev_num = 0;
                }
-               drm_irq_uninstall(dev);
+
                vga_switcheroo_unregister_client(dev->pdev);
                vga_client_register(dev->pdev, NULL, NULL, NULL);
        }
 
+       /* Free error state after interrupts are fully disabled. */
+       del_timer_sync(&dev_priv->hangcheck_timer);
+       cancel_work_sync(&dev_priv->error_work);
+       i915_destroy_error_state(dev);
+
        if (dev->pdev->msi_enabled)
                pci_disable_msi(dev->pdev);
 
        if (dev_priv->regs != NULL)
                iounmap(dev_priv->regs);
 
-       intel_opregion_free(dev, 0);
+       intel_opregion_fini(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               /* Flush any outstanding unpin_work. */
+               flush_workqueue(dev_priv->wq);
+
                i915_gem_free_all_phys_object(dev);
 
                mutex_lock(&dev->struct_mutex);
@@ -2299,34 +2147,35 @@ int i915_driver_unload(struct drm_device *dev)
                mutex_unlock(&dev->struct_mutex);
                if (I915_HAS_FBC(dev) && i915_powersave)
                        i915_cleanup_compression(dev);
-               drm_mm_takedown(&dev_priv->vram);
-               i915_gem_lastclose(dev);
+               drm_mm_takedown(&dev_priv->mm.vram);
 
                intel_cleanup_overlay(dev);
        }
 
+       intel_teardown_gmbus(dev);
        intel_teardown_mchbar(dev);
 
+       destroy_workqueue(dev_priv->wq);
+
        pci_dev_put(dev_priv->bridge_dev);
        kfree(dev->dev_private);
 
        return 0;
 }
 
-int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+int i915_driver_open(struct drm_device *dev, struct drm_file *file)
 {
-       struct drm_i915_file_private *i915_file_priv;
+       struct drm_i915_file_private *file_priv;
 
        DRM_DEBUG_DRIVER("\n");
-       i915_file_priv = (struct drm_i915_file_private *)
-           kmalloc(sizeof(*i915_file_priv), GFP_KERNEL);
-
-       if (!i915_file_priv)
+       file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL);
+       if (!file_priv)
                return -ENOMEM;
 
-       file_priv->driver_priv = i915_file_priv;
+       file->driver_priv = file_priv;
 
-       INIT_LIST_HEAD(&i915_file_priv->mm.request_list);
+       spin_lock_init(&file_priv->mm.lock);
+       INIT_LIST_HEAD(&file_priv->mm.request_list);
 
        return 0;
 }
@@ -2369,11 +2218,11 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
                i915_mem_release(dev, file_priv, dev_priv->agp_heap);
 }
 
-void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
+void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
 {
-       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+       struct drm_i915_file_private *file_priv = file->driver_priv;
 
-       kfree(i915_file_priv);
+       kfree(file_priv);
 }
 
 struct drm_ioctl_desc i915_ioctls[] = {
index 9ed9d23caf14eb49a61319db08425f4949b84cf0..c3decb2fef4ba8b80d7b95114a58cf25e35a7b59 100644 (file)
@@ -32,6 +32,7 @@
 #include "drm.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_drv.h"
 
 #include <linux/console.h>
 #include "drm_crtc_helper.h"
@@ -61,86 +62,108 @@ extern int intel_agp_enabled;
        .driver_data = (unsigned long) info }
 
 static const struct intel_device_info intel_i830_info = {
-       .gen = 2, .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1,
+       .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_845g_info = {
-       .gen = 2, .is_i8xx = 1,
+       .gen = 2,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i85x_info = {
-       .gen = 2, .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1,
+       .gen = 2, .is_i85x = 1, .is_mobile = 1,
        .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i865g_info = {
-       .gen = 2, .is_i8xx = 1,
+       .gen = 2,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i915g_info = {
-       .gen = 3, .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1,
+       .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 static const struct intel_device_info intel_i915gm_info = {
-       .gen = 3, .is_i9xx = 1,  .is_mobile = 1,
+       .gen = 3, .is_mobile = 1,
        .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
+       .supports_tv = 1,
 };
 static const struct intel_device_info intel_i945g_info = {
-       .gen = 3, .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1,
+       .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
 };
 static const struct intel_device_info intel_i945gm_info = {
-       .gen = 3, .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1,
+       .gen = 3, .is_i945gm = 1, .is_mobile = 1,
        .has_hotplug = 1, .cursor_needs_physical = 1,
+       .has_overlay = 1, .overlay_needs_physical = 1,
+       .supports_tv = 1,
 };
 
 static const struct intel_device_info intel_i965g_info = {
-       .gen = 4, .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1,
+       .gen = 4, .is_broadwater = 1,
        .has_hotplug = 1,
+       .has_overlay = 1,
 };
 
 static const struct intel_device_info intel_i965gm_info = {
-       .gen = 4, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1,
+       .gen = 4, .is_crestline = 1,
        .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+       .has_overlay = 1,
+       .supports_tv = 1,
 };
 
 static const struct intel_device_info intel_g33_info = {
-       .gen = 3, .is_g33 = 1, .is_i9xx = 1,
+       .gen = 3, .is_g33 = 1,
        .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_overlay = 1,
 };
 
 static const struct intel_device_info intel_g45_info = {
-       .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1,
+       .gen = 4, .is_g4x = 1, .need_gfx_hws = 1,
        .has_pipe_cxsr = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_gm45_info = {
-       .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1,
+       .gen = 4, .is_g4x = 1,
        .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
        .has_pipe_cxsr = 1, .has_hotplug = 1,
+       .supports_tv = 1,
+       .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_pineview_info = {
-       .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1,
+       .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1,
        .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_overlay = 1,
 };
 
 static const struct intel_device_info intel_ironlake_d_info = {
-       .gen = 5, .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1,
+       .gen = 5, .is_ironlake = 1,
        .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_ironlake_m_info = {
-       .gen = 5, .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1,
+       .gen = 5, .is_ironlake = 1, .is_mobile = 1,
        .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_d_info = {
-       .gen = 6, .is_i965g = 1, .is_i9xx = 1,
+       .gen = 6,
        .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_m_info = {
-       .gen = 6, .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1,
+       .gen = 6, .is_mobile = 1,
        .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
 };
 
 static const struct pci_device_id pciidlist[] = {              /* aka */
@@ -237,7 +260,7 @@ static int i915_drm_freeze(struct drm_device *dev)
 
        i915_save_state(dev);
 
-       intel_opregion_free(dev, 1);
+       intel_opregion_fini(dev);
 
        /* Modeset on resume, not lid events */
        dev_priv->modeset_on_lid = 0;
@@ -258,6 +281,8 @@ int i915_suspend(struct drm_device *dev, pm_message_t state)
        if (state.event == PM_EVENT_PRETHAW)
                return 0;
 
+       drm_kms_helper_poll_disable(dev);
+
        error = i915_drm_freeze(dev);
        if (error)
                return error;
@@ -277,8 +302,7 @@ static int i915_drm_thaw(struct drm_device *dev)
        int error = 0;
 
        i915_restore_state(dev);
-
-       intel_opregion_init(dev, 1);
+       intel_opregion_setup(dev);
 
        /* KMS EnterVT equivalent */
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
@@ -294,6 +318,8 @@ static int i915_drm_thaw(struct drm_device *dev)
                drm_helper_resume_force_mode(dev);
        }
 
+       intel_opregion_init(dev);
+
        dev_priv->modeset_on_lid = 0;
 
        return error;
@@ -301,12 +327,79 @@ static int i915_drm_thaw(struct drm_device *dev)
 
 int i915_resume(struct drm_device *dev)
 {
+       int ret;
+
        if (pci_enable_device(dev->pdev))
                return -EIO;
 
        pci_set_master(dev->pdev);
 
-       return i915_drm_thaw(dev);
+       ret = i915_drm_thaw(dev);
+       if (ret)
+               return ret;
+
+       drm_kms_helper_poll_enable(dev);
+       return 0;
+}
+
+static int i8xx_do_reset(struct drm_device *dev, u8 flags)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (IS_I85X(dev))
+               return -ENODEV;
+
+       I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830);
+       POSTING_READ(D_STATE);
+
+       if (IS_I830(dev) || IS_845G(dev)) {
+               I915_WRITE(DEBUG_RESET_I830,
+                          DEBUG_RESET_DISPLAY |
+                          DEBUG_RESET_RENDER |
+                          DEBUG_RESET_FULL);
+               POSTING_READ(DEBUG_RESET_I830);
+               msleep(1);
+
+               I915_WRITE(DEBUG_RESET_I830, 0);
+               POSTING_READ(DEBUG_RESET_I830);
+       }
+
+       msleep(1);
+
+       I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830);
+       POSTING_READ(D_STATE);
+
+       return 0;
+}
+
+static int i965_reset_complete(struct drm_device *dev)
+{
+       u8 gdrst;
+       pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+       return gdrst & 0x1;
+}
+
+static int i965_do_reset(struct drm_device *dev, u8 flags)
+{
+       u8 gdrst;
+
+       /*
+        * Set the domains we want to reset (GRDOM/bits 2 and 3) as
+        * well as the reset bit (GR/bit 0).  Setting the GR bit
+        * triggers the reset; when done, the hardware will clear it.
+        */
+       pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+       pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1);
+
+       return wait_for(i965_reset_complete(dev), 500);
+}
+
+static int ironlake_do_reset(struct drm_device *dev, u8 flags)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+       I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1);
+       return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
 }
 
 /**
@@ -325,54 +418,39 @@ int i915_resume(struct drm_device *dev)
  *   - re-init interrupt state
  *   - re-init display
  */
-int i965_reset(struct drm_device *dev, u8 flags)
+int i915_reset(struct drm_device *dev, u8 flags)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       unsigned long timeout;
-       u8 gdrst;
        /*
         * We really should only reset the display subsystem if we actually
         * need to
         */
        bool need_display = true;
+       int ret;
 
        mutex_lock(&dev->struct_mutex);
 
-       /*
-        * Clear request list
-        */
-       i915_gem_retire_requests(dev);
-
-       if (need_display)
-               i915_save_display(dev);
-
-       if (IS_I965G(dev) || IS_G4X(dev)) {
-               /*
-                * Set the domains we want to reset, then the reset bit (bit 0).
-                * Clear the reset bit after a while and wait for hardware status
-                * bit (bit 1) to be set
-                */
-               pci_read_config_byte(dev->pdev, GDRST, &gdrst);
-               pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | ((flags == GDRST_FULL) ? 0x1 : 0x0));
-               udelay(50);
-               pci_write_config_byte(dev->pdev, GDRST, gdrst & 0xfe);
-
-               /* ...we don't want to loop forever though, 500ms should be plenty */
-              timeout = jiffies + msecs_to_jiffies(500);
-               do {
-                       udelay(100);
-                       pci_read_config_byte(dev->pdev, GDRST, &gdrst);
-               } while ((gdrst & 0x1) && time_after(timeout, jiffies));
-
-               if (gdrst & 0x1) {
-                       WARN(true, "i915: Failed to reset chip\n");
-                       mutex_unlock(&dev->struct_mutex);
-                       return -EIO;
-               }
-       } else {
-               DRM_ERROR("Error occurred. Don't know how to reset this chip.\n");
+       i915_gem_reset(dev);
+
+       ret = -ENODEV;
+       if (get_seconds() - dev_priv->last_gpu_reset < 5) {
+               DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
+       } else switch (INTEL_INFO(dev)->gen) {
+       case 5:
+               ret = ironlake_do_reset(dev, flags);
+               break;
+       case 4:
+               ret = i965_do_reset(dev, flags);
+               break;
+       case 2:
+               ret = i8xx_do_reset(dev, flags);
+               break;
+       }
+       dev_priv->last_gpu_reset = get_seconds();
+       if (ret) {
+               DRM_ERROR("Failed to reset chip.\n");
                mutex_unlock(&dev->struct_mutex);
-               return -ENODEV;
+               return ret;
        }
 
        /* Ok, now get things going again... */
@@ -400,13 +478,19 @@ int i965_reset(struct drm_device *dev, u8 flags)
                mutex_lock(&dev->struct_mutex);
        }
 
+       mutex_unlock(&dev->struct_mutex);
+
        /*
-        * Display needs restore too...
+        * Perform a full modeset as on later generations, e.g. Ironlake, we may
+        * need to retrain the display link and cannot just restore the register
+        * values.
         */
-       if (need_display)
-               i915_restore_display(dev);
+       if (need_display) {
+               mutex_lock(&dev->mode_config.mutex);
+               drm_helper_resume_force_mode(dev);
+               mutex_unlock(&dev->mode_config.mutex);
+       }
 
-       mutex_unlock(&dev->struct_mutex);
        return 0;
 }
 
index af4a263cf25782a6906f80a1d0783841000ac9b1..73ad8bff2c2a7ab833dbad13156453e5d9c2569d 100644 (file)
@@ -34,6 +34,8 @@
 #include "intel_bios.h"
 #include "intel_ringbuffer.h"
 #include <linux/io-mapping.h>
+#include <linux/i2c.h>
+#include <drm/intel-gtt.h>
 
 /* General customization:
  */
@@ -73,11 +75,9 @@ enum plane {
 #define DRIVER_PATCHLEVEL      0
 
 #define WATCH_COHERENCY        0
-#define WATCH_BUF      0
 #define WATCH_EXEC     0
-#define WATCH_LRU      0
 #define WATCH_RELOC    0
-#define WATCH_INACTIVE 0
+#define WATCH_LISTS    0
 #define WATCH_PWRITE   0
 
 #define I915_GEM_PHYS_CURSOR_0 1
@@ -110,8 +110,9 @@ struct intel_opregion {
        struct opregion_acpi *acpi;
        struct opregion_swsci *swsci;
        struct opregion_asle *asle;
-       int enabled;
+       void *vbt;
 };
+#define OPREGION_SIZE            (8*1024)
 
 struct intel_overlay;
 struct intel_overlay_error_state;
@@ -125,13 +126,16 @@ struct drm_i915_master_private {
 struct drm_i915_fence_reg {
        struct drm_gem_object *obj;
        struct list_head lru_list;
+       bool gpu;
 };
 
 struct sdvo_device_mapping {
+       u8 initialized;
        u8 dvo_port;
        u8 slave_addr;
        u8 dvo_wiring;
-       u8 initialized;
+       u8 i2c_pin;
+       u8 i2c_speed;
        u8 ddc_pin;
 };
 
@@ -193,13 +197,9 @@ struct drm_i915_display_funcs {
 struct intel_device_info {
        u8 gen;
        u8 is_mobile : 1;
-       u8 is_i8xx : 1;
        u8 is_i85x : 1;
        u8 is_i915g : 1;
-       u8 is_i9xx : 1;
        u8 is_i945gm : 1;
-       u8 is_i965g : 1;
-       u8 is_i965gm : 1;
        u8 is_g33 : 1;
        u8 need_gfx_hws : 1;
        u8 is_g4x : 1;
@@ -212,9 +212,14 @@ struct intel_device_info {
        u8 has_pipe_cxsr : 1;
        u8 has_hotplug : 1;
        u8 cursor_needs_physical : 1;
+       u8 has_overlay : 1;
+       u8 overlay_needs_physical : 1;
+       u8 supports_tv : 1;
+       u8 has_bsd_ring : 1;
 };
 
 enum no_fbc_reason {
+       FBC_NO_OUTPUT, /* no outputs enabled to compress */
        FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
        FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
        FBC_MODE_TOO_LARGE, /* mode too large for compression */
@@ -241,6 +246,12 @@ typedef struct drm_i915_private {
 
        void __iomem *regs;
 
+       struct intel_gmbus {
+               struct i2c_adapter adapter;
+               struct i2c_adapter *force_bit;
+               u32 reg0;
+       } *gmbus;
+
        struct pci_dev *bridge_dev;
        struct intel_ring_buffer render_ring;
        struct intel_ring_buffer bsd_ring;
@@ -263,6 +274,9 @@ typedef struct drm_i915_private {
        int front_offset;
        int current_page;
        int page_flipping;
+#define I915_DEBUG_READ (1<<0)
+#define I915_DEBUG_WRITE (1<<1)
+       unsigned long debug_flags;
 
        wait_queue_head_t irq_queue;
        atomic_t irq_received;
@@ -289,24 +303,21 @@ typedef struct drm_i915_private {
        unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
        int vblank_pipe;
        int num_pipe;
-       u32 flush_rings;
-#define FLUSH_RENDER_RING      0x1
-#define FLUSH_BSD_RING         0x2
 
        /* For hangcheck timer */
-#define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */
+#define DRM_I915_HANGCHECK_PERIOD 250 /* in ms */
        struct timer_list hangcheck_timer;
        int hangcheck_count;
        uint32_t last_acthd;
        uint32_t last_instdone;
        uint32_t last_instdone1;
 
-       struct drm_mm vram;
-
        unsigned long cfb_size;
        unsigned long cfb_pitch;
+       unsigned long cfb_offset;
        int cfb_fence;
        int cfb_plane;
+       int cfb_y;
 
        int irq_enabled;
 
@@ -316,8 +327,7 @@ typedef struct drm_i915_private {
        struct intel_overlay *overlay;
 
        /* LVDS info */
-       int backlight_duty_cycle;  /* restore backlight to this value */
-       bool panel_wants_dither;
+       int backlight_level;  /* restore backlight to this value */
        struct drm_display_mode *panel_fixed_mode;
        struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
        struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
@@ -328,13 +338,22 @@ typedef struct drm_i915_private {
        unsigned int lvds_vbt:1;
        unsigned int int_crt_support:1;
        unsigned int lvds_use_ssc:1;
-       unsigned int edp_support:1;
        int lvds_ssc_freq;
-       int edp_bpp;
+
+       struct {
+               u8 rate:4;
+               u8 lanes:4;
+               u8 preemphasis:4;
+               u8 vswing:4;
+
+               u8 initialized:1;
+               u8 support:1;
+               u8 bpp:6;
+       } edp;
 
        struct notifier_block lid_notifier;
 
-       int crt_ddc_bus; /* 0 = unknown, else GPIO to use for CRT DDC */
+       int crt_ddc_pin;
        struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
        int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
        int num_fence_regs; /* 8 on pre-965, 16 otherwise */
@@ -344,6 +363,7 @@ typedef struct drm_i915_private {
        spinlock_t error_lock;
        struct drm_i915_error_state *first_error;
        struct work_struct error_work;
+       struct completion error_completion;
        struct workqueue_struct *wq;
 
        /* Display functions */
@@ -507,6 +527,11 @@ typedef struct drm_i915_private {
        u32 saveMCHBAR_RENDER_STANDBY;
 
        struct {
+               /** Bridge to intel-gtt-ko */
+               struct intel_gtt *gtt;
+               /** Memory allocator for GTT stolen memory */
+               struct drm_mm vram;
+               /** Memory allocator for GTT */
                struct drm_mm gtt_space;
 
                struct io_mapping *gtt_mapping;
@@ -521,8 +546,6 @@ typedef struct drm_i915_private {
                 */
                struct list_head shrink_list;
 
-               spinlock_t active_list_lock;
-
                /**
                 * List of objects which are not in the ringbuffer but which
                 * still have a write_domain which needs to be flushed before
@@ -555,6 +578,12 @@ typedef struct drm_i915_private {
                 */
                struct list_head inactive_list;
 
+               /**
+                * LRU list of objects which are not in the ringbuffer but
+                * are still pinned in the GTT.
+                */
+               struct list_head pinned_list;
+
                /** LRU list of objects with fence regs on them. */
                struct list_head fence_list;
 
@@ -611,6 +640,17 @@ typedef struct drm_i915_private {
 
                /* storage for physical objects */
                struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
+
+               uint32_t flush_rings;
+
+               /* accounting, useful for userland debugging */
+               size_t object_memory;
+               size_t pin_memory;
+               size_t gtt_memory;
+               size_t gtt_total;
+               u32 object_count;
+               u32 pin_count;
+               u32 gtt_count;
        } mm;
        struct sdvo_device_mapping sdvo_mappings[2];
        /* indicate whether the LVDS_BORDER should be enabled or not */
@@ -626,8 +666,6 @@ typedef struct drm_i915_private {
        /* Reclocking support */
        bool render_reclock_avail;
        bool lvds_downclock_avail;
-       /* indicate whether the LVDS EDID is OK */
-       bool lvds_edid_good;
        /* indicates the reduced downclock for LVDS*/
        int lvds_downclock;
        struct work_struct idle_work;
@@ -661,6 +699,8 @@ typedef struct drm_i915_private {
        struct drm_mm_node *compressed_fb;
        struct drm_mm_node *compressed_llb;
 
+       unsigned long last_gpu_reset;
+
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
 } drm_i915_private_t;
@@ -816,12 +856,14 @@ struct drm_i915_gem_request {
        /** global list entry for this request */
        struct list_head list;
 
+       struct drm_i915_file_private *file_priv;
        /** file_priv list entry for this request */
        struct list_head client_list;
 };
 
 struct drm_i915_file_private {
        struct {
+               struct spinlock lock;
                struct list_head request_list;
        } mm;
 };
@@ -862,7 +904,7 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
 extern int i915_emit_box(struct drm_device *dev,
                         struct drm_clip_rect *boxes,
                         int i, int DR1, int DR4);
-extern int i965_reset(struct drm_device *dev, u8 flags);
+extern int i915_reset(struct drm_device *dev, u8 flags);
 extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
@@ -871,7 +913,6 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
 
 /* i915_irq.c */
 void i915_hangcheck_elapsed(unsigned long data);
-void i915_destroy_error_state(struct drm_device *dev);
 extern int i915_irq_emit(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
 extern int i915_irq_wait(struct drm_device *dev, void *data,
@@ -908,6 +949,12 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
 
 void intel_enable_asle (struct drm_device *dev);
 
+#ifdef CONFIG_DEBUG_FS
+extern void i915_destroy_error_state(struct drm_device *dev);
+#else
+#define i915_destroy_error_state(x)
+#endif
+
 
 /* i915_mem.c */
 extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -922,6 +969,7 @@ extern void i915_mem_takedown(struct mem_block **heap);
 extern void i915_mem_release(struct drm_device * dev,
                             struct drm_file *file_priv, struct mem_block *heap);
 /* i915_gem.c */
+int i915_gem_check_is_wedged(struct drm_device *dev);
 int i915_gem_init_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 int i915_gem_create_ioctl(struct drm_device *dev, void *data,
@@ -972,13 +1020,22 @@ void i915_gem_object_unpin(struct drm_gem_object *obj);
 int i915_gem_object_unbind(struct drm_gem_object *obj);
 void i915_gem_release_mmap(struct drm_gem_object *obj);
 void i915_gem_lastclose(struct drm_device *dev);
-uint32_t i915_get_gem_seqno(struct drm_device *dev,
-               struct intel_ring_buffer *ring);
-bool i915_seqno_passed(uint32_t seq1, uint32_t seq2);
-int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
-int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);
+
+/**
+ * Returns true if seq1 is later than seq2.
+ */
+static inline bool
+i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+{
+       return (int32_t)(seq1 - seq2) >= 0;
+}
+
+int i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
+                                 bool interruptible);
+int i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
+                                 bool interruptible);
 void i915_gem_retire_requests(struct drm_device *dev);
-void i915_gem_retire_work_handler(struct work_struct *work);
+void i915_gem_reset(struct drm_device *dev);
 void i915_gem_clflush_object(struct drm_gem_object *obj);
 int i915_gem_object_set_domain(struct drm_gem_object *obj,
                               uint32_t read_domains,
@@ -990,16 +1047,18 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start,
 int i915_gpu_idle(struct drm_device *dev);
 int i915_gem_idle(struct drm_device *dev);
 uint32_t i915_add_request(struct drm_device *dev,
-               struct drm_file *file_priv,
-               uint32_t flush_domains,
-               struct intel_ring_buffer *ring);
+                         struct drm_file *file_priv,
+                         struct drm_i915_gem_request *request,
+                         struct intel_ring_buffer *ring);
 int i915_do_wait_request(struct drm_device *dev,
-               uint32_t seqno, int interruptible,
-               struct intel_ring_buffer *ring);
+                        uint32_t seqno,
+                        bool interruptible,
+                        struct intel_ring_buffer *ring);
 int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
                                      int write);
-int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj);
+int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
+                                        bool pipelined);
 int i915_gem_attach_phys_object(struct drm_device *dev,
                                struct drm_gem_object *obj,
                                int id,
@@ -1007,10 +1066,7 @@ int i915_gem_attach_phys_object(struct drm_device *dev,
 void i915_gem_detach_phys_object(struct drm_device *dev,
                                 struct drm_gem_object *obj);
 void i915_gem_free_all_phys_object(struct drm_device *dev);
-int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
-void i915_gem_object_put_pages(struct drm_gem_object *obj);
 void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
-int i915_gem_object_flush_write_domain(struct drm_gem_object *obj);
 
 void i915_gem_shrinker_init(void);
 void i915_gem_shrinker_exit(void);
@@ -1032,15 +1088,14 @@ bool i915_gem_object_fence_offset_ok(struct drm_gem_object *obj,
 /* i915_gem_debug.c */
 void i915_gem_dump_object(struct drm_gem_object *obj, int len,
                          const char *where, uint32_t mark);
-#if WATCH_INACTIVE
-void i915_verify_inactive(struct drm_device *dev, char *file, int line);
+#if WATCH_LISTS
+int i915_verify_lists(struct drm_device *dev);
 #else
-#define i915_verify_inactive(dev, file, line)
+#define i915_verify_lists(dev) 0
 #endif
 void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle);
 void i915_gem_dump_object(struct drm_gem_object *obj, int len,
                          const char *where, uint32_t mark);
-void i915_dump_lru(struct drm_device *dev, const char *where);
 
 /* i915_debugfs.c */
 int i915_debugfs_init(struct drm_minor *minor);
@@ -1054,19 +1109,31 @@ extern int i915_restore_state(struct drm_device *dev);
 extern int i915_save_state(struct drm_device *dev);
 extern int i915_restore_state(struct drm_device *dev);
 
+/* intel_i2c.c */
+extern int intel_setup_gmbus(struct drm_device *dev);
+extern void intel_teardown_gmbus(struct drm_device *dev);
+extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
+extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
+extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
+{
+       return container_of(adapter, struct intel_gmbus, adapter)->force_bit;
+}
+extern void intel_i2c_reset(struct drm_device *dev);
+
+/* intel_opregion.c */
+extern int intel_opregion_setup(struct drm_device *dev);
 #ifdef CONFIG_ACPI
-/* i915_opregion.c */
-extern int intel_opregion_init(struct drm_device *dev, int resume);
-extern void intel_opregion_free(struct drm_device *dev, int suspend);
-extern void opregion_asle_intr(struct drm_device *dev);
-extern void ironlake_opregion_gse_intr(struct drm_device *dev);
-extern void opregion_enable_asle(struct drm_device *dev);
+extern void intel_opregion_init(struct drm_device *dev);
+extern void intel_opregion_fini(struct drm_device *dev);
+extern void intel_opregion_asle_intr(struct drm_device *dev);
+extern void intel_opregion_gse_intr(struct drm_device *dev);
+extern void intel_opregion_enable_asle(struct drm_device *dev);
 #else
-static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; }
-static inline void intel_opregion_free(struct drm_device *dev, int suspend) { return; }
-static inline void opregion_asle_intr(struct drm_device *dev) { return; }
-static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; }
-static inline void opregion_enable_asle(struct drm_device *dev) { return; }
+static inline void intel_opregion_init(struct drm_device *dev) { return; }
+static inline void intel_opregion_fini(struct drm_device *dev) { return; }
+static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; }
+static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; }
+static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; }
 #endif
 
 /* modesetting */
@@ -1084,8 +1151,10 @@ extern void intel_detect_pch (struct drm_device *dev);
 extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
 
 /* overlay */
+#ifdef CONFIG_DEBUG_FS
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
 extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
+#endif
 
 /**
  * Lock test for when it's just for synchronization of ring access.
@@ -1099,8 +1168,26 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
                LOCK_TEST_WITH_RETURN(dev, file_priv);                  \
 } while (0)
 
-#define I915_READ(reg)          readl(dev_priv->regs + (reg))
-#define I915_WRITE(reg, val)     writel(val, dev_priv->regs + (reg))
+static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg)
+{
+       u32 val;
+
+       val = readl(dev_priv->regs + reg);
+       if (dev_priv->debug_flags & I915_DEBUG_READ)
+               printk(KERN_ERR "read 0x%08x from 0x%08x\n", val, reg);
+       return val;
+}
+
+static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
+                             u32 val)
+{
+       writel(val, dev_priv->regs + reg);
+       if (dev_priv->debug_flags & I915_DEBUG_WRITE)
+               printk(KERN_ERR "wrote 0x%08x to 0x%08x\n", val, reg);
+}
+
+#define I915_READ(reg)          i915_read(dev_priv, (reg))
+#define I915_WRITE(reg, val)    i915_write(dev_priv, (reg), (val))
 #define I915_READ16(reg)       readw(dev_priv->regs + (reg))
 #define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg))
 #define I915_READ8(reg)                readb(dev_priv->regs + (reg))
@@ -1110,6 +1197,11 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
 #define POSTING_READ(reg)      (void)I915_READ(reg)
 #define POSTING_READ16(reg)    (void)I915_READ16(reg)
 
+#define I915_DEBUG_ENABLE_IO() (dev_priv->debug_flags |= I915_DEBUG_READ | \
+                               I915_DEBUG_WRITE)
+#define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \
+                                                           I915_DEBUG_WRITE))
+
 #define I915_VERBOSE 0
 
 #define BEGIN_LP_RING(n)  do { \
@@ -1166,8 +1258,6 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
 #define IS_I915GM(dev)         ((dev)->pci_device == 0x2592)
 #define IS_I945G(dev)          ((dev)->pci_device == 0x2772)
 #define IS_I945GM(dev)         (INTEL_INFO(dev)->is_i945gm)
-#define IS_I965G(dev)          (INTEL_INFO(dev)->is_i965g)
-#define IS_I965GM(dev)         (INTEL_INFO(dev)->is_i965gm)
 #define IS_BROADWATER(dev)     (INTEL_INFO(dev)->is_broadwater)
 #define IS_CRESTLINE(dev)      (INTEL_INFO(dev)->is_crestline)
 #define IS_GM45(dev)           ((dev)->pci_device == 0x2A42)
@@ -1179,7 +1269,6 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
 #define IS_IRONLAKE_D(dev)     ((dev)->pci_device == 0x0042)
 #define IS_IRONLAKE_M(dev)     ((dev)->pci_device == 0x0046)
 #define IS_IRONLAKE(dev)       (INTEL_INFO(dev)->is_ironlake)
-#define IS_I9XX(dev)           (INTEL_INFO(dev)->is_i9xx)
 #define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
 
 #define IS_GEN2(dev)   (INTEL_INFO(dev)->gen == 2)
@@ -1188,26 +1277,27 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove
 #define IS_GEN5(dev)   (INTEL_INFO(dev)->gen == 5)
 #define IS_GEN6(dev)   (INTEL_INFO(dev)->gen == 6)
 
-#define HAS_BSD(dev)            (IS_IRONLAKE(dev) || IS_G4X(dev))
+#define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
 #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
 
+#define HAS_OVERLAY(dev)               (INTEL_INFO(dev)->has_overlay)
+#define OVERLAY_NEEDS_PHYSICAL(dev)    (INTEL_INFO(dev)->overlay_needs_physical)
+
 /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
  * rows, which changed the alignment requirements and fence programming.
  */
-#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
+#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \
                                                      IS_I915GM(dev)))
-#define SUPPORTS_DIGITAL_OUTPUTS(dev)  (IS_I9XX(dev) && !IS_PINEVIEW(dev))
+#define SUPPORTS_DIGITAL_OUTPUTS(dev)  (!IS_GEN2(dev) && !IS_PINEVIEW(dev))
 #define SUPPORTS_INTEGRATED_HDMI(dev)  (IS_G4X(dev) || IS_IRONLAKE(dev))
 #define SUPPORTS_INTEGRATED_DP(dev)    (IS_G4X(dev) || IS_IRONLAKE(dev))
 #define SUPPORTS_EDP(dev)              (IS_IRONLAKE_M(dev))
-#define SUPPORTS_TV(dev)               (IS_I9XX(dev) && IS_MOBILE(dev) && \
-                                       !IS_IRONLAKE(dev) && !IS_PINEVIEW(dev) && \
-                                       !IS_GEN6(dev))
+#define SUPPORTS_TV(dev)               (INTEL_INFO(dev)->supports_tv)
 #define I915_HAS_HOTPLUG(dev)           (INTEL_INFO(dev)->has_hotplug)
 /* dsparb controlled by hw only */
 #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
 
-#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IRONLAKE(dev))
+#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2)
 #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
 #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
 #define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
index cf4ffbee1c00633a809a624a165a359082386975..100a7537980e1c65eb4f4c2f4d0c89b3224d5451 100644 (file)
@@ -37,7 +37,9 @@
 #include <linux/intel-gtt.h>
 
 static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj);
-static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
+
+static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
+                                                 bool pipelined);
 static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
 static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
 static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj,
@@ -46,7 +48,8 @@ static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
                                                     uint64_t offset,
                                                     uint64_t size);
 static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj);
-static int i915_gem_object_wait_rendering(struct drm_gem_object *obj);
+static int i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+                                         bool interruptible);
 static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
                                           unsigned alignment);
 static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
@@ -55,9 +58,111 @@ static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *o
                                struct drm_file *file_priv);
 static void i915_gem_free_object_tail(struct drm_gem_object *obj);
 
+static int
+i915_gem_object_get_pages(struct drm_gem_object *obj,
+                         gfp_t gfpmask);
+
+static void
+i915_gem_object_put_pages(struct drm_gem_object *obj);
+
 static LIST_HEAD(shrink_list);
 static DEFINE_SPINLOCK(shrink_list_lock);
 
+/* some bookkeeping */
+static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
+                                 size_t size)
+{
+       dev_priv->mm.object_count++;
+       dev_priv->mm.object_memory += size;
+}
+
+static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv,
+                                    size_t size)
+{
+       dev_priv->mm.object_count--;
+       dev_priv->mm.object_memory -= size;
+}
+
+static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv,
+                                 size_t size)
+{
+       dev_priv->mm.gtt_count++;
+       dev_priv->mm.gtt_memory += size;
+}
+
+static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv,
+                                    size_t size)
+{
+       dev_priv->mm.gtt_count--;
+       dev_priv->mm.gtt_memory -= size;
+}
+
+static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv,
+                                 size_t size)
+{
+       dev_priv->mm.pin_count++;
+       dev_priv->mm.pin_memory += size;
+}
+
+static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv,
+                                    size_t size)
+{
+       dev_priv->mm.pin_count--;
+       dev_priv->mm.pin_memory -= size;
+}
+
+int
+i915_gem_check_is_wedged(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct completion *x = &dev_priv->error_completion;
+       unsigned long flags;
+       int ret;
+
+       if (!atomic_read(&dev_priv->mm.wedged))
+               return 0;
+
+       ret = wait_for_completion_interruptible(x);
+       if (ret)
+               return ret;
+
+       /* Success, we reset the GPU! */
+       if (!atomic_read(&dev_priv->mm.wedged))
+               return 0;
+
+       /* GPU is hung, bump the completion count to account for
+        * the token we just consumed so that we never hit zero and
+        * end up waiting upon a subsequent completion event that
+        * will never happen.
+        */
+       spin_lock_irqsave(&x->wait.lock, flags);
+       x->done++;
+       spin_unlock_irqrestore(&x->wait.lock, flags);
+       return -EIO;
+}
+
+static int i915_mutex_lock_interruptible(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = i915_gem_check_is_wedged(dev);
+       if (ret)
+               return ret;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       if (atomic_read(&dev_priv->mm.wedged)) {
+               mutex_unlock(&dev->struct_mutex);
+               return -EAGAIN;
+       }
+
+       WARN_ON(i915_verify_lists(dev));
+       return 0;
+}
+
 static inline bool
 i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
 {
@@ -66,7 +171,8 @@ i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
                obj_priv->pin_count == 0;
 }
 
-int i915_gem_do_init(struct drm_device *dev, unsigned long start,
+int i915_gem_do_init(struct drm_device *dev,
+                    unsigned long start,
                     unsigned long end)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -80,7 +186,7 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start,
        drm_mm_init(&dev_priv->mm.gtt_space, start,
                    end - start);
 
-       dev->gtt_total = (uint32_t) (end - start);
+       dev_priv->mm.gtt_total = end - start;
 
        return 0;
 }
@@ -103,14 +209,16 @@ int
 i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
                            struct drm_file *file_priv)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_get_aperture *args = data;
 
        if (!(dev->driver->driver_features & DRIVER_GEM))
                return -ENODEV;
 
-       args->aper_size = dev->gtt_total;
-       args->aper_available_size = (args->aper_size -
-                                    atomic_read(&dev->pin_memory));
+       mutex_lock(&dev->struct_mutex);
+       args->aper_size = dev_priv->mm.gtt_total;
+       args->aper_available_size = args->aper_size - dev_priv->mm.pin_memory;
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
@@ -136,14 +244,12 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
                return -ENOMEM;
 
        ret = drm_gem_handle_create(file_priv, obj, &handle);
+       /* drop reference from allocate - handle holds it now */
+       drm_gem_object_unreference_unlocked(obj);
        if (ret) {
-               drm_gem_object_unreference_unlocked(obj);
                return ret;
        }
 
-       /* Sink the floating reference from kref_init(handlecount) */
-       drm_gem_object_handle_unreference_unlocked(obj);
-
        args->handle = handle;
        return 0;
 }
@@ -265,7 +371,9 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj,
        user_data = (char __user *) (uintptr_t) args->data_ptr;
        remain = args->size;
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
 
        ret = i915_gem_object_get_pages(obj, 0);
        if (ret != 0)
@@ -384,7 +492,9 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
 
        do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               goto fail_put_user_pages;
 
        ret = i915_gem_object_get_pages_or_evict(obj);
        if (ret)
@@ -464,21 +574,27 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_pread *args = data;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
-       int ret;
+       int ret = 0;
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
                return -ENOENT;
        obj_priv = to_intel_bo(obj);
 
-       /* Bounds check source.
-        *
-        * XXX: This could use review for overflow issues...
-        */
-       if (args->offset > obj->size || args->size > obj->size ||
-           args->offset + args->size > obj->size) {
-               drm_gem_object_unreference_unlocked(obj);
-               return -EINVAL;
+       /* Bounds check source.  */
+       if (args->offset > obj->size || args->size > obj->size - args->offset) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (args->size == 0)
+               goto out;
+
+       if (!access_ok(VERIFY_WRITE,
+                      (char __user *)(uintptr_t)args->data_ptr,
+                      args->size)) {
+               ret = -EFAULT;
+               goto out;
        }
 
        if (i915_gem_object_needs_bit17_swizzle(obj)) {
@@ -490,8 +606,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
                                                        file_priv);
        }
 
+out:
        drm_gem_object_unreference_unlocked(obj);
-
        return ret;
 }
 
@@ -580,11 +696,11 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
 
        user_data = (char __user *) (uintptr_t) args->data_ptr;
        remain = args->size;
-       if (!access_ok(VERIFY_READ, user_data, remain))
-               return -EFAULT;
 
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
 
-       mutex_lock(&dev->struct_mutex);
        ret = i915_gem_object_pin(obj, 0);
        if (ret) {
                mutex_unlock(&dev->struct_mutex);
@@ -679,7 +795,10 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
                goto out_unpin_pages;
        }
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               goto out_unpin_pages;
+
        ret = i915_gem_object_pin(obj, 0);
        if (ret)
                goto out_unlock;
@@ -753,7 +872,9 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj,
        user_data = (char __user *) (uintptr_t) args->data_ptr;
        remain = args->size;
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ret;
 
        ret = i915_gem_object_get_pages(obj, 0);
        if (ret != 0)
@@ -849,7 +970,9 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
 
        do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               goto fail_put_user_pages;
 
        ret = i915_gem_object_get_pages_or_evict(obj);
        if (ret)
@@ -934,14 +1057,20 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
                return -ENOENT;
        obj_priv = to_intel_bo(obj);
 
-       /* Bounds check destination.
-        *
-        * XXX: This could use review for overflow issues...
-        */
-       if (args->offset > obj->size || args->size > obj->size ||
-           args->offset + args->size > obj->size) {
-               drm_gem_object_unreference_unlocked(obj);
-               return -EINVAL;
+       /* Bounds check destination. */
+       if (args->offset > obj->size || args->size > obj->size - args->offset) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (args->size == 0)
+               goto out;
+
+       if (!access_ok(VERIFY_READ,
+                      (char __user *)(uintptr_t)args->data_ptr,
+                      args->size)) {
+               ret = -EFAULT;
+               goto out;
        }
 
        /* We can only do the GTT pwrite on untiled buffers, as otherwise
@@ -953,7 +1082,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
        if (obj_priv->phys_obj)
                ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
        else if (obj_priv->tiling_mode == I915_TILING_NONE &&
-                dev->gtt_total != 0 &&
+                obj_priv->gtt_space &&
                 obj->write_domain != I915_GEM_DOMAIN_CPU) {
                ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv);
                if (ret == -EFAULT) {
@@ -975,8 +1104,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
                DRM_INFO("pwrite failed %d\n", ret);
 #endif
 
+out:
        drm_gem_object_unreference_unlocked(obj);
-
        return ret;
 }
 
@@ -1017,14 +1146,14 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
                return -ENOENT;
        obj_priv = to_intel_bo(obj);
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
 
        intel_mark_busy(dev, obj);
 
-#if WATCH_BUF
-       DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n",
-                obj, obj->size, read_domains, write_domain);
-#endif
        if (read_domains & I915_GEM_DOMAIN_GTT) {
                ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
 
@@ -1048,7 +1177,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
                ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
        }
 
-       
        /* Maintain LRU order of "inactive" objects */
        if (ret == 0 && i915_gem_object_is_inactive(obj_priv))
                list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
@@ -1067,27 +1195,23 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 {
        struct drm_i915_gem_sw_finish *args = data;
        struct drm_gem_object *obj;
-       struct drm_i915_gem_object *obj_priv;
        int ret = 0;
 
        if (!(dev->driver->driver_features & DRIVER_GEM))
                return -ENODEV;
 
-       mutex_lock(&dev->struct_mutex);
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-       if (obj == NULL) {
-               mutex_unlock(&dev->struct_mutex);
+       if (obj == NULL)
                return -ENOENT;
-       }
 
-#if WATCH_BUF
-       DRM_INFO("%s: sw_finish %d (%p %zd)\n",
-                __func__, args->handle, obj, obj->size);
-#endif
-       obj_priv = to_intel_bo(obj);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
 
        /* Pinned buffers may be scanout, so flush the cache */
-       if (obj_priv->pin_count)
+       if (to_intel_bo(obj)->pin_count)
                i915_gem_object_flush_cpu_write_domain(obj);
 
        drm_gem_object_unreference(obj);
@@ -1179,7 +1303,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        /* Need a new fence register? */
        if (obj_priv->tiling_mode != I915_TILING_NONE) {
-               ret = i915_gem_object_get_fence_reg(obj);
+               ret = i915_gem_object_get_fence_reg(obj, true);
                if (ret)
                        goto unlock;
        }
@@ -1244,7 +1368,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
                                                    obj->size / PAGE_SIZE, 0, 0);
        if (!list->file_offset_node) {
                DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
-               ret = -ENOMEM;
+               ret = -ENOSPC;
                goto out_free_list;
        }
 
@@ -1256,9 +1380,9 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
        }
 
        list->hash.key = list->file_offset_node->start;
-       if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) {
+       ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
+       if (ret) {
                DRM_ERROR("failed to add to map hash\n");
-               ret = -ENOMEM;
                goto out_free_mm;
        }
 
@@ -1343,14 +1467,14 @@ i915_gem_get_gtt_alignment(struct drm_gem_object *obj)
         * Minimum alignment is 4k (GTT page size), but might be greater
         * if a fence register is needed for the object.
         */
-       if (IS_I965G(dev) || obj_priv->tiling_mode == I915_TILING_NONE)
+       if (INTEL_INFO(dev)->gen >= 4 || obj_priv->tiling_mode == I915_TILING_NONE)
                return 4096;
 
        /*
         * Previous chips need to be aligned to the size of the smallest
         * fence register that can contain the object.
         */
-       if (IS_I9XX(dev))
+       if (INTEL_INFO(dev)->gen == 3)
                start = 1024*1024;
        else
                start = 512*1024;
@@ -1392,7 +1516,11 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
        if (obj == NULL)
                return -ENOENT;
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
 
        obj_priv = to_intel_bo(obj);
 
@@ -1434,7 +1562,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
        return 0;
 }
 
-void
+static void
 i915_gem_object_put_pages(struct drm_gem_object *obj)
 {
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
@@ -1468,13 +1596,24 @@ i915_gem_object_put_pages(struct drm_gem_object *obj)
        obj_priv->pages = NULL;
 }
 
+static uint32_t
+i915_gem_next_request_seqno(struct drm_device *dev,
+                           struct intel_ring_buffer *ring)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       ring->outstanding_lazy_request = true;
+       return dev_priv->next_seqno;
+}
+
 static void
-i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno,
+i915_gem_object_move_to_active(struct drm_gem_object *obj,
                               struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = obj->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+       uint32_t seqno = i915_gem_next_request_seqno(dev, ring);
+
        BUG_ON(ring == NULL);
        obj_priv->ring = ring;
 
@@ -1483,10 +1622,9 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno,
                drm_gem_object_reference(obj);
                obj_priv->active = 1;
        }
+
        /* Move from whatever list we were on to the tail of execution. */
-       spin_lock(&dev_priv->mm.active_list_lock);
        list_move_tail(&obj_priv->list, &ring->active_list);
-       spin_unlock(&dev_priv->mm.active_list_lock);
        obj_priv->last_rendering_seqno = seqno;
 }
 
@@ -1536,9 +1674,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
        if (obj_priv->pin_count != 0)
-               list_del_init(&obj_priv->list);
+               list_move_tail(&obj_priv->list, &dev_priv->mm.pinned_list);
        else
                list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
 
@@ -1550,12 +1687,12 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
                obj_priv->active = 0;
                drm_gem_object_unreference(obj);
        }
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       WARN_ON(i915_verify_lists(dev));
 }
 
 static void
 i915_gem_process_flushing_list(struct drm_device *dev,
-                              uint32_t flush_domains, uint32_t seqno,
+                              uint32_t flush_domains,
                               struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -1566,14 +1703,13 @@ i915_gem_process_flushing_list(struct drm_device *dev,
                                 gpu_write_list) {
                struct drm_gem_object *obj = &obj_priv->base;
 
-               if ((obj->write_domain & flush_domains) ==
-                   obj->write_domain &&
-                   obj_priv->ring->ring_flag == ring->ring_flag) {
+               if (obj->write_domain & flush_domains &&
+                   obj_priv->ring == ring) {
                        uint32_t old_write_domain = obj->write_domain;
 
                        obj->write_domain = 0;
                        list_del_init(&obj_priv->gpu_write_list);
-                       i915_gem_object_move_to_active(obj, seqno, ring);
+                       i915_gem_object_move_to_active(obj, ring);
 
                        /* update the fence lru list */
                        if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
@@ -1591,23 +1727,27 @@ i915_gem_process_flushing_list(struct drm_device *dev,
 }
 
 uint32_t
-i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
-                uint32_t flush_domains, struct intel_ring_buffer *ring)
+i915_add_request(struct drm_device *dev,
+                struct drm_file *file,
+                struct drm_i915_gem_request *request,
+                struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_i915_file_private *i915_file_priv = NULL;
-       struct drm_i915_gem_request *request;
+       struct drm_i915_file_private *file_priv = NULL;
        uint32_t seqno;
        int was_empty;
 
-       if (file_priv != NULL)
-               i915_file_priv = file_priv->driver_priv;
+       if (file != NULL)
+               file_priv = file->driver_priv;
 
-       request = kzalloc(sizeof(*request), GFP_KERNEL);
-       if (request == NULL)
-               return 0;
+       if (request == NULL) {
+               request = kzalloc(sizeof(*request), GFP_KERNEL);
+               if (request == NULL)
+                       return 0;
+       }
 
-       seqno = ring->add_request(dev, ring, file_priv, flush_domains);
+       seqno = ring->add_request(dev, ring, 0);
+       ring->outstanding_lazy_request = false;
 
        request->seqno = seqno;
        request->ring = ring;
@@ -1615,23 +1755,20 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
        was_empty = list_empty(&ring->request_list);
        list_add_tail(&request->list, &ring->request_list);
 
-       if (i915_file_priv) {
+       if (file_priv) {
+               spin_lock(&file_priv->mm.lock);
+               request->file_priv = file_priv;
                list_add_tail(&request->client_list,
-                             &i915_file_priv->mm.request_list);
-       } else {
-               INIT_LIST_HEAD(&request->client_list);
+                             &file_priv->mm.request_list);
+               spin_unlock(&file_priv->mm.lock);
        }
 
-       /* Associate any objects on the flushing list matching the write
-        * domain we're flushing with our flush.
-        */
-       if (flush_domains != 0) 
-               i915_gem_process_flushing_list(dev, flush_domains, seqno, ring);
-
        if (!dev_priv->mm.suspended) {
-               mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+               mod_timer(&dev_priv->hangcheck_timer,
+                         jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
                if (was_empty)
-                       queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+                       queue_delayed_work(dev_priv->wq,
+                                          &dev_priv->mm.retire_work, HZ);
        }
        return seqno;
 }
@@ -1642,91 +1779,105 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
  * Ensures that all commands in the ring are finished
  * before signalling the CPU
  */
-static uint32_t
+static void
 i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring)
 {
        uint32_t flush_domains = 0;
 
        /* The sampler always gets flushed on i965 (sigh) */
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                flush_domains |= I915_GEM_DOMAIN_SAMPLER;
 
        ring->flush(dev, ring,
                        I915_GEM_DOMAIN_COMMAND, flush_domains);
-       return flush_domains;
 }
 
-/**
- * Moves buffers associated only with the given active seqno from the active
- * to inactive list, potentially freeing them.
- */
-static void
-i915_gem_retire_request(struct drm_device *dev,
-                       struct drm_i915_gem_request *request)
+static inline void
+i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_file_private *file_priv = request->file_priv;
 
-       trace_i915_gem_request_retire(dev, request->seqno);
+       if (!file_priv)
+               return;
 
-       /* Move any buffers on the active list that are no longer referenced
-        * by the ringbuffer to the flushing/inactive lists as appropriate.
-        */
-       spin_lock(&dev_priv->mm.active_list_lock);
-       while (!list_empty(&request->ring->active_list)) {
-               struct drm_gem_object *obj;
+       spin_lock(&file_priv->mm.lock);
+       list_del(&request->client_list);
+       request->file_priv = NULL;
+       spin_unlock(&file_priv->mm.lock);
+}
+
+static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
+                                     struct intel_ring_buffer *ring)
+{
+       while (!list_empty(&ring->request_list)) {
+               struct drm_i915_gem_request *request;
+
+               request = list_first_entry(&ring->request_list,
+                                          struct drm_i915_gem_request,
+                                          list);
+
+               list_del(&request->list);
+               i915_gem_request_remove_from_client(request);
+               kfree(request);
+       }
+
+       while (!list_empty(&ring->active_list)) {
                struct drm_i915_gem_object *obj_priv;
 
-               obj_priv = list_first_entry(&request->ring->active_list,
+               obj_priv = list_first_entry(&ring->active_list,
                                            struct drm_i915_gem_object,
                                            list);
-               obj = &obj_priv->base;
 
-               /* If the seqno being retired doesn't match the oldest in the
-                * list, then the oldest in the list must still be newer than
-                * this seqno.
-                */
-               if (obj_priv->last_rendering_seqno != request->seqno)
-                       goto out;
-
-#if WATCH_LRU
-               DRM_INFO("%s: retire %d moves to inactive list %p\n",
-                        __func__, request->seqno, obj);
-#endif
-
-               if (obj->write_domain != 0)
-                       i915_gem_object_move_to_flushing(obj);
-               else {
-                       /* Take a reference on the object so it won't be
-                        * freed while the spinlock is held.  The list
-                        * protection for this spinlock is safe when breaking
-                        * the lock like this since the next thing we do
-                        * is just get the head of the list again.
-                        */
-                       drm_gem_object_reference(obj);
-                       i915_gem_object_move_to_inactive(obj);
-                       spin_unlock(&dev_priv->mm.active_list_lock);
-                       drm_gem_object_unreference(obj);
-                       spin_lock(&dev_priv->mm.active_list_lock);
-               }
+               obj_priv->base.write_domain = 0;
+               list_del_init(&obj_priv->gpu_write_list);
+               i915_gem_object_move_to_inactive(&obj_priv->base);
        }
-out:
-       spin_unlock(&dev_priv->mm.active_list_lock);
 }
 
-/**
- * Returns true if seq1 is later than seq2.
- */
-bool
-i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+void i915_gem_reset(struct drm_device *dev)
 {
-       return (int32_t)(seq1 - seq2) >= 0;
-}
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv;
+       int i;
 
-uint32_t
-i915_get_gem_seqno(struct drm_device *dev,
-                  struct intel_ring_buffer *ring)
-{
-       return ring->get_gem_seqno(dev, ring);
+       i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring);
+       if (HAS_BSD(dev))
+               i915_gem_reset_ring_lists(dev_priv, &dev_priv->bsd_ring);
+
+       /* Remove anything from the flushing lists. The GPU cache is likely
+        * to be lost on reset along with the data, so simply move the
+        * lost bo to the inactive list.
+        */
+       while (!list_empty(&dev_priv->mm.flushing_list)) {
+               obj_priv = list_first_entry(&dev_priv->mm.flushing_list,
+                                           struct drm_i915_gem_object,
+                                           list);
+
+               obj_priv->base.write_domain = 0;
+               list_del_init(&obj_priv->gpu_write_list);
+               i915_gem_object_move_to_inactive(&obj_priv->base);
+       }
+
+       /* Move everything out of the GPU domains to ensure we do any
+        * necessary invalidation upon reuse.
+        */
+       list_for_each_entry(obj_priv,
+                           &dev_priv->mm.inactive_list,
+                           list)
+       {
+               obj_priv->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
+       }
+
+       /* The fence registers are invalidated so clear them out */
+       for (i = 0; i < 16; i++) {
+               struct drm_i915_fence_reg *reg;
+
+               reg = &dev_priv->fence_regs[i];
+               if (!reg->obj)
+                       continue;
+
+               i915_gem_clear_fence_reg(reg->obj);
+       }
 }
 
 /**
@@ -1739,38 +1890,58 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
        drm_i915_private_t *dev_priv = dev->dev_private;
        uint32_t seqno;
 
-       if (!ring->status_page.page_addr
-                       || list_empty(&ring->request_list))
+       if (!ring->status_page.page_addr ||
+           list_empty(&ring->request_list))
                return;
 
-       seqno = i915_get_gem_seqno(dev, ring);
+       WARN_ON(i915_verify_lists(dev));
 
+       seqno = ring->get_seqno(dev, ring);
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
-               uint32_t retiring_seqno;
 
                request = list_first_entry(&ring->request_list,
                                           struct drm_i915_gem_request,
                                           list);
-               retiring_seqno = request->seqno;
 
-               if (i915_seqno_passed(seqno, retiring_seqno) ||
-                   atomic_read(&dev_priv->mm.wedged)) {
-                       i915_gem_retire_request(dev, request);
+               if (!i915_seqno_passed(seqno, request->seqno))
+                       break;
+
+               trace_i915_gem_request_retire(dev, request->seqno);
+
+               list_del(&request->list);
+               i915_gem_request_remove_from_client(request);
+               kfree(request);
+       }
+
+       /* Move any buffers on the active list that are no longer referenced
+        * by the ringbuffer to the flushing/inactive lists as appropriate.
+        */
+       while (!list_empty(&ring->active_list)) {
+               struct drm_gem_object *obj;
+               struct drm_i915_gem_object *obj_priv;
+
+               obj_priv = list_first_entry(&ring->active_list,
+                                           struct drm_i915_gem_object,
+                                           list);
 
-                       list_del(&request->list);
-                       list_del(&request->client_list);
-                       kfree(request);
-               } else
+               if (!i915_seqno_passed(seqno, obj_priv->last_rendering_seqno))
                        break;
+
+               obj = &obj_priv->base;
+               if (obj->write_domain != 0)
+                       i915_gem_object_move_to_flushing(obj);
+               else
+                       i915_gem_object_move_to_inactive(obj);
        }
 
        if (unlikely (dev_priv->trace_irq_seqno &&
                      i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
-
                ring->user_irq_put(dev, ring);
                dev_priv->trace_irq_seqno = 0;
        }
+
+       WARN_ON(i915_verify_lists(dev));
 }
 
 void
@@ -1797,7 +1968,7 @@ i915_gem_retire_requests(struct drm_device *dev)
                i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
 }
 
-void
+static void
 i915_gem_retire_work_handler(struct work_struct *work)
 {
        drm_i915_private_t *dev_priv;
@@ -1807,7 +1978,12 @@ i915_gem_retire_work_handler(struct work_struct *work)
                                mm.retire_work.work);
        dev = dev_priv->dev;
 
-       mutex_lock(&dev->struct_mutex);
+       /* Come back later if the device is busy... */
+       if (!mutex_trylock(&dev->struct_mutex)) {
+               queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+               return;
+       }
+
        i915_gem_retire_requests(dev);
 
        if (!dev_priv->mm.suspended &&
@@ -1820,7 +1996,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
 
 int
 i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
-               int interruptible, struct intel_ring_buffer *ring)
+                    bool interruptible, struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 ier;
@@ -1829,9 +2005,16 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
        BUG_ON(seqno == 0);
 
        if (atomic_read(&dev_priv->mm.wedged))
-               return -EIO;
+               return -EAGAIN;
+
+       if (ring->outstanding_lazy_request) {
+               seqno = i915_add_request(dev, NULL, NULL, ring);
+               if (seqno == 0)
+                       return -ENOMEM;
+       }
+       BUG_ON(seqno == dev_priv->next_seqno);
 
-       if (!i915_seqno_passed(ring->get_gem_seqno(dev, ring), seqno)) {
+       if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
                if (HAS_PCH_SPLIT(dev))
                        ier = I915_READ(DEIER) | I915_READ(GTIER);
                else
@@ -1850,12 +2033,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
                if (interruptible)
                        ret = wait_event_interruptible(ring->irq_queue,
                                i915_seqno_passed(
-                                       ring->get_gem_seqno(dev, ring), seqno)
+                                       ring->get_seqno(dev, ring), seqno)
                                || atomic_read(&dev_priv->mm.wedged));
                else
                        wait_event(ring->irq_queue,
                                i915_seqno_passed(
-                                       ring->get_gem_seqno(dev, ring), seqno)
+                                       ring->get_seqno(dev, ring), seqno)
                                || atomic_read(&dev_priv->mm.wedged));
 
                ring->user_irq_put(dev, ring);
@@ -1864,11 +2047,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
                trace_i915_gem_request_wait_end(dev, seqno);
        }
        if (atomic_read(&dev_priv->mm.wedged))
-               ret = -EIO;
+               ret = -EAGAIN;
 
        if (ret && ret != -ERESTARTSYS)
-               DRM_ERROR("%s returns %d (awaiting %d at %d)\n",
-                         __func__, ret, seqno, ring->get_gem_seqno(dev, ring));
+               DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n",
+                         __func__, ret, seqno, ring->get_seqno(dev, ring),
+                         dev_priv->next_seqno);
 
        /* Directly dispatch request retiring.  While we have the work queue
         * to handle this, the waiter on a request often wants an associated
@@ -1887,27 +2071,44 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
  */
 static int
 i915_wait_request(struct drm_device *dev, uint32_t seqno,
-               struct intel_ring_buffer *ring)
+                 struct intel_ring_buffer *ring)
 {
        return i915_do_wait_request(dev, seqno, 1, ring);
 }
 
+static void
+i915_gem_flush_ring(struct drm_device *dev,
+                   struct drm_file *file_priv,
+                   struct intel_ring_buffer *ring,
+                   uint32_t invalidate_domains,
+                   uint32_t flush_domains)
+{
+       ring->flush(dev, ring, invalidate_domains, flush_domains);
+       i915_gem_process_flushing_list(dev, flush_domains, ring);
+}
+
 static void
 i915_gem_flush(struct drm_device *dev,
+              struct drm_file *file_priv,
               uint32_t invalidate_domains,
-              uint32_t flush_domains)
+              uint32_t flush_domains,
+              uint32_t flush_rings)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+
        if (flush_domains & I915_GEM_DOMAIN_CPU)
                drm_agp_chipset_flush(dev);
-       dev_priv->render_ring.flush(dev, &dev_priv->render_ring,
-                       invalidate_domains,
-                       flush_domains);
 
-       if (HAS_BSD(dev))
-               dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring,
-                               invalidate_domains,
-                               flush_domains);
+       if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) {
+               if (flush_rings & RING_RENDER)
+                       i915_gem_flush_ring(dev, file_priv,
+                                           &dev_priv->render_ring,
+                                           invalidate_domains, flush_domains);
+               if (flush_rings & RING_BSD)
+                       i915_gem_flush_ring(dev, file_priv,
+                                           &dev_priv->bsd_ring,
+                                           invalidate_domains, flush_domains);
+       }
 }
 
 /**
@@ -1915,7 +2116,8 @@ i915_gem_flush(struct drm_device *dev,
  * safe to unbind from the GTT or access from the CPU.
  */
 static int
-i915_gem_object_wait_rendering(struct drm_gem_object *obj)
+i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+                              bool interruptible)
 {
        struct drm_device *dev = obj->dev;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
@@ -1930,13 +2132,11 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj)
         * it.
         */
        if (obj_priv->active) {
-#if WATCH_BUF
-               DRM_INFO("%s: object %p wait for seqno %08x\n",
-                         __func__, obj, obj_priv->last_rendering_seqno);
-#endif
-               ret = i915_wait_request(dev,
-                               obj_priv->last_rendering_seqno, obj_priv->ring);
-               if (ret != 0)
+               ret = i915_do_wait_request(dev,
+                                          obj_priv->last_rendering_seqno,
+                                          interruptible,
+                                          obj_priv->ring);
+               if (ret)
                        return ret;
        }
 
@@ -1950,14 +2150,10 @@ int
 i915_gem_object_unbind(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        int ret = 0;
 
-#if WATCH_BUF
-       DRM_INFO("%s:%d %p\n", __func__, __LINE__, obj);
-       DRM_INFO("gtt_space %p\n", obj_priv->gtt_space);
-#endif
        if (obj_priv->gtt_space == NULL)
                return 0;
 
@@ -1982,33 +2178,26 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
         * should be safe and we need to cleanup or else we might
         * cause memory corruption through use-after-free.
         */
+       if (ret) {
+               i915_gem_clflush_object(obj);
+               obj->read_domains = obj->write_domain = I915_GEM_DOMAIN_CPU;
+       }
 
        /* release the fence reg _after_ flushing */
        if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
                i915_gem_clear_fence_reg(obj);
 
-       if (obj_priv->agp_mem != NULL) {
-               drm_unbind_agp(obj_priv->agp_mem);
-               drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
-               obj_priv->agp_mem = NULL;
-       }
+       drm_unbind_agp(obj_priv->agp_mem);
+       drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
 
        i915_gem_object_put_pages(obj);
        BUG_ON(obj_priv->pages_refcount);
 
-       if (obj_priv->gtt_space) {
-               atomic_dec(&dev->gtt_count);
-               atomic_sub(obj->size, &dev->gtt_memory);
+       i915_gem_info_remove_gtt(dev_priv, obj->size);
+       list_del_init(&obj_priv->list);
 
-               drm_mm_put_block(obj_priv->gtt_space);
-               obj_priv->gtt_space = NULL;
-       }
-
-       /* Remove ourselves from the LRU list if present. */
-       spin_lock(&dev_priv->mm.active_list_lock);
-       if (!list_empty(&obj_priv->list))
-               list_del_init(&obj_priv->list);
-       spin_unlock(&dev_priv->mm.active_list_lock);
+       drm_mm_put_block(obj_priv->gtt_space);
+       obj_priv->gtt_space = NULL;
 
        if (i915_gem_object_is_purgeable(obj_priv))
                i915_gem_object_truncate(obj);
@@ -2018,48 +2207,45 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
        return ret;
 }
 
+static int i915_ring_idle(struct drm_device *dev,
+                         struct intel_ring_buffer *ring)
+{
+       i915_gem_flush_ring(dev, NULL, ring,
+                           I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+       return i915_wait_request(dev,
+                                i915_gem_next_request_seqno(dev, ring),
+                                ring);
+}
+
 int
 i915_gpu_idle(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        bool lists_empty;
-       uint32_t seqno1, seqno2;
        int ret;
 
-       spin_lock(&dev_priv->mm.active_list_lock);
        lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
                       list_empty(&dev_priv->render_ring.active_list) &&
                       (!HAS_BSD(dev) ||
                        list_empty(&dev_priv->bsd_ring.active_list)));
-       spin_unlock(&dev_priv->mm.active_list_lock);
-
        if (lists_empty)
                return 0;
 
        /* Flush everything onto the inactive list. */
-       i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
-       seqno1 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
-                       &dev_priv->render_ring);
-       if (seqno1 == 0)
-               return -ENOMEM;
-       ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring);
+       ret = i915_ring_idle(dev, &dev_priv->render_ring);
+       if (ret)
+               return ret;
 
        if (HAS_BSD(dev)) {
-               seqno2 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
-                               &dev_priv->bsd_ring);
-               if (seqno2 == 0)
-                       return -ENOMEM;
-
-               ret = i915_wait_request(dev, seqno2, &dev_priv->bsd_ring);
+               ret = i915_ring_idle(dev, &dev_priv->bsd_ring);
                if (ret)
                        return ret;
        }
 
-
-       return ret;
+       return 0;
 }
 
-int
+static int
 i915_gem_object_get_pages(struct drm_gem_object *obj,
                          gfp_t gfpmask)
 {
@@ -2239,7 +2425,8 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
        I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
 }
 
-static int i915_find_fence_reg(struct drm_device *dev)
+static int i915_find_fence_reg(struct drm_device *dev,
+                              bool interruptible)
 {
        struct drm_i915_fence_reg *reg = NULL;
        struct drm_i915_gem_object *obj_priv = NULL;
@@ -2284,7 +2471,7 @@ static int i915_find_fence_reg(struct drm_device *dev)
         * private reference to obj like the other callers of put_fence_reg
         * (set_tiling ioctl) do. */
        drm_gem_object_reference(obj);
-       ret = i915_gem_object_put_fence_reg(obj);
+       ret = i915_gem_object_put_fence_reg(obj, interruptible);
        drm_gem_object_unreference(obj);
        if (ret != 0)
                return ret;
@@ -2306,7 +2493,8 @@ static int i915_find_fence_reg(struct drm_device *dev)
  * and tiling format.
  */
 int
-i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
+i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
+                             bool interruptible)
 {
        struct drm_device *dev = obj->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2341,7 +2529,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
                break;
        }
 
-       ret = i915_find_fence_reg(dev);
+       ret = i915_find_fence_reg(dev, interruptible);
        if (ret < 0)
                return ret;
 
@@ -2400,7 +2588,7 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
                I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0);
                break;
        case 3:
-               if (obj_priv->fence_reg > 8)
+               if (obj_priv->fence_reg >= 8)
                        fence_reg = FENCE_REG_945_8 + (obj_priv->fence_reg - 8) * 4;
                else
        case 2:
@@ -2419,15 +2607,19 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
  * i915_gem_object_put_fence_reg - waits on outstanding fenced access
  * to the buffer to finish, and then resets the fence register.
  * @obj: tiled object holding a fence register.
+ * @bool: whether the wait upon the fence is interruptible
  *
  * Zeroes out the fence register itself and clears out the associated
  * data structures in dev_priv and obj_priv.
  */
 int
-i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
+i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
+                             bool interruptible)
 {
        struct drm_device *dev = obj->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+       struct drm_i915_fence_reg *reg;
 
        if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
                return 0;
@@ -2442,20 +2634,23 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
         * therefore we must wait for any outstanding access to complete
         * before clearing the fence.
         */
-       if (!IS_I965G(dev)) {
+       reg = &dev_priv->fence_regs[obj_priv->fence_reg];
+       if (reg->gpu) {
                int ret;
 
-               ret = i915_gem_object_flush_gpu_write_domain(obj);
-               if (ret != 0)
+               ret = i915_gem_object_flush_gpu_write_domain(obj, true);
+               if (ret)
                        return ret;
 
-               ret = i915_gem_object_wait_rendering(obj);
-               if (ret != 0)
+               ret = i915_gem_object_wait_rendering(obj, interruptible);
+               if (ret)
                        return ret;
+
+               reg->gpu = false;
        }
 
        i915_gem_object_flush_gtt_write_domain(obj);
-       i915_gem_clear_fence_reg (obj);
+       i915_gem_clear_fence_reg(obj);
 
        return 0;
 }
@@ -2488,7 +2683,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
        /* If the object is bigger than the entire aperture, reject it early
         * before evicting everything in a vain attempt to find space.
         */
-       if (obj->size > dev->gtt_total) {
+       if (obj->size > dev_priv->mm.gtt_total) {
                DRM_ERROR("Attempting to bind an object larger than the aperture\n");
                return -E2BIG;
        }
@@ -2506,9 +2701,6 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                /* If the gtt is empty and we're still having trouble
                 * fitting our object in, we're out of memory.
                 */
-#if WATCH_LRU
-               DRM_INFO("%s: GTT full, evicting something\n", __func__);
-#endif
                ret = i915_gem_evict_something(dev, obj->size, alignment);
                if (ret)
                        return ret;
@@ -2516,10 +2708,6 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                goto search_free;
        }
 
-#if WATCH_BUF
-       DRM_INFO("Binding object of size %zd at 0x%08x\n",
-                obj->size, obj_priv->gtt_offset);
-#endif
        ret = i915_gem_object_get_pages(obj, gfpmask);
        if (ret) {
                drm_mm_put_block(obj_priv->gtt_space);
@@ -2564,11 +2752,10 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
 
                goto search_free;
        }
-       atomic_inc(&dev->gtt_count);
-       atomic_add(obj->size, &dev->gtt_memory);
 
        /* keep track of bounds object by adding it to the inactive list */
        list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+       i915_gem_info_add_gtt(dev_priv, obj->size);
 
        /* Assert that the object is not currently in any GPU domain. As it
         * wasn't in the GTT, there shouldn't be any way it could have been in
@@ -2601,25 +2788,30 @@ i915_gem_clflush_object(struct drm_gem_object *obj)
 
 /** Flushes any GPU write domain for the object if it's dirty. */
 static int
-i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
+i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
+                                      bool pipelined)
 {
        struct drm_device *dev = obj->dev;
        uint32_t old_write_domain;
-       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
        if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
                return 0;
 
        /* Queue the GPU write cache flushing we need. */
        old_write_domain = obj->write_domain;
-       i915_gem_flush(dev, 0, obj->write_domain);
-       if (i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring) == 0)
-               return -ENOMEM;
+       i915_gem_flush_ring(dev, NULL,
+                           to_intel_bo(obj)->ring,
+                           0, obj->write_domain);
+       BUG_ON(obj->write_domain);
 
        trace_i915_gem_object_change_domain(obj,
                                            obj->read_domains,
                                            old_write_domain);
-       return 0;
+
+       if (pipelined)
+               return 0;
+
+       return i915_gem_object_wait_rendering(obj, true);
 }
 
 /** Flushes the GTT write domain for the object if it's dirty. */
@@ -2663,26 +2855,6 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj)
                                            old_write_domain);
 }
 
-int
-i915_gem_object_flush_write_domain(struct drm_gem_object *obj)
-{
-       int ret = 0;
-
-       switch (obj->write_domain) {
-       case I915_GEM_DOMAIN_GTT:
-               i915_gem_object_flush_gtt_write_domain(obj);
-               break;
-       case I915_GEM_DOMAIN_CPU:
-               i915_gem_object_flush_cpu_write_domain(obj);
-               break;
-       default:
-               ret = i915_gem_object_flush_gpu_write_domain(obj);
-               break;
-       }
-
-       return ret;
-}
-
 /**
  * Moves a single object to the GTT read, and possibly write domain.
  *
@@ -2700,32 +2872,28 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
        if (obj_priv->gtt_space == NULL)
                return -EINVAL;
 
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
+       ret = i915_gem_object_flush_gpu_write_domain(obj, false);
        if (ret != 0)
                return ret;
 
-       /* Wait on any GPU rendering and flushing to occur. */
-       ret = i915_gem_object_wait_rendering(obj);
-       if (ret != 0)
-               return ret;
+       i915_gem_object_flush_cpu_write_domain(obj);
+
+       if (write) {
+               ret = i915_gem_object_wait_rendering(obj, true);
+               if (ret)
+                       return ret;
+       }
 
        old_write_domain = obj->write_domain;
        old_read_domains = obj->read_domains;
 
-       /* If we're writing through the GTT domain, then CPU and GPU caches
-        * will need to be invalidated at next use.
-        */
-       if (write)
-               obj->read_domains &= I915_GEM_DOMAIN_GTT;
-
-       i915_gem_object_flush_cpu_write_domain(obj);
-
        /* It should now be out of any other write domains, and we can update
         * the domain values for our changes.
         */
        BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
        obj->read_domains |= I915_GEM_DOMAIN_GTT;
        if (write) {
+               obj->read_domains = I915_GEM_DOMAIN_GTT;
                obj->write_domain = I915_GEM_DOMAIN_GTT;
                obj_priv->dirty = 1;
        }
@@ -2742,51 +2910,36 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
  * wait, as in modesetting process we're not supposed to be interrupted.
  */
 int
-i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
+i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
+                                    bool pipelined)
 {
-       struct drm_device *dev = obj->dev;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-       uint32_t old_write_domain, old_read_domains;
+       uint32_t old_read_domains;
        int ret;
 
        /* Not valid to be called on unbound objects. */
        if (obj_priv->gtt_space == NULL)
                return -EINVAL;
 
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
+       ret = i915_gem_object_flush_gpu_write_domain(obj, true);
        if (ret)
                return ret;
 
-       /* Wait on any GPU rendering and flushing to occur. */
-       if (obj_priv->active) {
-#if WATCH_BUF
-               DRM_INFO("%s: object %p wait for seqno %08x\n",
-                         __func__, obj, obj_priv->last_rendering_seqno);
-#endif
-               ret = i915_do_wait_request(dev,
-                               obj_priv->last_rendering_seqno,
-                               0,
-                               obj_priv->ring);
-               if (ret != 0)
+       /* Currently, we are always called from an non-interruptible context. */
+       if (!pipelined) {
+               ret = i915_gem_object_wait_rendering(obj, false);
+               if (ret)
                        return ret;
        }
 
        i915_gem_object_flush_cpu_write_domain(obj);
 
-       old_write_domain = obj->write_domain;
        old_read_domains = obj->read_domains;
-
-       /* It should now be out of any other write domains, and we can update
-        * the domain values for our changes.
-        */
-       BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
-       obj->read_domains = I915_GEM_DOMAIN_GTT;
-       obj->write_domain = I915_GEM_DOMAIN_GTT;
-       obj_priv->dirty = 1;
+       obj->read_domains |= I915_GEM_DOMAIN_GTT;
 
        trace_i915_gem_object_change_domain(obj,
                                            old_read_domains,
-                                           old_write_domain);
+                                           obj->write_domain);
 
        return 0;
 }
@@ -2803,12 +2956,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
        uint32_t old_write_domain, old_read_domains;
        int ret;
 
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
-       if (ret)
-               return ret;
-
-       /* Wait on any GPU rendering and flushing to occur. */
-       ret = i915_gem_object_wait_rendering(obj);
+       ret = i915_gem_object_flush_gpu_write_domain(obj, false);
        if (ret != 0)
                return ret;
 
@@ -2819,6 +2967,12 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
         */
        i915_gem_object_set_to_full_cpu_read_domain(obj);
 
+       if (write) {
+               ret = i915_gem_object_wait_rendering(obj, true);
+               if (ret)
+                       return ret;
+       }
+
        old_write_domain = obj->write_domain;
        old_read_domains = obj->read_domains;
 
@@ -2838,7 +2992,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
         * need to be invalidated at next use.
         */
        if (write) {
-               obj->read_domains &= I915_GEM_DOMAIN_CPU;
+               obj->read_domains = I915_GEM_DOMAIN_CPU;
                obj->write_domain = I915_GEM_DOMAIN_CPU;
        }
 
@@ -2964,7 +3118,7 @@ static void
 i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
 {
        struct drm_device               *dev = obj->dev;
-       drm_i915_private_t              *dev_priv = dev->dev_private;
+       struct drm_i915_private         *dev_priv = dev->dev_private;
        struct drm_i915_gem_object      *obj_priv = to_intel_bo(obj);
        uint32_t                        invalidate_domains = 0;
        uint32_t                        flush_domains = 0;
@@ -2975,12 +3129,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
 
        intel_mark_busy(dev, obj);
 
-#if WATCH_BUF
-       DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
-                __func__, obj,
-                obj->read_domains, obj->pending_read_domains,
-                obj->write_domain, obj->pending_write_domain);
-#endif
        /*
         * If the object isn't moving to a new write domain,
         * let the object stay in multiple read domains
@@ -3007,13 +3155,8 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
         * stale data. That is, any new read domains.
         */
        invalidate_domains |= obj->pending_read_domains & ~obj->read_domains;
-       if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
-#if WATCH_BUF
-               DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n",
-                        __func__, flush_domains, invalidate_domains);
-#endif
+       if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
                i915_gem_clflush_object(obj);
-       }
 
        old_read_domains = obj->read_domains;
 
@@ -3027,21 +3170,10 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
                obj->pending_write_domain = obj->write_domain;
        obj->read_domains = obj->pending_read_domains;
 
-       if (flush_domains & I915_GEM_GPU_DOMAINS) {
-               if (obj_priv->ring == &dev_priv->render_ring)
-                       dev_priv->flush_rings |= FLUSH_RENDER_RING;
-               else if (obj_priv->ring == &dev_priv->bsd_ring)
-                       dev_priv->flush_rings |= FLUSH_BSD_RING;
-       }
-
        dev->invalidate_domains |= invalidate_domains;
        dev->flush_domains |= flush_domains;
-#if WATCH_BUF
-       DRM_INFO("%s: read %08x write %08x invalidate %08x flush %08x\n",
-                __func__,
-                obj->read_domains, obj->write_domain,
-                dev->invalidate_domains, dev->flush_domains);
-#endif
+       if (obj_priv->ring)
+               dev_priv->mm.flush_rings |= obj_priv->ring->id;
 
        trace_i915_gem_object_change_domain(obj,
                                            old_read_domains,
@@ -3104,12 +3236,7 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
        if (offset == 0 && size == obj->size)
                return i915_gem_object_set_to_cpu_domain(obj, 0);
 
-       ret = i915_gem_object_flush_gpu_write_domain(obj);
-       if (ret)
-               return ret;
-
-       /* Wait on any GPU rendering and flushing to occur. */
-       ret = i915_gem_object_wait_rendering(obj);
+       ret = i915_gem_object_flush_gpu_write_domain(obj, false);
        if (ret != 0)
                return ret;
        i915_gem_object_flush_gtt_write_domain(obj);
@@ -3196,11 +3323,13 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
         * properly handle blits to/from tiled surfaces.
         */
        if (need_fence) {
-               ret = i915_gem_object_get_fence_reg(obj);
+               ret = i915_gem_object_get_fence_reg(obj, true);
                if (ret != 0) {
                        i915_gem_object_unpin(obj);
                        return ret;
                }
+
+               dev_priv->fence_regs[obj_priv->fence_reg].gpu = true;
        }
 
        entry->offset = obj_priv->gtt_offset;
@@ -3258,6 +3387,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
                                  (int) reloc->offset,
                                  reloc->read_domains,
                                  reloc->write_domain);
+                       drm_gem_object_unreference(target_obj);
+                       i915_gem_object_unpin(obj);
                        return -EINVAL;
                }
                if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
@@ -3333,7 +3464,7 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
                if (ret != 0) {
                        drm_gem_object_unreference(target_obj);
                        i915_gem_object_unpin(obj);
-                       return -EINVAL;
+                       return ret;
                }
 
                /* Map the page containing the relocation we're going to
@@ -3348,11 +3479,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
                                                   (reloc_offset & (PAGE_SIZE - 1)));
                reloc_val = target_obj_priv->gtt_offset + reloc->delta;
 
-#if WATCH_BUF
-               DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n",
-                         obj, (unsigned int) reloc->offset,
-                         readl(reloc_entry), reloc_val);
-#endif
                writel(reloc_val, reloc_entry);
                io_mapping_unmap_atomic(reloc_page, KM_USER0);
 
@@ -3364,10 +3490,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
                drm_gem_object_unreference(target_obj);
        }
 
-#if WATCH_BUF
-       if (0)
-               i915_gem_dump_object(obj, 128, __func__, ~0);
-#endif
        return 0;
 }
 
@@ -3382,28 +3504,48 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
  * relatively low latency when blocking on a particular request to finish.
  */
 static int
-i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
+i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
 {
-       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
-       int ret = 0;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_file_private *file_priv = file->driver_priv;
        unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
+       struct drm_i915_gem_request *request;
+       struct intel_ring_buffer *ring = NULL;
+       u32 seqno = 0;
+       int ret;
 
-       mutex_lock(&dev->struct_mutex);
-       while (!list_empty(&i915_file_priv->mm.request_list)) {
-               struct drm_i915_gem_request *request;
-
-               request = list_first_entry(&i915_file_priv->mm.request_list,
-                                          struct drm_i915_gem_request,
-                                          client_list);
-
+       spin_lock(&file_priv->mm.lock);
+       list_for_each_entry(request, &file_priv->mm.request_list, client_list) {
                if (time_after_eq(request->emitted_jiffies, recent_enough))
                        break;
 
-               ret = i915_wait_request(dev, request->seqno, request->ring);
-               if (ret != 0)
-                       break;
+               ring = request->ring;
+               seqno = request->seqno;
        }
-       mutex_unlock(&dev->struct_mutex);
+       spin_unlock(&file_priv->mm.lock);
+
+       if (seqno == 0)
+               return 0;
+
+       ret = 0;
+       if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
+               /* And wait for the seqno passing without holding any locks and
+                * causing extra latency for others. This is safe as the irq
+                * generation is designed to be run atomically and so is
+                * lockless.
+                */
+               ring->user_irq_get(dev, ring);
+               ret = wait_event_interruptible(ring->irq_queue,
+                                              i915_seqno_passed(ring->get_seqno(dev, ring), seqno)
+                                              || atomic_read(&dev_priv->mm.wedged));
+               ring->user_irq_put(dev, ring);
+
+               if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
+                       ret = -EIO;
+       }
+
+       if (ret == 0)
+               queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
 
        return ret;
 }
@@ -3539,8 +3681,7 @@ i915_gem_wait_for_pending_flip(struct drm_device *dev,
        return ret;
 }
 
-
-int
+static int
 i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                       struct drm_file *file_priv,
                       struct drm_i915_gem_execbuffer2 *args,
@@ -3552,13 +3693,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        struct drm_i915_gem_object *obj_priv;
        struct drm_clip_rect *cliprects = NULL;
        struct drm_i915_gem_relocation_entry *relocs = NULL;
-       int ret = 0, ret2, i, pinned = 0;
+       struct drm_i915_gem_request *request = NULL;
+       int ret, ret2, i, pinned = 0;
        uint64_t exec_offset;
-       uint32_t seqno, flush_domains, reloc_index;
+       uint32_t reloc_index;
        int pin_tries, flips;
 
        struct intel_ring_buffer *ring = NULL;
 
+       ret = i915_gem_check_is_wedged(dev);
+       if (ret)
+               return ret;
+
 #if WATCH_EXEC
        DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
                  (int) args->buffers_ptr, args->buffer_count, args->batch_len);
@@ -3605,20 +3751,20 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                }
        }
 
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (request == NULL) {
+               ret = -ENOMEM;
+               goto pre_mutex_err;
+       }
+
        ret = i915_gem_get_relocs_from_user(exec_list, args->buffer_count,
                                            &relocs);
        if (ret != 0)
                goto pre_mutex_err;
 
-       mutex_lock(&dev->struct_mutex);
-
-       i915_verify_inactive(dev, __FILE__, __LINE__);
-
-       if (atomic_read(&dev_priv->mm.wedged)) {
-               mutex_unlock(&dev->struct_mutex);
-               ret = -EIO;
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
                goto pre_mutex_err;
-       }
 
        if (dev_priv->mm.suspended) {
                mutex_unlock(&dev->struct_mutex);
@@ -3698,15 +3844,16 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                                          pinned+1, args->buffer_count,
                                          total_size, num_fences,
                                          ret);
-                               DRM_ERROR("%d objects [%d pinned], "
-                                         "%d object bytes [%d pinned], "
-                                         "%d/%d gtt bytes\n",
-                                         atomic_read(&dev->object_count),
-                                         atomic_read(&dev->pin_count),
-                                         atomic_read(&dev->object_memory),
-                                         atomic_read(&dev->pin_memory),
-                                         atomic_read(&dev->gtt_memory),
-                                         dev->gtt_total);
+                               DRM_ERROR("%u objects [%u pinned, %u GTT], "
+                                         "%zu object bytes [%zu pinned], "
+                                         "%zu /%zu gtt bytes\n",
+                                         dev_priv->mm.object_count,
+                                         dev_priv->mm.pin_count,
+                                         dev_priv->mm.gtt_count,
+                                         dev_priv->mm.object_memory,
+                                         dev_priv->mm.pin_memory,
+                                         dev_priv->mm.gtt_memory,
+                                         dev_priv->mm.gtt_total);
                        }
                        goto err;
                }
@@ -3739,15 +3886,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                goto err;
        }
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
-
        /* Zero the global flush/invalidate flags. These
         * will be modified as new domains are computed
         * for each object
         */
        dev->invalidate_domains = 0;
        dev->flush_domains = 0;
-       dev_priv->flush_rings = 0;
+       dev_priv->mm.flush_rings = 0;
 
        for (i = 0; i < args->buffer_count; i++) {
                struct drm_gem_object *obj = object_list[i];
@@ -3756,8 +3901,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                i915_gem_object_set_to_gpu_domain(obj);
        }
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
-
        if (dev->invalidate_domains | dev->flush_domains) {
 #if WATCH_EXEC
                DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
@@ -3765,17 +3908,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                         dev->invalidate_domains,
                         dev->flush_domains);
 #endif
-               i915_gem_flush(dev,
+               i915_gem_flush(dev, file_priv,
                               dev->invalidate_domains,
-                              dev->flush_domains);
-               if (dev_priv->flush_rings & FLUSH_RENDER_RING)
-                       (void)i915_add_request(dev, file_priv,
-                                              dev->flush_domains,
-                                              &dev_priv->render_ring);
-               if (dev_priv->flush_rings & FLUSH_BSD_RING)
-                       (void)i915_add_request(dev, file_priv,
-                                              dev->flush_domains,
-                                              &dev_priv->bsd_ring);
+                              dev->flush_domains,
+                              dev_priv->mm.flush_rings);
        }
 
        for (i = 0; i < args->buffer_count; i++) {
@@ -3787,16 +3923,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                if (obj->write_domain)
                        list_move_tail(&obj_priv->gpu_write_list,
                                       &dev_priv->mm.gpu_write_list);
-               else
-                       list_del_init(&obj_priv->gpu_write_list);
 
                trace_i915_gem_object_change_domain(obj,
                                                    obj->read_domains,
                                                    old_write_domain);
        }
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
-
 #if WATCH_COHERENCY
        for (i = 0; i < args->buffer_count; i++) {
                i915_gem_object_check_coherency(object_list[i],
@@ -3823,33 +3955,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
         * Ensure that the commands in the batch buffer are
         * finished before the interrupt fires
         */
-       flush_domains = i915_retire_commands(dev, ring);
-
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       i915_retire_commands(dev, ring);
 
-       /*
-        * Get a seqno representing the execution of the current buffer,
-        * which we can wait on.  We would like to mitigate these interrupts,
-        * likely by only creating seqnos occasionally (so that we have
-        * *some* interrupts representing completion of buffers that we can
-        * wait on when trying to clear up gtt space).
-        */
-       seqno = i915_add_request(dev, file_priv, flush_domains, ring);
-       BUG_ON(seqno == 0);
        for (i = 0; i < args->buffer_count; i++) {
                struct drm_gem_object *obj = object_list[i];
                obj_priv = to_intel_bo(obj);
 
-               i915_gem_object_move_to_active(obj, seqno, ring);
-#if WATCH_LRU
-               DRM_INFO("%s: move to exec list %p\n", __func__, obj);
-#endif
+               i915_gem_object_move_to_active(obj, ring);
        }
-#if WATCH_LRU
-       i915_dump_lru(dev, __func__);
-#endif
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       i915_add_request(dev, file_priv, request, ring);
+       request = NULL;
 
 err:
        for (i = 0; i < pinned; i++)
@@ -3882,6 +3998,7 @@ pre_mutex_err:
 
        drm_free_large(object_list);
        kfree(cliprects);
+       kfree(request);
 
        return ret;
 }
@@ -3938,7 +4055,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
                exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr;
                exec2_list[i].alignment = exec_list[i].alignment;
                exec2_list[i].offset = exec_list[i].offset;
-               if (!IS_I965G(dev))
+               if (INTEL_INFO(dev)->gen < 4)
                        exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE;
                else
                        exec2_list[i].flags = 0;
@@ -4035,12 +4152,12 @@ int
 i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
 {
        struct drm_device *dev = obj->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        int ret;
 
        BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
-
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       WARN_ON(i915_verify_lists(dev));
 
        if (obj_priv->gtt_space != NULL) {
                if (alignment == 0)
@@ -4068,14 +4185,13 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
         * remove it from the inactive list
         */
        if (obj_priv->pin_count == 1) {
-               atomic_inc(&dev->pin_count);
-               atomic_add(obj->size, &dev->pin_memory);
-               if (!obj_priv->active &&
-                   (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
-                       list_del_init(&obj_priv->list);
+               i915_gem_info_add_pin(dev_priv, obj->size);
+               if (!obj_priv->active)
+                       list_move_tail(&obj_priv->list,
+                                      &dev_priv->mm.pinned_list);
        }
-       i915_verify_inactive(dev, __FILE__, __LINE__);
 
+       WARN_ON(i915_verify_lists(dev));
        return 0;
 }
 
@@ -4086,7 +4202,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj)
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       WARN_ON(i915_verify_lists(dev));
        obj_priv->pin_count--;
        BUG_ON(obj_priv->pin_count < 0);
        BUG_ON(obj_priv->gtt_space == NULL);
@@ -4096,14 +4212,12 @@ i915_gem_object_unpin(struct drm_gem_object *obj)
         * the inactive list
         */
        if (obj_priv->pin_count == 0) {
-               if (!obj_priv->active &&
-                   (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
+               if (!obj_priv->active)
                        list_move_tail(&obj_priv->list,
                                       &dev_priv->mm.inactive_list);
-               atomic_dec(&dev->pin_count);
-               atomic_sub(obj->size, &dev->pin_memory);
+               i915_gem_info_remove_pin(dev_priv, obj->size);
        }
-       i915_verify_inactive(dev, __FILE__, __LINE__);
+       WARN_ON(i915_verify_lists(dev));
 }
 
 int
@@ -4115,17 +4229,20 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_object *obj_priv;
        int ret;
 
-       mutex_lock(&dev->struct_mutex);
-
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL) {
                DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n",
                          args->handle);
-               mutex_unlock(&dev->struct_mutex);
                return -ENOENT;
        }
        obj_priv = to_intel_bo(obj);
 
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
+
        if (obj_priv->madv != I915_MADV_WILLNEED) {
                DRM_ERROR("Attempting to pin a purgeable buffer\n");
                drm_gem_object_unreference(obj);
@@ -4170,18 +4287,23 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_pin *args = data;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
-
-       mutex_lock(&dev->struct_mutex);
+       int ret;
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL) {
                DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n",
                          args->handle);
-               mutex_unlock(&dev->struct_mutex);
                return -ENOENT;
        }
 
        obj_priv = to_intel_bo(obj);
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
+
        if (obj_priv->pin_filp != file_priv) {
                DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
                          args->handle);
@@ -4207,6 +4329,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_busy *args = data;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
+       int ret;
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL) {
@@ -4215,7 +4338,11 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
                return -ENOENT;
        }
 
-       mutex_lock(&dev->struct_mutex);
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
 
        /* Count all active objects as busy, even if they are currently not used
         * by the gpu. Users of this interface expect objects to eventually
@@ -4230,10 +4357,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
                 * use this buffer rather sooner than later, so issuing the required
                 * flush earlier is beneficial.
                 */
-               if (obj->write_domain) {
-                       i915_gem_flush(dev, 0, obj->write_domain);
-                       (void)i915_add_request(dev, file_priv, obj->write_domain, obj_priv->ring);
-               }
+               if (obj->write_domain & I915_GEM_GPU_DOMAINS)
+                       i915_gem_flush_ring(dev, file_priv,
+                                           obj_priv->ring,
+                                           0, obj->write_domain);
 
                /* Update the active list for the hardware's current position.
                 * Otherwise this only updates on a delayed timer or when irqs
@@ -4264,6 +4391,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_madvise *args = data;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
+       int ret;
 
        switch (args->madv) {
        case I915_MADV_DONTNEED:
@@ -4279,10 +4407,14 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
                          args->handle);
                return -ENOENT;
        }
-
-       mutex_lock(&dev->struct_mutex);
        obj_priv = to_intel_bo(obj);
 
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
+
        if (obj_priv->pin_count) {
                drm_gem_object_unreference(obj);
                mutex_unlock(&dev->struct_mutex);
@@ -4310,6 +4442,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
 struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
                                              size_t size)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
 
        obj = kzalloc(sizeof(*obj), GFP_KERNEL);
@@ -4321,6 +4454,8 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
                return NULL;
        }
 
+       i915_gem_info_add_obj(dev_priv, size);
+
        obj->base.write_domain = I915_GEM_DOMAIN_CPU;
        obj->base.read_domains = I915_GEM_DOMAIN_CPU;
 
@@ -4361,6 +4496,7 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj)
                i915_gem_free_mmap_offset(obj);
 
        drm_gem_object_release(obj);
+       i915_gem_info_remove_obj(dev_priv, obj->size);
 
        kfree(obj_priv->page_cpu_valid);
        kfree(obj_priv->bit_17);
@@ -4419,7 +4555,7 @@ i915_gem_idle(struct drm_device *dev)
         * And not confound mm.suspended!
         */
        dev_priv->mm.suspended = 1;
-       del_timer(&dev_priv->hangcheck_timer);
+       del_timer_sync(&dev_priv->hangcheck_timer);
 
        i915_kernel_lost_context(dev);
        i915_gem_cleanup_ringbuffer(dev);
@@ -4499,28 +4635,18 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
 
-       dev_priv->render_ring = render_ring;
-
-       if (!I915_NEED_GFX_HWS(dev)) {
-               dev_priv->render_ring.status_page.page_addr
-                       = dev_priv->status_page_dmah->vaddr;
-               memset(dev_priv->render_ring.status_page.page_addr,
-                               0, PAGE_SIZE);
-       }
-
        if (HAS_PIPE_CONTROL(dev)) {
                ret = i915_gem_init_pipe_control(dev);
                if (ret)
                        return ret;
        }
 
-       ret = intel_init_ring_buffer(dev, &dev_priv->render_ring);
+       ret = intel_init_render_ring_buffer(dev);
        if (ret)
                goto cleanup_pipe_control;
 
        if (HAS_BSD(dev)) {
-               dev_priv->bsd_ring = bsd_ring;
-               ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+               ret = intel_init_bsd_ring_buffer(dev);
                if (ret)
                        goto cleanup_render_ring;
        }
@@ -4573,11 +4699,8 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
                return ret;
        }
 
-       spin_lock(&dev_priv->mm.active_list_lock);
        BUG_ON(!list_empty(&dev_priv->render_ring.active_list));
        BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.active_list));
-       spin_unlock(&dev_priv->mm.active_list_lock);
-
        BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
        BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
        BUG_ON(!list_empty(&dev_priv->render_ring.request_list));
@@ -4629,10 +4752,10 @@ i915_gem_load(struct drm_device *dev)
        int i;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       spin_lock_init(&dev_priv->mm.active_list_lock);
        INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
        INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
        INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+       INIT_LIST_HEAD(&dev_priv->mm.pinned_list);
        INIT_LIST_HEAD(&dev_priv->mm.fence_list);
        INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
        INIT_LIST_HEAD(&dev_priv->render_ring.active_list);
@@ -4645,6 +4768,7 @@ i915_gem_load(struct drm_device *dev)
                INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list);
        INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
                          i915_gem_retire_work_handler);
+       init_completion(&dev_priv->error_completion);
        spin_lock(&shrink_list_lock);
        list_add(&dev_priv->mm.shrink_list, &shrink_list);
        spin_unlock(&shrink_list_lock);
@@ -4663,21 +4787,30 @@ i915_gem_load(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                dev_priv->fence_reg_start = 3;
 
-       if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+       if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
                dev_priv->num_fence_regs = 16;
        else
                dev_priv->num_fence_regs = 8;
 
        /* Initialize fence registers to zero */
-       if (IS_I965G(dev)) {
+       switch (INTEL_INFO(dev)->gen) {
+       case 6:
+               for (i = 0; i < 16; i++)
+                       I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0);
+               break;
+       case 5:
+       case 4:
                for (i = 0; i < 16; i++)
                        I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
-       } else {
-               for (i = 0; i < 8; i++)
-                       I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+               break;
+       case 3:
                if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
                        for (i = 0; i < 8; i++)
                                I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
+       case 2:
+               for (i = 0; i < 8; i++)
+                       I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+               break;
        }
        i915_gem_detect_bit_6_swizzle(dev);
        init_waitqueue_head(&dev_priv->pending_flip_queue);
@@ -4687,8 +4820,8 @@ i915_gem_load(struct drm_device *dev)
  * Create a physically contiguous memory object for this object
  * e.g. for cursor + overlay regs
  */
-int i915_gem_init_phys_object(struct drm_device *dev,
-                             int id, int size, int align)
+static int i915_gem_init_phys_object(struct drm_device *dev,
+                                    int id, int size, int align)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_phys_object *phys_obj;
@@ -4720,7 +4853,7 @@ kfree_obj:
        return ret;
 }
 
-void i915_gem_free_phys_object(struct drm_device *dev, int id)
+static void i915_gem_free_phys_object(struct drm_device *dev, int id)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_phys_object *phys_obj;
@@ -4865,18 +4998,25 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
        return 0;
 }
 
-void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv)
+void i915_gem_release(struct drm_device *dev, struct drm_file *file)
 {
-       struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+       struct drm_i915_file_private *file_priv = file->driver_priv;
 
        /* Clean up our request list when the client is going away, so that
         * later retire_requests won't dereference our soon-to-be-gone
         * file_priv.
         */
-       mutex_lock(&dev->struct_mutex);
-       while (!list_empty(&i915_file_priv->mm.request_list))
-               list_del_init(i915_file_priv->mm.request_list.next);
-       mutex_unlock(&dev->struct_mutex);
+       spin_lock(&file_priv->mm.lock);
+       while (!list_empty(&file_priv->mm.request_list)) {
+               struct drm_i915_gem_request *request;
+
+               request = list_first_entry(&file_priv->mm.request_list,
+                                          struct drm_i915_gem_request,
+                                          client_list);
+               list_del(&request->client_list);
+               request->file_priv = NULL;
+       }
+       spin_unlock(&file_priv->mm.lock);
 }
 
 static int
@@ -4885,12 +5025,10 @@ i915_gpu_is_active(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        int lists_empty;
 
-       spin_lock(&dev_priv->mm.active_list_lock);
        lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
                      list_empty(&dev_priv->render_ring.active_list);
        if (HAS_BSD(dev))
                lists_empty &= list_empty(&dev_priv->bsd_ring.active_list);
-       spin_unlock(&dev_priv->mm.active_list_lock);
 
        return !lists_empty;
 }
index 80f380b1d951fe8875260b90849cbf78ced35d5a..48644b840a8dc08dfac36c6d5570265427324f6a 100644 (file)
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-#if WATCH_INACTIVE
-void
-i915_verify_inactive(struct drm_device *dev, char *file, int line)
+#if WATCH_LISTS
+int
+i915_verify_lists(struct drm_device *dev)
 {
+       static int warned;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_gem_object *obj;
-       struct drm_i915_gem_object *obj_priv;
-
-       list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
-               obj = &obj_priv->base;
-               if (obj_priv->pin_count || obj_priv->active ||
-                   (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
-                                          I915_GEM_DOMAIN_GTT)))
-                       DRM_ERROR("inactive %p (p %d a %d w %x)  %s:%d\n",
+       struct drm_i915_gem_object *obj;
+       int err = 0;
+
+       if (warned)
+               return 0;
+
+       list_for_each_entry(obj, &dev_priv->render_ring.active_list, list) {
+               if (obj->base.dev != dev ||
+                   !atomic_read(&obj->base.refcount.refcount)) {
+                       DRM_ERROR("freed render active %p\n", obj);
+                       err++;
+                       break;
+               } else if (!obj->active ||
+                          (obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0) {
+                       DRM_ERROR("invalid render active %p (a %d r %x)\n",
+                                 obj,
+                                 obj->active,
+                                 obj->base.read_domains);
+                       err++;
+               } else if (obj->base.write_domain && list_empty(&obj->gpu_write_list)) {
+                       DRM_ERROR("invalid render active %p (w %x, gwl %d)\n",
+                                 obj,
+                                 obj->base.write_domain,
+                                 !list_empty(&obj->gpu_write_list));
+                       err++;
+               }
+       }
+
+       list_for_each_entry(obj, &dev_priv->mm.flushing_list, list) {
+               if (obj->base.dev != dev ||
+                   !atomic_read(&obj->base.refcount.refcount)) {
+                       DRM_ERROR("freed flushing %p\n", obj);
+                       err++;
+                       break;
+               } else if (!obj->active ||
+                          (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0 ||
+                          list_empty(&obj->gpu_write_list)){
+                       DRM_ERROR("invalid flushing %p (a %d w %x gwl %d)\n",
                                  obj,
-                                 obj_priv->pin_count, obj_priv->active,
-                                 obj->write_domain, file, line);
+                                 obj->active,
+                                 obj->base.write_domain,
+                                 !list_empty(&obj->gpu_write_list));
+                       err++;
+               }
+       }
+
+       list_for_each_entry(obj, &dev_priv->mm.gpu_write_list, gpu_write_list) {
+               if (obj->base.dev != dev ||
+                   !atomic_read(&obj->base.refcount.refcount)) {
+                       DRM_ERROR("freed gpu write %p\n", obj);
+                       err++;
+                       break;
+               } else if (!obj->active ||
+                          (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) {
+                       DRM_ERROR("invalid gpu write %p (a %d w %x)\n",
+                                 obj,
+                                 obj->active,
+                                 obj->base.write_domain);
+                       err++;
+               }
+       }
+
+       list_for_each_entry(obj, &dev_priv->mm.inactive_list, list) {
+               if (obj->base.dev != dev ||
+                   !atomic_read(&obj->base.refcount.refcount)) {
+                       DRM_ERROR("freed inactive %p\n", obj);
+                       err++;
+                       break;
+               } else if (obj->pin_count || obj->active ||
+                          (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
+                       DRM_ERROR("invalid inactive %p (p %d a %d w %x)\n",
+                                 obj,
+                                 obj->pin_count, obj->active,
+                                 obj->base.write_domain);
+                       err++;
+               }
        }
+
+       list_for_each_entry(obj, &dev_priv->mm.pinned_list, list) {
+               if (obj->base.dev != dev ||
+                   !atomic_read(&obj->base.refcount.refcount)) {
+                       DRM_ERROR("freed pinned %p\n", obj);
+                       err++;
+                       break;
+               } else if (!obj->pin_count || obj->active ||
+                          (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
+                       DRM_ERROR("invalid pinned %p (p %d a %d w %x)\n",
+                                 obj,
+                                 obj->pin_count, obj->active,
+                                 obj->base.write_domain);
+                       err++;
+               }
+       }
+
+       return warned = err;
 }
 #endif /* WATCH_INACTIVE */
 
 
-#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE
+#if WATCH_EXEC | WATCH_PWRITE
 static void
 i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end,
                   uint32_t bias, uint32_t mark)
@@ -97,41 +180,6 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len,
 }
 #endif
 
-#if WATCH_LRU
-void
-i915_dump_lru(struct drm_device *dev, const char *where)
-{
-       drm_i915_private_t              *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object      *obj_priv;
-
-       DRM_INFO("active list %s {\n", where);
-       spin_lock(&dev_priv->mm.active_list_lock);
-       list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
-                           list)
-       {
-               DRM_INFO("    %p: %08x\n", obj_priv,
-                        obj_priv->last_rendering_seqno);
-       }
-       spin_unlock(&dev_priv->mm.active_list_lock);
-       DRM_INFO("}\n");
-       DRM_INFO("flushing list %s {\n", where);
-       list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
-                           list)
-       {
-               DRM_INFO("    %p: %08x\n", obj_priv,
-                        obj_priv->last_rendering_seqno);
-       }
-       DRM_INFO("}\n");
-       DRM_INFO("inactive %s {\n", where);
-       list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
-               DRM_INFO("    %p: %08x\n", obj_priv,
-                        obj_priv->last_rendering_seqno);
-       }
-       DRM_INFO("}\n");
-}
-#endif
-
-
 #if WATCH_COHERENCY
 void
 i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
index e85246ef691ce339ab3ba331c30a6e846b7ead36..3d7fbf32bb1893bc42eacfb7d8c6d3fc7767df09 100644 (file)
@@ -93,7 +93,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct list_head eviction_list, unwind_list;
-       struct drm_i915_gem_object *obj_priv, *tmp_obj_priv;
+       struct drm_i915_gem_object *obj_priv;
        struct list_head *render_iter, *bsd_iter;
        int ret = 0;
 
@@ -175,39 +175,34 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen
        return -ENOSPC;
 
 found:
+       /* drm_mm doesn't allow any other other operations while
+        * scanning, therefore store to be evicted objects on a
+        * temporary list. */
        INIT_LIST_HEAD(&eviction_list);
-       list_for_each_entry_safe(obj_priv, tmp_obj_priv,
-                                &unwind_list, evict_list) {
+       while (!list_empty(&unwind_list)) {
+               obj_priv = list_first_entry(&unwind_list,
+                                           struct drm_i915_gem_object,
+                                           evict_list);
                if (drm_mm_scan_remove_block(obj_priv->gtt_space)) {
-                       /* drm_mm doesn't allow any other other operations while
-                        * scanning, therefore store to be evicted objects on a
-                        * temporary list. */
                        list_move(&obj_priv->evict_list, &eviction_list);
-               } else
-                       drm_gem_object_unreference(&obj_priv->base);
+                       continue;
+               }
+               list_del(&obj_priv->evict_list);
+               drm_gem_object_unreference(&obj_priv->base);
        }
 
        /* Unbinding will emit any required flushes */
-       list_for_each_entry_safe(obj_priv, tmp_obj_priv,
-                                &eviction_list, evict_list) {
-#if WATCH_LRU
-               DRM_INFO("%s: evicting %p\n", __func__, &obj_priv->base);
-#endif
-               ret = i915_gem_object_unbind(&obj_priv->base);
-               if (ret)
-                       return ret;
-
+       while (!list_empty(&eviction_list)) {
+               obj_priv = list_first_entry(&eviction_list,
+                                           struct drm_i915_gem_object,
+                                           evict_list);
+               if (ret == 0)
+                       ret = i915_gem_object_unbind(&obj_priv->base);
+               list_del(&obj_priv->evict_list);
                drm_gem_object_unreference(&obj_priv->base);
        }
 
-       /* The just created free hole should be on the top of the free stack
-        * maintained by drm_mm, so this BUG_ON actually executes in O(1).
-        * Furthermore all accessed data has just recently been used, so it
-        * should be really fast, too. */
-       BUG_ON(!drm_mm_search_free(&dev_priv->mm.gtt_space, min_size,
-                                  alignment, 0));
-
-       return 0;
+       return ret;
 }
 
 int
@@ -217,14 +212,11 @@ i915_gem_evict_everything(struct drm_device *dev)
        int ret;
        bool lists_empty;
 
-       spin_lock(&dev_priv->mm.active_list_lock);
        lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
                       list_empty(&dev_priv->mm.flushing_list) &&
                       list_empty(&dev_priv->render_ring.active_list) &&
                       (!HAS_BSD(dev)
                        || list_empty(&dev_priv->bsd_ring.active_list)));
-       spin_unlock(&dev_priv->mm.active_list_lock);
-
        if (lists_empty)
                return -ENOSPC;
 
@@ -239,13 +231,11 @@ i915_gem_evict_everything(struct drm_device *dev)
        if (ret)
                return ret;
 
-       spin_lock(&dev_priv->mm.active_list_lock);
        lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
                       list_empty(&dev_priv->mm.flushing_list) &&
                       list_empty(&dev_priv->render_ring.active_list) &&
                       (!HAS_BSD(dev)
                        || list_empty(&dev_priv->bsd_ring.active_list)));
-       spin_unlock(&dev_priv->mm.active_list_lock);
        BUG_ON(!lists_empty);
 
        return 0;
index 710eca70b323953e376d3c214a33e78996bed1d2..8c9ffc4768ee25aef6f6d0bac5bffbc884df12e7 100644 (file)
@@ -98,7 +98,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
                 */
                swizzle_x = I915_BIT_6_SWIZZLE_9_10;
                swizzle_y = I915_BIT_6_SWIZZLE_9;
-       } else if (!IS_I9XX(dev)) {
+       } else if (IS_GEN2(dev)) {
                /* As far as we know, the 865 doesn't have these bit 6
                 * swizzling issues.
                 */
@@ -190,19 +190,19 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
        if (tiling_mode == I915_TILING_NONE)
                return true;
 
-       if (!IS_I9XX(dev) ||
+       if (IS_GEN2(dev) ||
            (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
                tile_width = 128;
        else
                tile_width = 512;
 
        /* check maximum stride & object size */
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                /* i965 stores the end address of the gtt mapping in the fence
                 * reg, so dont bother to check the size */
                if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
                        return false;
-       } else if (IS_GEN3(dev) || IS_GEN2(dev)) {
+       } else {
                if (stride > 8192)
                        return false;
 
@@ -216,7 +216,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
        }
 
        /* 965+ just needs multiples of tile width */
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                if (stride & (tile_width - 1))
                        return false;
                return true;
@@ -244,16 +244,18 @@ i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
        if (tiling_mode == I915_TILING_NONE)
                return true;
 
-       if (!IS_I965G(dev)) {
-               if (obj_priv->gtt_offset & (obj->size - 1))
+       if (INTEL_INFO(dev)->gen >= 4)
+               return true;
+
+       if (obj_priv->gtt_offset & (obj->size - 1))
+               return false;
+
+       if (IS_GEN3(dev)) {
+               if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
+                       return false;
+       } else {
+               if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
                        return false;
-               if (IS_I9XX(dev)) {
-                       if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
-                               return false;
-               } else {
-                       if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
-                               return false;
-               }
        }
 
        return true;
@@ -271,7 +273,11 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
-       int ret = 0;
+       int ret;
+
+       ret = i915_gem_check_is_wedged(dev);
+       if (ret)
+               return ret;
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (obj == NULL)
@@ -328,7 +334,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode))
                        ret = i915_gem_object_unbind(obj);
                else if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
-                       ret = i915_gem_object_put_fence_reg(obj);
+                       ret = i915_gem_object_put_fence_reg(obj, true);
                else
                        i915_gem_release_mmap(obj);
 
@@ -399,16 +405,14 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
  * bit 17 of its physical address and therefore being interpreted differently
  * by the GPU.
  */
-static int
+static void
 i915_gem_swizzle_page(struct page *page)
 {
+       char temp[64];
        char *vaddr;
        int i;
-       char temp[64];
 
        vaddr = kmap(page);
-       if (vaddr == NULL)
-               return -ENOMEM;
 
        for (i = 0; i < PAGE_SIZE; i += 128) {
                memcpy(temp, &vaddr[i], 64);
@@ -417,8 +421,6 @@ i915_gem_swizzle_page(struct page *page)
        }
 
        kunmap(page);
-
-       return 0;
 }
 
 void
@@ -440,11 +442,7 @@ i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj)
                char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17;
                if ((new_bit_17 & 0x1) !=
                    (test_bit(i, obj_priv->bit_17) != 0)) {
-                       int ret = i915_gem_swizzle_page(obj_priv->pages[i]);
-                       if (ret != 0) {
-                               DRM_ERROR("Failed to swizzle page\n");
-                               return;
-                       }
+                       i915_gem_swizzle_page(obj_priv->pages[i]);
                        set_page_dirty(obj_priv->pages[i]);
                }
        }
index 744225ebb4b25d5988fab454441de95d7db94115..64c07c24e3001af891f8ed659a2ecfc4aad7026b 100644 (file)
@@ -85,7 +85,7 @@ ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
 }
 
 /* For display hotplug interrupt */
-void
+static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
        if ((dev_priv->irq_mask_reg & mask) != 0) {
@@ -172,7 +172,7 @@ void intel_enable_asle (struct drm_device *dev)
        else {
                i915_enable_pipestat(dev_priv, 1,
                                     PIPE_LEGACY_BLC_EVENT_ENABLE);
-               if (IS_I965G(dev))
+               if (INTEL_INFO(dev)->gen >= 4)
                        i915_enable_pipestat(dev_priv, 0,
                                             PIPE_LEGACY_BLC_EVENT_ENABLE);
        }
@@ -191,12 +191,7 @@ static int
 i915_pipe_enabled(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
-
-       if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
-               return 1;
-
-       return 0;
+       return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
 }
 
 /* Called from drm generic code, passed a 'crtc', which
@@ -207,10 +202,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long high_frame;
        unsigned long low_frame;
-       u32 high1, high2, low, count;
-
-       high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
-       low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+       u32 high1, high2, low;
 
        if (!i915_pipe_enabled(dev, pipe)) {
                DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
@@ -218,23 +210,23 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
                return 0;
        }
 
+       high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+       low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
        /*
         * High & low register fields aren't synchronized, so make sure
         * we get a low value that's stable across two reads of the high
         * register.
         */
        do {
-               high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
-                        PIPE_FRAME_HIGH_SHIFT);
-               low =  ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
-                       PIPE_FRAME_LOW_SHIFT);
-               high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
-                        PIPE_FRAME_HIGH_SHIFT);
+               high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
+               low   = I915_READ(low_frame)  & PIPE_FRAME_LOW_MASK;
+               high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
        } while (high1 != high2);
 
-       count = (high1 << 8) | low;
-
-       return count;
+       high1 >>= PIPE_FRAME_HIGH_SHIFT;
+       low >>= PIPE_FRAME_LOW_SHIFT;
+       return (high1 << 8) | low;
 }
 
 u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
@@ -260,16 +252,12 @@ static void i915_hotplug_work_func(struct work_struct *work)
                                                    hotplug_work);
        struct drm_device *dev = dev_priv->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_encoder *encoder;
-
-       if (mode_config->num_encoder) {
-               list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-                       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-       
-                       if (intel_encoder->hot_plug)
-                               (*intel_encoder->hot_plug) (intel_encoder);
-               }
-       }
+       struct intel_encoder *encoder;
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+               if (encoder->hot_plug)
+                       encoder->hot_plug(encoder);
+
        /* Just fire off a uevent and let userspace tell us what to do */
        drm_helper_hpd_irq_event(dev);
 }
@@ -305,13 +293,17 @@ static void i915_handle_rps_change(struct drm_device *dev)
        return;
 }
 
-irqreturn_t ironlake_irq_handler(struct drm_device *dev)
+static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int ret = IRQ_NONE;
        u32 de_iir, gt_iir, de_ier, pch_iir;
        struct drm_i915_master_private *master_priv;
        struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
+       u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
+
+       if (IS_GEN6(dev))
+               bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
 
        /* disable master interrupt before clearing iir  */
        de_ier = I915_READ(DEIER);
@@ -335,28 +327,28 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
        }
 
        if (gt_iir & GT_PIPE_NOTIFY) {
-               u32 seqno = render_ring->get_gem_seqno(dev, render_ring);
+               u32 seqno = render_ring->get_seqno(dev, render_ring);
                render_ring->irq_gem_seqno = seqno;
                trace_i915_gem_request_complete(dev, seqno);
-               DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+               wake_up_all(&dev_priv->render_ring.irq_queue);
                dev_priv->hangcheck_count = 0;
-               mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+               mod_timer(&dev_priv->hangcheck_timer,
+                         jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
        }
-       if (gt_iir & GT_BSD_USER_INTERRUPT)
-               DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
-
+       if (gt_iir & bsd_usr_interrupt)
+               wake_up_all(&dev_priv->bsd_ring.irq_queue);
 
        if (de_iir & DE_GSE)
-               ironlake_opregion_gse_intr(dev);
+               intel_opregion_gse_intr(dev);
 
        if (de_iir & DE_PLANEA_FLIP_DONE) {
                intel_prepare_page_flip(dev, 0);
-               intel_finish_page_flip(dev, 0);
+               intel_finish_page_flip_plane(dev, 0);
        }
 
        if (de_iir & DE_PLANEB_FLIP_DONE) {
                intel_prepare_page_flip(dev, 1);
-               intel_finish_page_flip(dev, 1);
+               intel_finish_page_flip_plane(dev, 1);
        }
 
        if (de_iir & DE_PIPEA_VBLANK)
@@ -404,23 +396,20 @@ static void i915_error_work_func(struct work_struct *work)
        char *reset_event[] = { "RESET=1", NULL };
        char *reset_done_event[] = { "ERROR=0", NULL };
 
-       DRM_DEBUG_DRIVER("generating error event\n");
        kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
 
        if (atomic_read(&dev_priv->mm.wedged)) {
-               if (IS_I965G(dev)) {
-                       DRM_DEBUG_DRIVER("resetting chip\n");
-                       kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
-                       if (!i965_reset(dev, GDRST_RENDER)) {
-                               atomic_set(&dev_priv->mm.wedged, 0);
-                               kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
-                       }
-               } else {
-                       DRM_DEBUG_DRIVER("reboot required\n");
+               DRM_DEBUG_DRIVER("resetting chip\n");
+               kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
+               if (!i915_reset(dev, GRDOM_RENDER)) {
+                       atomic_set(&dev_priv->mm.wedged, 0);
+                       kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
                }
+               complete_all(&dev_priv->error_completion);
        }
 }
 
+#ifdef CONFIG_DEBUG_FS
 static struct drm_i915_error_object *
 i915_error_object_create(struct drm_device *dev,
                         struct drm_gem_object *src)
@@ -511,7 +500,7 @@ i915_get_bbaddr(struct drm_device *dev, u32 *ring)
 
        if (IS_I830(dev) || IS_845G(dev))
                cmd = MI_BATCH_BUFFER;
-       else if (IS_I965G(dev))
+       else if (INTEL_INFO(dev)->gen >= 4)
                cmd = (MI_BATCH_BUFFER_START | (2 << 6) |
                       MI_BATCH_NON_SECURE_I965);
        else
@@ -584,13 +573,16 @@ static void i915_capture_error_state(struct drm_device *dev)
                return;
        }
 
-       error->seqno = i915_get_gem_seqno(dev, &dev_priv->render_ring);
+       DRM_DEBUG_DRIVER("generating error event\n");
+
+       error->seqno =
+               dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring);
        error->eir = I915_READ(EIR);
        error->pgtbl_er = I915_READ(PGTBL_ER);
        error->pipeastat = I915_READ(PIPEASTAT);
        error->pipebstat = I915_READ(PIPEBSTAT);
        error->instpm = I915_READ(INSTPM);
-       if (!IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen < 4) {
                error->ipeir = I915_READ(IPEIR);
                error->ipehr = I915_READ(IPEHR);
                error->instdone = I915_READ(INSTDONE);
@@ -744,6 +736,9 @@ void i915_destroy_error_state(struct drm_device *dev)
        if (error)
                i915_error_state_free(dev, error);
 }
+#else
+#define i915_capture_error_state(x)
+#endif
 
 static void i915_report_and_clear_eir(struct drm_device *dev)
 {
@@ -785,7 +780,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
                }
        }
 
-       if (IS_I9XX(dev)) {
+       if (!IS_GEN2(dev)) {
                if (eir & I915_ERROR_PAGE_TABLE) {
                        u32 pgtbl_err = I915_READ(PGTBL_ER);
                        printk(KERN_ERR "page table error\n");
@@ -811,7 +806,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
                printk(KERN_ERR "instruction error\n");
                printk(KERN_ERR "  INSTPM: 0x%08x\n",
                       I915_READ(INSTPM));
-               if (!IS_I965G(dev)) {
+               if (INTEL_INFO(dev)->gen < 4) {
                        u32 ipeir = I915_READ(IPEIR);
 
                        printk(KERN_ERR "  IPEIR: 0x%08x\n",
@@ -876,12 +871,15 @@ static void i915_handle_error(struct drm_device *dev, bool wedged)
        i915_report_and_clear_eir(dev);
 
        if (wedged) {
+               INIT_COMPLETION(dev_priv->error_completion);
                atomic_set(&dev_priv->mm.wedged, 1);
 
                /*
                 * Wakeup waiting processes so they don't hang
                 */
-               DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+               wake_up_all(&dev_priv->render_ring.irq_queue);
+               if (HAS_BSD(dev))
+                       wake_up_all(&dev_priv->bsd_ring.irq_queue);
        }
 
        queue_work(dev_priv->wq, &dev_priv->error_work);
@@ -912,7 +910,7 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
 
        /* Potential stall - if we see that the flip has happened, assume a missed interrupt */
        obj_priv = to_intel_bo(work->pending_flip_obj);
-       if(IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF;
                stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset;
        } else {
@@ -951,7 +949,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 
        iir = I915_READ(IIR);
 
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS;
        else
                vblank_status = PIPE_VBLANK_INTERRUPT_STATUS;
@@ -1020,17 +1018,17 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                }
 
                if (iir & I915_USER_INTERRUPT) {
-                       u32 seqno =
-                               render_ring->get_gem_seqno(dev, render_ring);
+                       u32 seqno = render_ring->get_seqno(dev, render_ring);
                        render_ring->irq_gem_seqno = seqno;
                        trace_i915_gem_request_complete(dev, seqno);
-                       DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+                       wake_up_all(&dev_priv->render_ring.irq_queue);
                        dev_priv->hangcheck_count = 0;
-                       mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+                       mod_timer(&dev_priv->hangcheck_timer,
+                                 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
                }
 
                if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT))
-                       DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+                       wake_up_all(&dev_priv->bsd_ring.irq_queue);
 
                if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
                        intel_prepare_page_flip(dev, 0);
@@ -1065,7 +1063,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
                    (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
                    (iir & I915_ASLE_INTERRUPT))
-                       opregion_asle_intr(dev);
+                       intel_opregion_asle_intr(dev);
 
                /* With MSI, interrupts are only generated when iir
                 * transitions from zero to nonzero.  If another bit got
@@ -1207,18 +1205,15 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       u32 pipeconf;
 
-       pipeconf = I915_READ(pipeconf_reg);
-       if (!(pipeconf & PIPEACONF_ENABLE))
+       if (!i915_pipe_enabled(dev, pipe))
                return -EINVAL;
 
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
        if (HAS_PCH_SPLIT(dev))
                ironlake_enable_display_irq(dev_priv, (pipe == 0) ? 
                                            DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
-       else if (IS_I965G(dev))
+       else if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, pipe,
                                     PIPE_START_VBLANK_INTERRUPT_ENABLE);
        else
@@ -1252,7 +1247,7 @@ void i915_enable_interrupt (struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (!HAS_PCH_SPLIT(dev))
-               opregion_enable_asle(dev);
+               intel_opregion_enable_asle(dev);
        dev_priv->irq_enabled = 1;
 }
 
@@ -1311,7 +1306,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
        return -EINVAL;
 }
 
-struct drm_i915_gem_request *
+static struct drm_i915_gem_request *
 i915_get_tail_request(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -1331,11 +1326,7 @@ void i915_hangcheck_elapsed(unsigned long data)
        drm_i915_private_t *dev_priv = dev->dev_private;
        uint32_t acthd, instdone, instdone1;
 
-       /* No reset support on this chip yet. */
-       if (IS_GEN6(dev))
-               return;
-
-       if (!IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen < 4) {
                acthd = I915_READ(ACTHD);
                instdone = I915_READ(INSTDONE);
                instdone1 = 0;
@@ -1347,9 +1338,8 @@ void i915_hangcheck_elapsed(unsigned long data)
 
        /* If all work is done then ACTHD clearly hasn't advanced. */
        if (list_empty(&dev_priv->render_ring.request_list) ||
-               i915_seqno_passed(i915_get_gem_seqno(dev,
-                               &dev_priv->render_ring),
-                       i915_get_tail_request(dev)->seqno)) {
+               i915_seqno_passed(dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring),
+                                 i915_get_tail_request(dev)->seqno)) {
                bool missed_wakeup = false;
 
                dev_priv->hangcheck_count = 0;
@@ -1357,13 +1347,13 @@ void i915_hangcheck_elapsed(unsigned long data)
                /* Issue a wake-up to catch stuck h/w. */
                if (dev_priv->render_ring.waiting_gem_seqno &&
                    waitqueue_active(&dev_priv->render_ring.irq_queue)) {
-                       DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+                       wake_up_all(&dev_priv->render_ring.irq_queue);
                        missed_wakeup = true;
                }
 
                if (dev_priv->bsd_ring.waiting_gem_seqno &&
                    waitqueue_active(&dev_priv->bsd_ring.irq_queue)) {
-                       DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+                       wake_up_all(&dev_priv->bsd_ring.irq_queue);
                        missed_wakeup = true;
                }
 
@@ -1377,6 +1367,21 @@ void i915_hangcheck_elapsed(unsigned long data)
            dev_priv->last_instdone1 == instdone1) {
                if (dev_priv->hangcheck_count++ > 1) {
                        DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
+
+                       if (!IS_GEN2(dev)) {
+                               /* Is the chip hanging on a WAIT_FOR_EVENT?
+                                * If so we can simply poke the RB_WAIT bit
+                                * and break the hang. This should work on
+                                * all but the second generation chipsets.
+                                */
+                               u32 tmp = I915_READ(PRB0_CTL);
+                               if (tmp & RING_WAIT) {
+                                       I915_WRITE(PRB0_CTL, tmp);
+                                       POSTING_READ(PRB0_CTL);
+                                       goto out;
+                               }
+                       }
+
                        i915_handle_error(dev, true);
                        return;
                }
@@ -1388,8 +1393,10 @@ void i915_hangcheck_elapsed(unsigned long data)
                dev_priv->last_instdone1 = instdone1;
        }
 
+out:
        /* Reset timer case chip hangs without another request being added */
-       mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+       mod_timer(&dev_priv->hangcheck_timer,
+                 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 }
 
 /* drm_dma.h hooks
@@ -1436,17 +1443,19 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
        (void) I915_READ(DEIER);
 
-       /* Gen6 only needs render pipe_control now */
        if (IS_GEN6(dev))
-               render_mask = GT_PIPE_NOTIFY;
+               render_mask = GT_PIPE_NOTIFY | GT_GEN6_BSD_USER_INTERRUPT;
 
        dev_priv->gt_irq_mask_reg = ~render_mask;
        dev_priv->gt_irq_enable_reg = render_mask;
 
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
-       if (IS_GEN6(dev))
+       if (IS_GEN6(dev)) {
                I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT);
+               I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_IMR_USER_INTERRUPT);
+       }
+
        I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
        (void) I915_READ(GTIER);
 
@@ -1578,7 +1587,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
                I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
        }
 
-       opregion_enable_asle(dev);
+       intel_opregion_enable_asle(dev);
 
        return 0;
 }
index 4f5e15577e89e3e6f7005cd92f9f87ab0636b4eb..d02de212e6ad217de1f09ddc589ea7949ae814f4 100644 (file)
 #ifndef _I915_REG_H_
 #define _I915_REG_H_
 
+#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
+
 /*
  * The Bridge device's PCI config space has information about the
  * fb aperture size and the amount of pre-reserved memory.
+ * This is all handled in the intel-gtt.ko module. i915.ko only
+ * cares about the vga bit for the vga rbiter.
  */
 #define INTEL_GMCH_CTRL                0x52
 #define INTEL_GMCH_VGA_DISABLE  (1 << 1)
-#define INTEL_GMCH_ENABLED     0x4
-#define INTEL_GMCH_MEM_MASK    0x1
-#define INTEL_GMCH_MEM_64M     0x1
-#define INTEL_GMCH_MEM_128M    0
-
-#define INTEL_GMCH_GMS_MASK            (0xf << 4)
-#define INTEL_855_GMCH_GMS_DISABLED    (0x0 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_1M   (0x1 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_4M   (0x2 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_8M   (0x3 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_16M  (0x4 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_32M  (0x5 << 4)
-
-#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4)
-#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4)
-#define INTEL_GMCH_GMS_STOLEN_128M     (0x8 << 4)
-#define INTEL_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 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)
 
 /* PCI config space */
 
 #define   I915_GC_RENDER_CLOCK_200_MHZ (1 << 0)
 #define   I915_GC_RENDER_CLOCK_333_MHZ (4 << 0)
 #define LBB    0xf4
-#define GDRST 0xc0
-#define  GDRST_FULL    (0<<2)
-#define  GDRST_RENDER  (1<<2)
-#define  GDRST_MEDIA   (3<<2)
+
+/* Graphics reset regs */
+#define I965_GDRST 0xc0 /* PCI config register */
+#define ILK_GDSR 0x2ca4 /* MCHBAR offset */
+#define  GRDOM_FULL    (0<<2)
+#define  GRDOM_RENDER  (1<<2)
+#define  GRDOM_MEDIA   (3<<2)
 
 /* VGA stuff */
 
 #define MI_STORE_DWORD_INDEX   MI_INSTR(0x21, 1)
 #define   MI_STORE_DWORD_INDEX_SHIFT 2
 #define MI_LOAD_REGISTER_IMM   MI_INSTR(0x22, 1)
+#define MI_FLUSH_DW            MI_INSTR(0x26, 2) /* for GEN6 */
 #define MI_BATCH_BUFFER                MI_INSTR(0x30, 1)
 #define   MI_BATCH_NON_SECURE  (1)
 #define   MI_BATCH_NON_SECURE_I965 (1<<8)
 #define MI_BATCH_BUFFER_START  MI_INSTR(0x31, 0)
-
 /*
  * 3D instructions used by the kernel
  */
 #define   PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
 #define   PIPE_CONTROL_STALL_EN        (1<<1) /* in addr word, Ironlake+ only */
 
+
+/*
+ * Reset registers
+ */
+#define DEBUG_RESET_I830               0x6070
+#define  DEBUG_RESET_FULL              (1<<7)
+#define  DEBUG_RESET_RENDER            (1<<8)
+#define  DEBUG_RESET_DISPLAY           (1<<9)
+
+
 /*
  * Fence registers
  */
 #define PRB0_HEAD      0x02034
 #define PRB0_START     0x02038
 #define PRB0_CTL       0x0203c
+#define RENDER_RING_BASE       0x02000
+#define BSD_RING_BASE          0x04000
+#define GEN6_BSD_RING_BASE     0x12000
+#define RING_TAIL(base)                ((base)+0x30)
+#define RING_HEAD(base)                ((base)+0x34)
+#define RING_START(base)       ((base)+0x38)
+#define RING_CTL(base)         ((base)+0x3c)
+#define RING_HWS_PGA(base)     ((base)+0x80)
+#define RING_HWS_PGA_GEN6(base)        ((base)+0x2080)
+#define RING_ACTHD(base)       ((base)+0x74)
 #define   TAIL_ADDR            0x001FFFF8
 #define   HEAD_WRAP_COUNT      0xFFE00000
 #define   HEAD_WRAP_ONE                0x00200000
 #define   RING_VALID_MASK      0x00000001
 #define   RING_VALID           0x00000001
 #define   RING_INVALID         0x00000000
+#define   RING_WAIT_I8XX       (1<<0) /* gen2, PRBx_HEAD */
+#define   RING_WAIT            (1<<11) /* gen3+, PRBx_CTL */
 #define PRB1_TAIL      0x02040 /* 915+ only */
 #define PRB1_HEAD      0x02044 /* 915+ only */
 #define PRB1_START     0x02048 /* 915+ only */
 #define INSTDONE1      0x0207c /* 965+ only */
 #define ACTHD_I965     0x02074
 #define HWS_PGA                0x02080
-#define HWS_PGA_GEN6   0x04080
 #define HWS_ADDRESS_MASK       0xfffff000
 #define HWS_START_ADDRESS_SHIFT        4
 #define PWRCTXA                0x2088 /* 965GM+ only */
 #define   GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR     (1 << 25)
 #define   GEN6_BLITTER_SYNC_STATUS                     (1 << 24)
 #define   GEN6_BLITTER_USER_INTERRUPT                  (1 << 22)
-/*
- * BSD (bit stream decoder instruction and interrupt control register defines
- * (G4X and Ironlake only)
- */
 
-#define BSD_RING_TAIL          0x04030
-#define BSD_RING_HEAD          0x04034
-#define BSD_RING_START         0x04038
-#define BSD_RING_CTL           0x0403c
-#define BSD_RING_ACTHD         0x04074
-#define BSD_HWS_PGA            0x04080
+#define GEN6_BSD_SLEEP_PSMI_CONTROL    0x12050
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK      (1 << 16)
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE          (1 << 0)
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE           0
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR                   (1 << 3)
+
+#define GEN6_BSD_IMR                   0x120a8
+#define   GEN6_BSD_IMR_USER_INTERRUPT  (1 << 12)
+
+#define GEN6_BSD_RNCID                 0x12198
 
 /*
  * Framebuffer compression (915+ only)
 # define GPIO_DATA_VAL_IN              (1 << 12)
 # define GPIO_DATA_PULLUP_DISABLE      (1 << 13)
 
-#define GMBUS0                 0x5100
-#define GMBUS1                 0x5104
-#define GMBUS2                 0x5108
-#define GMBUS3                 0x510c
-#define GMBUS4                 0x5110
-#define GMBUS5                 0x5120
+#define GMBUS0                 0x5100 /* clock/port select */
+#define   GMBUS_RATE_100KHZ    (0<<8)
+#define   GMBUS_RATE_50KHZ     (1<<8)
+#define   GMBUS_RATE_400KHZ    (2<<8) /* reserved on Pineview */
+#define   GMBUS_RATE_1MHZ      (3<<8) /* reserved on Pineview */
+#define   GMBUS_HOLD_EXT       (1<<7) /* 300ns hold time, rsvd on Pineview */
+#define   GMBUS_PORT_DISABLED  0
+#define   GMBUS_PORT_SSC       1
+#define   GMBUS_PORT_VGADDC    2
+#define   GMBUS_PORT_PANEL     3
+#define   GMBUS_PORT_DPC       4 /* HDMIC */
+#define   GMBUS_PORT_DPB       5 /* SDVO, HDMIB */
+                                 /* 6 reserved */
+#define   GMBUS_PORT_DPD       7 /* HDMID */
+#define   GMBUS_NUM_PORTS       8
+#define GMBUS1                 0x5104 /* command/status */
+#define   GMBUS_SW_CLR_INT     (1<<31)
+#define   GMBUS_SW_RDY         (1<<30)
+#define   GMBUS_ENT            (1<<29) /* enable timeout */
+#define   GMBUS_CYCLE_NONE     (0<<25)
+#define   GMBUS_CYCLE_WAIT     (1<<25)
+#define   GMBUS_CYCLE_INDEX    (2<<25)
+#define   GMBUS_CYCLE_STOP     (4<<25)
+#define   GMBUS_BYTE_COUNT_SHIFT 16
+#define   GMBUS_SLAVE_INDEX_SHIFT 8
+#define   GMBUS_SLAVE_ADDR_SHIFT 1
+#define   GMBUS_SLAVE_READ     (1<<0)
+#define   GMBUS_SLAVE_WRITE    (0<<0)
+#define GMBUS2                 0x5108 /* status */
+#define   GMBUS_INUSE          (1<<15)
+#define   GMBUS_HW_WAIT_PHASE  (1<<14)
+#define   GMBUS_STALL_TIMEOUT  (1<<13)
+#define   GMBUS_INT            (1<<12)
+#define   GMBUS_HW_RDY         (1<<11)
+#define   GMBUS_SATOER         (1<<10)
+#define   GMBUS_ACTIVE         (1<<9)
+#define GMBUS3                 0x510c /* data buffer bytes 3-0 */
+#define GMBUS4                 0x5110 /* interrupt mask (Pineview+) */
+#define   GMBUS_SLAVE_TIMEOUT_EN (1<<4)
+#define   GMBUS_NAK_EN         (1<<3)
+#define   GMBUS_IDLE_EN                (1<<2)
+#define   GMBUS_HW_WAIT_EN     (1<<1)
+#define   GMBUS_HW_RDY_EN      (1<<0)
+#define GMBUS5                 0x5120 /* byte index */
+#define   GMBUS_2BYTE_INDEX_EN (1<<31)
 
 /*
  * Clock control & power management
 #define   VGA1_PD_P1_MASK      (0x1f << 8)
 #define DPLL_A 0x06014
 #define DPLL_B 0x06018
+#define DPLL(pipe) _PIPE(pipe, DPLL_A, DPLL_B)
 #define   DPLL_VCO_ENABLE              (1 << 31)
 #define   DPLL_DVO_HIGH_SPEED          (1 << 30)
 #define   DPLL_SYNCLOCK_ENABLE         (1 << 29)
 #define ADPA_DPMS_STANDBY      (2<<10)
 #define ADPA_DPMS_OFF          (3<<10)
 
-#define RING_TAIL              0x00
-#define TAIL_ADDR              0x001FFFF8
-#define RING_HEAD              0x04
-#define HEAD_WRAP_COUNT                0xFFE00000
-#define HEAD_WRAP_ONE          0x00200000
-#define HEAD_ADDR              0x001FFFFC
-#define RING_START             0x08
-#define START_ADDR             0xFFFFF000
-#define RING_LEN               0x0C
-#define RING_NR_PAGES          0x001FF000
-#define RING_REPORT_MASK       0x00000006
-#define RING_REPORT_64K                0x00000002
-#define RING_REPORT_128K       0x00000004
-#define RING_NO_REPORT         0x00000000
-#define RING_VALID_MASK                0x00000001
-#define RING_VALID             0x00000001
-#define RING_INVALID           0x00000000
-
 /* Scratch pad debug 0 reg:
  */
 #define   DPLL_FPA01_P1_POST_DIV_MASK_I830     0x001f0000
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_MASK      0x0000003f
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT     0
 #define DPLL_B_MD 0x06020 /* 965+ only */
+#define DPLL_MD(pipe) _PIPE(pipe, DPLL_A_MD, DPLL_B_MD)
 #define FPA0   0x06040
 #define FPA1   0x06044
 #define FPB0   0x06048
 #define FPB1   0x0604c
+#define FP0(pipe) _PIPE(pipe, FPA0, FPB0)
+#define FP1(pipe) _PIPE(pipe, FPA1, FPB1)
 #define   FP_N_DIV_MASK                0x003f0000
 #define   FP_N_PINEVIEW_DIV_MASK       0x00ff0000
 #define   FP_N_DIV_SHIFT               16
 #define   DPLLA_TEST_M_BYPASS          (1 << 2)
 #define   DPLLA_INPUT_BUFFER_ENABLE    (1 << 0)
 #define D_STATE                0x6104
+#define  DSTATE_GFX_RESET_I830                 (1<<6)
 #define  DSTATE_PLL_D3_OFF                     (1<<3)
 #define  DSTATE_GFX_CLOCK_GATING               (1<<1)
 #define  DSTATE_DOT_CLOCK_GATING               (1<<0)
 #define CLKCFG_MEM_800                                 (3 << 4)
 #define CLKCFG_MEM_MASK                                        (7 << 4)
 
+#define TSC1                   0x11001
+#define   TSE                  (1<<0)
 #define TR1                    0x11006
 #define TSFS                   0x11020
 #define   TSFS_SLOPE_MASK      0x0000ff00
 #define   MEMSTAT_SRC_CTL_STDBY 3
 #define RCPREVBSYTUPAVG                0x113b8
 #define RCPREVBSYTDNAVG                0x113bc
+#define PMMISC                 0x11214
+#define   MCPPCE_EN            (1<<0) /* enable PM_MSG from PCH->MPC */
 #define SDEW                   0x1124c
 #define CSIEW0                 0x11250
 #define CSIEW1                 0x11254
 #define PIPEBSRC       0x6101c
 #define BCLRPAT_B      0x61020
 
+#define HTOTAL(pipe) _PIPE(pipe, HTOTAL_A, HTOTAL_B)
+#define HBLANK(pipe) _PIPE(pipe, HBLANK_A, HBLANK_B)
+#define HSYNC(pipe) _PIPE(pipe, HSYNC_A, HSYNC_B)
+#define VTOTAL(pipe) _PIPE(pipe, VTOTAL_A, VTOTAL_B)
+#define VBLANK(pipe) _PIPE(pipe, VBLANK_A, VBLANK_B)
+#define VSYNC(pipe) _PIPE(pipe, VSYNC_A, VSYNC_B)
+#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC)
+#define BCLRPAT(pipe) _PIPE(pipe, BCLRPAT_A, BCLRPAT_B)
+
 /* VGA port control */
 #define ADPA                   0x61100
 #define   ADPA_DAC_ENABLE      (1<<31)
 # define TV_TEST_MODE_MASK             (7 << 0)
 
 #define TV_DAC                 0x68004
+# define TV_DAC_SAVE           0x00ffff00
 /**
  * Reports that DAC state change logic has reported change (RO).
  *
 
 /* Display & cursor control */
 
-/* dithering flag on Ironlake */
-#define PIPE_ENABLE_DITHER             (1 << 4)
-#define PIPE_DITHER_TYPE_MASK          (3 << 2)
-#define PIPE_DITHER_TYPE_SPATIAL       (0 << 2)
-#define PIPE_DITHER_TYPE_ST01          (1 << 2)
 /* Pipe A */
 #define PIPEADSL               0x70000
-#define   DSL_LINEMASK         0x00000fff
+#define   DSL_LINEMASK         0x00000fff
 #define PIPEACONF              0x70008
-#define   PIPEACONF_ENABLE     (1<<31)
-#define   PIPEACONF_DISABLE    0
-#define   PIPEACONF_DOUBLE_WIDE        (1<<30)
+#define   PIPECONF_ENABLE      (1<<31)
+#define   PIPECONF_DISABLE     0
+#define   PIPECONF_DOUBLE_WIDE (1<<30)
 #define   I965_PIPECONF_ACTIVE (1<<30)
-#define   PIPEACONF_SINGLE_WIDE        0
-#define   PIPEACONF_PIPE_UNLOCKED 0
-#define   PIPEACONF_PIPE_LOCKED        (1<<25)
-#define   PIPEACONF_PALETTE    0
-#define   PIPEACONF_GAMMA              (1<<24)
+#define   PIPECONF_SINGLE_WIDE 0
+#define   PIPECONF_PIPE_UNLOCKED 0
+#define   PIPECONF_PIPE_LOCKED (1<<25)
+#define   PIPECONF_PALETTE     0
+#define   PIPECONF_GAMMA               (1<<24)
 #define   PIPECONF_FORCE_BORDER        (1<<25)
 #define   PIPECONF_PROGRESSIVE (0 << 21)
 #define   PIPECONF_INTERLACE_W_FIELD_INDICATION        (6 << 21)
 #define   PIPECONF_INTERLACE_FIELD_0_ONLY              (7 << 21)
 #define   PIPECONF_CXSR_DOWNCLOCK      (1<<16)
+#define   PIPECONF_BPP_MASK    (0x000000e0)
+#define   PIPECONF_BPP_8       (0<<5)
+#define   PIPECONF_BPP_10      (1<<5)
+#define   PIPECONF_BPP_6       (2<<5)
+#define   PIPECONF_BPP_12      (3<<5)
+#define   PIPECONF_DITHER_EN   (1<<4)
+#define   PIPECONF_DITHER_TYPE_MASK (0x0000000c)
+#define   PIPECONF_DITHER_TYPE_SP (0<<2)
+#define   PIPECONF_DITHER_TYPE_ST1 (1<<2)
+#define   PIPECONF_DITHER_TYPE_ST2 (2<<2)
+#define   PIPECONF_DITHER_TYPE_TEMP (3<<2)
 #define PIPEASTAT              0x70024
 #define   PIPE_FIFO_UNDERRUN_STATUS            (1UL<<31)
 #define   PIPE_CRC_ERROR_ENABLE                        (1UL<<29)
 #define   PIPE_START_VBLANK_INTERRUPT_STATUS   (1UL<<2) /* 965 or later */
 #define   PIPE_VBLANK_INTERRUPT_STATUS         (1UL<<1)
 #define   PIPE_OVERLAY_UPDATED_STATUS          (1UL<<0)
-#define   PIPE_BPC_MASK                        (7 << 5) /* Ironlake */
+#define   PIPE_BPC_MASK                                (7 << 5) /* Ironlake */
 #define   PIPE_8BPC                            (0 << 5)
 #define   PIPE_10BPC                           (1 << 5)
 #define   PIPE_6BPC                            (2 << 5)
 #define   PIPE_12BPC                           (3 << 5)
 
+#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF)
+#define PIPEDSL(pipe)  _PIPE(pipe, PIPEADSL, PIPEBDSL)
+
 #define DSPARB                 0x70030
 #define   DSPARB_CSTART_MASK   (0x7f << 7)
 #define   DSPARB_CSTART_SHIFT  7
 #define  WM1_LP_SR_EN          (1<<31)
 #define  WM1_LP_LATENCY_SHIFT  24
 #define  WM1_LP_LATENCY_MASK   (0x7f<<24)
-#define  WM1_LP_FBC_LP1_MASK   (0xf<<20)
-#define  WM1_LP_FBC_LP1_SHIFT  20
+#define  WM1_LP_FBC_MASK       (0xf<<20)
+#define  WM1_LP_FBC_SHIFT      20
 #define  WM1_LP_SR_MASK                (0x1ff<<8)
 #define  WM1_LP_SR_SHIFT       8
 #define  WM1_LP_CURSOR_MASK    (0x3f)
 #define DSPASURF               0x7019C /* 965+ only */
 #define DSPATILEOFF            0x701A4 /* 965+ only */
 
+#define DSPCNTR(plane) _PIPE(plane, DSPACNTR, DSPBCNTR)
+#define DSPADDR(plane) _PIPE(plane, DSPAADDR, DSPBADDR)
+#define DSPSTRIDE(plane) _PIPE(plane, DSPASTRIDE, DSPBSTRIDE)
+#define DSPPOS(plane) _PIPE(plane, DSPAPOS, DSPBPOS)
+#define DSPSIZE(plane) _PIPE(plane, DSPASIZE, DSPBSIZE)
+#define DSPSURF(plane) _PIPE(plane, DSPASURF, DSPBSURF)
+#define DSPTILEOFF(plane) _PIPE(plane, DSPATILEOFF, DSPBTILEOFF)
+
 /* VBIOS flags */
 #define SWF00                  0x71410
 #define SWF01                  0x71414
 #define  RR_HW_HIGH_POWER_FRAMES_MASK   0xff00
 
 #define FDI_PLL_BIOS_0  0x46000
+#define  FDI_PLL_FB_CLOCK_MASK  0xff
 #define FDI_PLL_BIOS_1  0x46004
 #define FDI_PLL_BIOS_2  0x46008
 #define DISPLAY_PORT_PLL_BIOS_0         0x4600c
 #define PIPEA_DATA_M1           0x60030
 #define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
 #define  TU_SIZE_MASK           0x7e000000
-#define  PIPEA_DATA_M1_OFFSET   0
+#define  PIPE_DATA_M1_OFFSET    0
 #define PIPEA_DATA_N1           0x60034
-#define  PIPEA_DATA_N1_OFFSET   0
+#define  PIPE_DATA_N1_OFFSET    0
 
 #define PIPEA_DATA_M2           0x60038
-#define  PIPEA_DATA_M2_OFFSET   0
+#define  PIPE_DATA_M2_OFFSET    0
 #define PIPEA_DATA_N2           0x6003c
-#define  PIPEA_DATA_N2_OFFSET   0
+#define  PIPE_DATA_N2_OFFSET    0
 
 #define PIPEA_LINK_M1           0x60040
-#define  PIPEA_LINK_M1_OFFSET   0
+#define  PIPE_LINK_M1_OFFSET    0
 #define PIPEA_LINK_N1           0x60044
-#define  PIPEA_LINK_N1_OFFSET   0
+#define  PIPE_LINK_N1_OFFSET    0
 
 #define PIPEA_LINK_M2           0x60048
-#define  PIPEA_LINK_M2_OFFSET   0
+#define  PIPE_LINK_M2_OFFSET    0
 #define PIPEA_LINK_N2           0x6004c
-#define  PIPEA_LINK_N2_OFFSET   0
+#define  PIPE_LINK_N2_OFFSET    0
 
 /* PIPEB timing regs are same start from 0x61000 */
 
 #define PIPEB_DATA_M1           0x61030
-#define  PIPEB_DATA_M1_OFFSET   0
 #define PIPEB_DATA_N1           0x61034
-#define  PIPEB_DATA_N1_OFFSET   0
 
 #define PIPEB_DATA_M2           0x61038
-#define  PIPEB_DATA_M2_OFFSET   0
 #define PIPEB_DATA_N2           0x6103c
-#define  PIPEB_DATA_N2_OFFSET   0
 
 #define PIPEB_LINK_M1           0x61040
-#define  PIPEB_LINK_M1_OFFSET   0
 #define PIPEB_LINK_N1           0x61044
-#define  PIPEB_LINK_N1_OFFSET   0
 
 #define PIPEB_LINK_M2           0x61048
-#define  PIPEB_LINK_M2_OFFSET   0
 #define PIPEB_LINK_N2           0x6104c
-#define  PIPEB_LINK_N2_OFFSET   0
+
+#define PIPE_DATA_M1(pipe) _PIPE(pipe, PIPEA_DATA_M1, PIPEB_DATA_M1)
+#define PIPE_DATA_N1(pipe) _PIPE(pipe, PIPEA_DATA_N1, PIPEB_DATA_N1)
+#define PIPE_DATA_M2(pipe) _PIPE(pipe, PIPEA_DATA_M2, PIPEB_DATA_M2)
+#define PIPE_DATA_N2(pipe) _PIPE(pipe, PIPEA_DATA_N2, PIPEB_DATA_N2)
+#define PIPE_LINK_M1(pipe) _PIPE(pipe, PIPEA_LINK_M1, PIPEB_LINK_M1)
+#define PIPE_LINK_N1(pipe) _PIPE(pipe, PIPEA_LINK_N1, PIPEB_LINK_N1)
+#define PIPE_LINK_M2(pipe) _PIPE(pipe, PIPEA_LINK_M2, PIPEB_LINK_M2)
+#define PIPE_LINK_N2(pipe) _PIPE(pipe, PIPEA_LINK_N2, PIPEB_LINK_N2)
 
 /* CPU panel fitter */
 #define PFA_CTL_1               0x68080
 #define GT_SYNC_STATUS          (1 << 2)
 #define GT_USER_INTERRUPT       (1 << 0)
 #define GT_BSD_USER_INTERRUPT   (1 << 5)
-
+#define GT_GEN6_BSD_USER_INTERRUPT     (1 << 12)
 
 #define GTISR   0x44010
 #define GTIMR   0x44014
 
 #define PCH_DPLL_A              0xc6014
 #define PCH_DPLL_B              0xc6018
+#define PCH_DPLL(pipe) _PIPE(pipe, PCH_DPLL_A, PCH_DPLL_B)
 
 #define PCH_FPA0                0xc6040
 #define PCH_FPA1                0xc6044
 #define PCH_FPB0                0xc6048
 #define PCH_FPB1                0xc604c
+#define PCH_FP0(pipe) _PIPE(pipe, PCH_FPA0, PCH_FPB0)
+#define PCH_FP1(pipe) _PIPE(pipe, PCH_FPA1, PCH_FPB1)
 
 #define PCH_DPLL_TEST           0xc606c
 
 #define TRANS_VBLANK_B          0xe1010
 #define TRANS_VSYNC_B           0xe1014
 
+#define TRANS_HTOTAL(pipe) _PIPE(pipe, TRANS_HTOTAL_A, TRANS_HTOTAL_B)
+#define TRANS_HBLANK(pipe) _PIPE(pipe, TRANS_HBLANK_A, TRANS_HBLANK_B)
+#define TRANS_HSYNC(pipe) _PIPE(pipe, TRANS_HSYNC_A, TRANS_HSYNC_B)
+#define TRANS_VTOTAL(pipe) _PIPE(pipe, TRANS_VTOTAL_A, TRANS_VTOTAL_B)
+#define TRANS_VBLANK(pipe) _PIPE(pipe, TRANS_VBLANK_A, TRANS_VBLANK_B)
+#define TRANS_VSYNC(pipe) _PIPE(pipe, TRANS_VSYNC_A, TRANS_VSYNC_B)
+
 #define TRANSB_DATA_M1          0xe1030
 #define TRANSB_DATA_N1          0xe1034
 #define TRANSB_DATA_M2          0xe1038
 
 #define TRANSACONF              0xf0008
 #define TRANSBCONF              0xf1008
+#define TRANSCONF(plane) _PIPE(plane, TRANSACONF, TRANSBCONF)
 #define  TRANS_DISABLE          (0<<31)
 #define  TRANS_ENABLE           (1<<31)
 #define  TRANS_STATE_MASK       (1<<30)
 /* CPU: FDI_TX */
 #define FDI_TXA_CTL             0x60100
 #define FDI_TXB_CTL             0x61100
+#define FDI_TX_CTL(pipe) _PIPE(pipe, FDI_TXA_CTL, FDI_TXB_CTL)
 #define  FDI_TX_DISABLE         (0<<31)
 #define  FDI_TX_ENABLE          (1<<31)
 #define  FDI_LINK_TRAIN_PATTERN_1       (0<<28)
 /* FDI_RX, FDI_X is hard-wired to Transcoder_X */
 #define FDI_RXA_CTL             0xf000c
 #define FDI_RXB_CTL             0xf100c
+#define FDI_RX_CTL(pipe) _PIPE(pipe, FDI_RXA_CTL, FDI_RXB_CTL)
 #define  FDI_RX_ENABLE          (1<<31)
-#define  FDI_RX_DISABLE         (0<<31)
 /* train, dp width same as FDI_TX */
 #define  FDI_DP_PORT_WIDTH_X8           (7<<19)
 #define  FDI_8BPC                       (0<<16)
 #define  FDI_FS_ERR_REPORT_ENABLE       (1<<9)
 #define  FDI_FE_ERR_REPORT_ENABLE       (1<<8)
 #define  FDI_RX_ENHANCE_FRAME_ENABLE    (1<<6)
-#define  FDI_SEL_RAWCLK                 (0<<4)
-#define  FDI_SEL_PCDCLK                 (1<<4)
+#define  FDI_PCDCLK                    (1<<4)
 /* CPT */
 #define  FDI_AUTO_TRAINING                     (1<<10)
 #define  FDI_LINK_TRAIN_PATTERN_1_CPT          (0<<8)
 #define FDI_RXA_TUSIZE2         0xf0038
 #define FDI_RXB_TUSIZE1         0xf1030
 #define FDI_RXB_TUSIZE2         0xf1038
+#define FDI_RX_MISC(pipe) _PIPE(pipe, FDI_RXA_MISC, FDI_RXB_MISC)
+#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, FDI_RXA_TUSIZE1, FDI_RXB_TUSIZE1)
+#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, FDI_RXA_TUSIZE2, FDI_RXB_TUSIZE2)
 
 /* FDI_RX interrupt register format */
 #define FDI_RX_INTER_LANE_ALIGN         (1<<10)
 #define FDI_RXA_IMR             0xf0018
 #define FDI_RXB_IIR             0xf1014
 #define FDI_RXB_IMR             0xf1018
+#define FDI_RX_IIR(pipe) _PIPE(pipe, FDI_RXA_IIR, FDI_RXB_IIR)
+#define FDI_RX_IMR(pipe) _PIPE(pipe, FDI_RXA_IMR, FDI_RXB_IMR)
 
 #define FDI_PLL_CTL_1           0xfe000
 #define FDI_PLL_CTL_2           0xfe004
 #define TRANS_DP_CTL_A         0xe0300
 #define TRANS_DP_CTL_B         0xe1300
 #define TRANS_DP_CTL_C         0xe2300
+#define TRANS_DP_CTL(pipe)     (TRANS_DP_CTL_A + (pipe) * 0x01000)
 #define  TRANS_DP_OUTPUT_ENABLE        (1<<31)
 #define  TRANS_DP_PORT_SEL_B   (0<<29)
 #define  TRANS_DP_PORT_SEL_C   (1<<29)
index 31f08581e93a46dbdc2ca1cfa563faec31e9ffc5..989c19d2d959b6bc6c54a0e4bf31d9aee093efe6 100644 (file)
@@ -256,7 +256,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
                dev_priv->saveFPA1 = I915_READ(FPA1);
                dev_priv->saveDPLL_A = I915_READ(DPLL_A);
        }
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
                dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
        dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
        dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
@@ -294,7 +294,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
        dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
        dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
        dev_priv->saveDSPAADDR = I915_READ(DSPAADDR);
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                dev_priv->saveDSPASURF = I915_READ(DSPASURF);
                dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
        }
@@ -313,7 +313,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
                dev_priv->saveFPB1 = I915_READ(FPB1);
                dev_priv->saveDPLL_B = I915_READ(DPLL_B);
        }
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
                dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
        dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
        dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
@@ -351,7 +351,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
        dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
        dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
        dev_priv->saveDSPBADDR = I915_READ(DSPBADDR);
-       if (IS_I965GM(dev) || IS_GM45(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
                dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
        }
@@ -404,7 +404,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
        I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A);
        POSTING_READ(dpll_a_reg);
        udelay(150);
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
                I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
                POSTING_READ(DPLL_A_MD);
        }
@@ -448,7 +448,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
        I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
        I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
        I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
                I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
        }
@@ -473,7 +473,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
        I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B);
        POSTING_READ(dpll_b_reg);
        udelay(150);
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
                I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
                POSTING_READ(DPLL_B_MD);
        }
@@ -517,7 +517,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
        I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
        I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
        I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
                I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
        }
@@ -550,7 +550,7 @@ void i915_save_display(struct drm_device *dev)
        dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
        dev_priv->saveCURBPOS = I915_READ(CURBPOS);
        dev_priv->saveCURBBASE = I915_READ(CURBBASE);
-       if (!IS_I9XX(dev))
+       if (IS_GEN2(dev))
                dev_priv->saveCURSIZE = I915_READ(CURSIZE);
 
        /* CRT state */
@@ -573,7 +573,7 @@ void i915_save_display(struct drm_device *dev)
                dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
                dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
                dev_priv->saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL);
-               if (IS_I965G(dev))
+               if (INTEL_INFO(dev)->gen >= 4)
                        dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
                if (IS_MOBILE(dev) && !IS_I830(dev))
                        dev_priv->saveLVDS = I915_READ(LVDS);
@@ -664,7 +664,7 @@ void i915_restore_display(struct drm_device *dev)
        I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
        I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
        I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
-       if (!IS_I9XX(dev))
+       if (IS_GEN2(dev))
                I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
 
        /* CRT state */
@@ -674,7 +674,7 @@ void i915_restore_display(struct drm_device *dev)
                I915_WRITE(ADPA, dev_priv->saveADPA);
 
        /* LVDS state */
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
                I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
 
        if (HAS_PCH_SPLIT(dev)) {
@@ -878,9 +878,7 @@ int i915_restore_state(struct drm_device *dev)
        for (i = 0; i < 3; i++)
                I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
 
-       /* I2C state */
-       intel_i2c_reset_gmbus(dev);
+       intel_i2c_reset(dev);
 
        return 0;
 }
-
index 96f75d7f663319c77ed5f77d279c8cc4794591d2..b1f73ac0f3fd310c7599383212091fff02c1c093 100644 (file)
@@ -129,10 +129,6 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        int i, temp_downclock;
        struct drm_display_mode *temp_mode;
 
-       /* Defaults if we can't find VBT info */
-       dev_priv->lvds_dither = 0;
-       dev_priv->lvds_vbt = 0;
-
        lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
        if (!lvds_options)
                return;
@@ -140,6 +136,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        dev_priv->lvds_dither = lvds_options->pixel_dither;
        if (lvds_options->panel_type == 0xff)
                return;
+
        panel_type = lvds_options->panel_type;
 
        lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
@@ -169,6 +166,8 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
                        ((unsigned char *)entry + dvo_timing_offset);
 
        panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
+       if (!panel_fixed_mode)
+               return;
 
        fill_detail_timing_data(panel_fixed_mode, dvo_timing);
 
@@ -230,8 +229,6 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
        struct lvds_dvo_timing *dvo_timing;
        struct drm_display_mode *panel_fixed_mode;
 
-       dev_priv->sdvo_lvds_vbt_mode = NULL;
-
        sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
        if (!sdvo_lvds_options)
                return;
@@ -260,10 +257,6 @@ parse_general_features(struct drm_i915_private *dev_priv,
        struct drm_device *dev = dev_priv->dev;
        struct bdb_general_features *general;
 
-       /* Set sensible defaults in case we can't find the general block */
-       dev_priv->int_tv_support = 1;
-       dev_priv->int_crt_support = 1;
-
        general = find_section(bdb, BDB_GENERAL_FEATURES);
        if (general) {
                dev_priv->int_tv_support = general->int_tv_support;
@@ -289,14 +282,6 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
                          struct bdb_header *bdb)
 {
        struct bdb_general_definitions *general;
-       const int crt_bus_map_table[] = {
-               GPIOB,
-               GPIOA,
-               GPIOC,
-               GPIOD,
-               GPIOE,
-               GPIOF,
-       };
 
        general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
        if (general) {
@@ -304,10 +289,8 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
                if (block_size >= sizeof(*general)) {
                        int bus_pin = general->crt_ddc_gmbus_pin;
                        DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
-                       if ((bus_pin >= 1) && (bus_pin <= 6)) {
-                               dev_priv->crt_ddc_bus =
-                                       crt_bus_map_table[bus_pin-1];
-                       }
+                       if (bus_pin >= 1 && bus_pin <= 6)
+                               dev_priv->crt_ddc_pin = bus_pin;
                } else {
                        DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
                                  block_size);
@@ -317,7 +300,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
 
 static void
 parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
-                      struct bdb_header *bdb)
+                         struct bdb_header *bdb)
 {
        struct sdvo_device_mapping *p_mapping;
        struct bdb_general_definitions *p_defs;
@@ -327,7 +310,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
 
        p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
        if (!p_defs) {
-               DRM_DEBUG_KMS("No general definition block is found\n");
+               DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
                return;
        }
        /* judge whether the size of child device meets the requirements.
@@ -377,7 +360,16 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
                        p_mapping->slave_addr = p_child->slave_addr;
                        p_mapping->dvo_wiring = p_child->dvo_wiring;
                        p_mapping->ddc_pin = p_child->ddc_pin;
+                       p_mapping->i2c_pin = p_child->i2c_pin;
+                       p_mapping->i2c_speed = p_child->i2c_speed;
                        p_mapping->initialized = 1;
+                       DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d, i2c_speed=%d\n",
+                                     p_mapping->dvo_port,
+                                     p_mapping->slave_addr,
+                                     p_mapping->dvo_wiring,
+                                     p_mapping->ddc_pin,
+                                     p_mapping->i2c_pin,
+                                     p_mapping->i2c_speed);
                } else {
                        DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
                                         "two SDVO device.\n");
@@ -409,14 +401,11 @@ parse_driver_features(struct drm_i915_private *dev_priv,
        if (!driver)
                return;
 
-       if (driver && SUPPORTS_EDP(dev) &&
-           driver->lvds_config == BDB_DRIVER_FEATURE_EDP) {
-               dev_priv->edp_support = 1;
-       } else {
-               dev_priv->edp_support = 0;
-       }
+       if (SUPPORTS_EDP(dev) &&
+           driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
+               dev_priv->edp.support = 1;
 
-       if (driver && driver->dual_frequency)
+       if (driver->dual_frequency)
                dev_priv->render_reclock_avail = true;
 }
 
@@ -427,26 +416,40 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 
        edp = find_section(bdb, BDB_EDP);
        if (!edp) {
-               if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) {
+               if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) {
                        DRM_DEBUG_KMS("No eDP BDB found but eDP panel "
-                                     "supported, assume 18bpp panel color "
-                                     "depth.\n");
-                       dev_priv->edp_bpp = 18;
+                                     "supported, assume %dbpp panel color "
+                                     "depth.\n",
+                                     dev_priv->edp.bpp);
                }
                return;
        }
 
        switch ((edp->color_depth >> (panel_type * 2)) & 3) {
        case EDP_18BPP:
-               dev_priv->edp_bpp = 18;
+               dev_priv->edp.bpp = 18;
                break;
        case EDP_24BPP:
-               dev_priv->edp_bpp = 24;
+               dev_priv->edp.bpp = 24;
                break;
        case EDP_30BPP:
-               dev_priv->edp_bpp = 30;
+               dev_priv->edp.bpp = 30;
                break;
        }
+
+       dev_priv->edp.rate = edp->link_params[panel_type].rate;
+       dev_priv->edp.lanes = edp->link_params[panel_type].lanes;
+       dev_priv->edp.preemphasis = edp->link_params[panel_type].preemphasis;
+       dev_priv->edp.vswing = edp->link_params[panel_type].vswing;
+
+       DRM_DEBUG_KMS("eDP vBIOS settings: bpp=%d, rate=%d, lanes=%d, preemphasis=%d, vswing=%d\n",
+                     dev_priv->edp.bpp,
+                     dev_priv->edp.rate,
+                     dev_priv->edp.lanes,
+                     dev_priv->edp.preemphasis,
+                     dev_priv->edp.vswing);
+
+       dev_priv->edp.initialized = true;
 }
 
 static void
@@ -460,7 +463,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
 
        p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
        if (!p_defs) {
-               DRM_DEBUG_KMS("No general definition block is found\n");
+               DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
                return;
        }
        /* judge whether the size of child device meets the requirements.
@@ -513,6 +516,28 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
        }
        return;
 }
+
+static void
+init_vbt_defaults(struct drm_i915_private *dev_priv)
+{
+       dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC;
+
+       /* LFP panel data */
+       dev_priv->lvds_dither = 1;
+       dev_priv->lvds_vbt = 0;
+
+       /* SDVO panel data */
+       dev_priv->sdvo_lvds_vbt_mode = NULL;
+
+       /* general features */
+       dev_priv->int_tv_support = 1;
+       dev_priv->int_crt_support = 1;
+       dev_priv->lvds_use_ssc = 0;
+
+       /* eDP data */
+       dev_priv->edp.bpp = 18;
+}
+
 /**
  * intel_init_bios - initialize VBIOS settings & find VBT
  * @dev: DRM device
@@ -520,11 +545,6 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
  * Loads the Video BIOS and checks that the VBT exists.  Sets scratch registers
  * to appropriate values.
  *
- * VBT existence is a sanity check that is relied on by other i830_bios.c code.
- * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may
- * feed an updated VBT back through that, compared to what we'll fetch using
- * this method of groping around in the BIOS data.
- *
  * Returns 0 on success, nonzero on failure.
  */
 bool
@@ -532,31 +552,47 @@ intel_init_bios(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct pci_dev *pdev = dev->pdev;
-       struct vbt_header *vbt = NULL;
-       struct bdb_header *bdb;
-       u8 __iomem *bios;
-       size_t size;
-       int i;
-
-       bios = pci_map_rom(pdev, &size);
-       if (!bios)
-               return -1;
-
-       /* Scour memory looking for the VBT signature */
-       for (i = 0; i + 4 < size; i++) {
-               if (!memcmp(bios + i, "$VBT", 4)) {
-                       vbt = (struct vbt_header *)(bios + i);
-                       break;
-               }
+       struct bdb_header *bdb = NULL;
+       u8 __iomem *bios = NULL;
+
+       init_vbt_defaults(dev_priv);
+
+       /* XXX Should this validation be moved to intel_opregion.c? */
+       if (dev_priv->opregion.vbt) {
+               struct vbt_header *vbt = dev_priv->opregion.vbt;
+               if (memcmp(vbt->signature, "$VBT", 4) == 0) {
+                       DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n",
+                                        vbt->signature);
+                       bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
+               } else
+                       dev_priv->opregion.vbt = NULL;
        }
 
-       if (!vbt) {
-               DRM_ERROR("VBT signature missing\n");
-               pci_unmap_rom(pdev, bios);
-               return -1;
-       }
+       if (bdb == NULL) {
+               struct vbt_header *vbt = NULL;
+               size_t size;
+               int i;
+
+               bios = pci_map_rom(pdev, &size);
+               if (!bios)
+                       return -1;
+
+               /* Scour memory looking for the VBT signature */
+               for (i = 0; i + 4 < size; i++) {
+                       if (!memcmp(bios + i, "$VBT", 4)) {
+                               vbt = (struct vbt_header *)(bios + i);
+                               break;
+                       }
+               }
 
-       bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+               if (!vbt) {
+                       DRM_ERROR("VBT signature missing\n");
+                       pci_unmap_rom(pdev, bios);
+                       return -1;
+               }
+
+               bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+       }
 
        /* Grab useful general definitions */
        parse_general_features(dev_priv, bdb);
@@ -568,7 +604,8 @@ intel_init_bios(struct drm_device *dev)
        parse_driver_features(dev_priv, bdb);
        parse_edp(dev_priv, bdb);
 
-       pci_unmap_rom(pdev, bios);
+       if (bios)
+               pci_unmap_rom(pdev, bios);
 
        return 0;
 }
index 4c18514f6f80f469d15a039ef47d37bd0e249ce4..e1a598f2a96684e6e895748a18b91b28f6253b4a 100644 (file)
@@ -197,7 +197,8 @@ struct bdb_general_features {
 struct child_device_config {
        u16 handle;
        u16 device_type;
-       u8  device_id[10]; /* See DEVICE_TYPE_* above */
+       u8  i2c_speed;
+       u8  rsvd[9];
        u16 addin_offset;
        u8  dvo_port; /* See Device_PORT_* above */
        u8  i2c_pin;
index 197d4f32585a59b5b336328b470fa038bc922781..389fcd2aea1f0f7fe90ec6e0dbb152214b735b7b 100644 (file)
@@ -79,7 +79,7 @@ static int intel_crt_mode_valid(struct drm_connector *connector,
        if (mode->clock < 25000)
                return MODE_CLOCK_LOW;
 
-       if (!IS_I9XX(dev))
+       if (IS_GEN2(dev))
                max_clock = 350000;
        else
                max_clock = 400000;
@@ -123,7 +123,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
         * Disable separate mode multiplier used when cloning SDVO to CRT
         * XXX this needs to be adjusted when we really are cloning
         */
-       if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
                dpll_md = I915_READ(dpll_md_reg);
                I915_WRITE(dpll_md_reg,
                           dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@@ -187,7 +187,7 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
        I915_WRITE(PCH_ADPA, adpa);
 
        if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
-                    1000, 1))
+                    1000))
                DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
 
        if (turn_off_dac) {
@@ -244,7 +244,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
                /* wait for FORCE_DETECT to go off */
                if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
                              CRT_HOTPLUG_FORCE_DETECT) == 0,
-                            1000, 1))
+                            1000))
                        DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
        }
 
@@ -261,21 +261,47 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
        return ret;
 }
 
+static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus)
+{
+       u8 buf;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = 0xA0,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &buf,
+               },
+       };
+       /* DDC monitor detect: Does it ACK a write to 0xA0? */
+       return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
+}
+
 static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
 {
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+       struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 
        /* CRT should always be at 0, but check anyway */
        if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
                return false;
 
-       return intel_ddc_probe(intel_encoder);
+       if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
+               DRM_DEBUG_KMS("CRT detected via DDC:0xa0\n");
+               return true;
+       }
+
+       if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) {
+               DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
+               return true;
+       }
+
+       return false;
 }
 
 static enum drm_connector_status
 intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
 {
-       struct drm_encoder *encoder = &intel_encoder->enc;
+       struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -295,6 +321,8 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
        uint8_t st00;
        enum drm_connector_status status;
 
+       DRM_DEBUG_KMS("starting load-detect on CRT\n");
+
        if (pipe == 0) {
                bclrpat_reg = BCLRPAT_A;
                vtotal_reg = VTOTAL_A;
@@ -324,9 +352,10 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
        /* Set the border color to purple. */
        I915_WRITE(bclrpat_reg, 0x500050);
 
-       if (IS_I9XX(dev)) {
+       if (!IS_GEN2(dev)) {
                uint32_t pipeconf = I915_READ(pipeconf_reg);
                I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
+               POSTING_READ(pipeconf_reg);
                /* Wait for next Vblank to substitue
                 * border color for Color info */
                intel_wait_for_vblank(dev, pipe);
@@ -404,34 +433,37 @@ static enum drm_connector_status
 intel_crt_detect(struct drm_connector *connector, bool force)
 {
        struct drm_device *dev = connector->dev;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+       struct intel_encoder *encoder = intel_attached_encoder(connector);
        struct drm_crtc *crtc;
        int dpms_mode;
        enum drm_connector_status status;
 
-       if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
-               if (intel_crt_detect_hotplug(connector))
+       if (I915_HAS_HOTPLUG(dev)) {
+               if (intel_crt_detect_hotplug(connector)) {
+                       DRM_DEBUG_KMS("CRT detected via hotplug\n");
                        return connector_status_connected;
-               else
+               else
                        return connector_status_disconnected;
        }
 
-       if (intel_crt_detect_ddc(encoder))
+       if (intel_crt_detect_ddc(&encoder->base))
                return connector_status_connected;
 
        if (!force)
                return connector->status;
 
        /* for pre-945g platforms use load detect */
-       if (encoder->crtc && encoder->crtc->enabled) {
-               status = intel_crt_load_detect(encoder->crtc, intel_encoder);
+       if (encoder->base.crtc && encoder->base.crtc->enabled) {
+               status = intel_crt_load_detect(encoder->base.crtc, encoder);
        } else {
-               crtc = intel_get_load_detect_pipe(intel_encoder, connector,
+               crtc = intel_get_load_detect_pipe(encoder, connector,
                                                  NULL, &dpms_mode);
                if (crtc) {
-                       status = intel_crt_load_detect(crtc, intel_encoder);
-                       intel_release_load_detect_pipe(intel_encoder,
+                       if (intel_crt_detect_ddc(&encoder->base))
+                               status = connector_status_connected;
+                       else
+                               status = intel_crt_load_detect(crtc, encoder);
+                       intel_release_load_detect_pipe(encoder,
                                                       connector, dpms_mode);
                } else
                        status = connector_status_unknown;
@@ -449,32 +481,18 @@ static void intel_crt_destroy(struct drm_connector *connector)
 
 static int intel_crt_get_modes(struct drm_connector *connector)
 {
-       int ret;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-       struct i2c_adapter *ddc_bus;
        struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
 
-
-       ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
+       ret = intel_ddc_get_modes(connector,
+                                &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
        if (ret || !IS_G4X(dev))
-               goto end;
+               return ret;
 
        /* Try to probe digital port for output in DVI-I -> VGA mode. */
-       ddc_bus = intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
-
-       if (!ddc_bus) {
-               dev_printk(KERN_ERR, &connector->dev->pdev->dev,
-                          "DDC bus registration failed for CRTDDC_D.\n");
-               goto end;
-       }
-       /* Try to get modes by GPIOD port */
-       ret = intel_ddc_get_modes(connector, ddc_bus);
-       intel_i2c_destroy(ddc_bus);
-
-end:
-       return ret;
-
+       return intel_ddc_get_modes(connector,
+                                  &dev_priv->gmbus[GMBUS_PORT_DPB].adapter);
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
@@ -507,7 +525,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
        .mode_valid = intel_crt_mode_valid,
        .get_modes = intel_crt_get_modes,
-       .best_encoder = intel_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_crt_enc_funcs = {
@@ -520,7 +538,6 @@ void intel_crt_init(struct drm_device *dev)
        struct intel_encoder *intel_encoder;
        struct intel_connector *intel_connector;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 i2c_reg;
 
        intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
        if (!intel_encoder)
@@ -536,27 +553,10 @@ void intel_crt_init(struct drm_device *dev)
        drm_connector_init(dev, &intel_connector->base,
                           &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
 
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_crt_enc_funcs,
+       drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs,
                         DRM_MODE_ENCODER_DAC);
 
-       drm_mode_connector_attach_encoder(&intel_connector->base,
-                                         &intel_encoder->enc);
-
-       /* Set up the DDC bus. */
-       if (HAS_PCH_SPLIT(dev))
-               i2c_reg = PCH_GPIOA;
-       else {
-               i2c_reg = GPIOA;
-               /* Use VBT information for CRT DDC if available */
-               if (dev_priv->crt_ddc_bus != 0)
-                       i2c_reg = dev_priv->crt_ddc_bus;
-       }
-       intel_encoder->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
-       if (!intel_encoder->ddc_bus) {
-               dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
-                          "failed.\n");
-               return;
-       }
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
 
        intel_encoder->type = INTEL_OUTPUT_ANALOG;
        intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
@@ -566,7 +566,7 @@ void intel_crt_init(struct drm_device *dev)
        connector->interlace_allowed = 1;
        connector->doublescan_allowed = 0;
 
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs);
+       drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs);
        drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
 
        drm_sysfs_connector_add(connector);
index b5bf51a4502dc4f4e2ca4d2914673004c931c3b5..69c54c5a42546d21e4e46dd3958925664840d9e1 100644 (file)
@@ -43,8 +43,8 @@
 
 bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
 static void intel_update_watermarks(struct drm_device *dev);
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
-static void intel_crtc_update_cursor(struct drm_crtc *crtc);
+static void intel_increase_pllclock(struct drm_crtc *crtc);
+static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
 typedef struct {
     /* given values */
@@ -342,6 +342,13 @@ static bool
 intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
                           int target, int refclk, intel_clock_t *best_clock);
 
+static inline u32 /* units of 100MHz */
+intel_fdi_link_freq(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2;
+}
+
 static const intel_limit_t intel_limits_i8xx_dvo = {
         .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
         .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
@@ -701,16 +708,16 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
                limit = intel_ironlake_limit(crtc);
        else if (IS_G4X(dev)) {
                limit = intel_g4x_limit(crtc);
-       } else if (IS_I9XX(dev) && !IS_PINEVIEW(dev)) {
-               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-                       limit = &intel_limits_i9xx_lvds;
-               else
-                       limit = &intel_limits_i9xx_sdvo;
        } else if (IS_PINEVIEW(dev)) {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_pineview_lvds;
                else
                        limit = &intel_limits_pineview_sdvo;
+       } else if (!IS_GEN2(dev)) {
+               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+                       limit = &intel_limits_i9xx_lvds;
+               else
+                       limit = &intel_limits_i9xx_sdvo;
        } else {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_i8xx_lvds;
@@ -744,20 +751,17 @@ static void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock
 /**
  * Returns whether any output on the specified pipe is of the specified type
  */
-bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
+bool intel_pipe_has_type(struct drm_crtc *crtc, int type)
 {
-    struct drm_device *dev = crtc->dev;
-    struct drm_mode_config *mode_config = &dev->mode_config;
-    struct drm_encoder *l_entry;
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
 
-    list_for_each_entry(l_entry, &mode_config->encoder_list, head) {
-           if (l_entry && l_entry->crtc == crtc) {
-                   struct intel_encoder *intel_encoder = enc_to_intel_encoder(l_entry);
-                   if (intel_encoder->type == type)
-                           return true;
-           }
-    }
-    return false;
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+               if (encoder->base.crtc == crtc && encoder->type == type)
+                       return true;
+
+       return false;
 }
 
 #define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)
@@ -955,26 +959,26 @@ static bool
 intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
                      int target, int refclk, intel_clock_t *best_clock)
 {
-    intel_clock_t clock;
-    if (target < 200000) {
-       clock.p1 = 2;
-       clock.p2 = 10;
-       clock.n = 2;
-       clock.m1 = 23;
-       clock.m2 = 8;
-    } else {
-       clock.p1 = 1;
-       clock.p2 = 10;
-       clock.n = 1;
-       clock.m1 = 14;
-       clock.m2 = 2;
-    }
-    clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
-    clock.p = (clock.p1 * clock.p2);
-    clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
-    clock.vco = 0;
-    memcpy(best_clock, &clock, sizeof(intel_clock_t));
-    return true;
+       intel_clock_t clock;
+       if (target < 200000) {
+               clock.p1 = 2;
+               clock.p2 = 10;
+               clock.n = 2;
+               clock.m1 = 23;
+               clock.m2 = 8;
+       } else {
+               clock.p1 = 1;
+               clock.p2 = 10;
+               clock.n = 1;
+               clock.m1 = 14;
+               clock.m2 = 2;
+       }
+       clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
+       clock.p = (clock.p1 * clock.p2);
+       clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
+       clock.vco = 0;
+       memcpy(best_clock, &clock, sizeof(intel_clock_t));
+       return true;
 }
 
 /**
@@ -1007,14 +1011,14 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
                   I915_READ(pipestat_reg) | PIPE_VBLANK_INTERRUPT_STATUS);
 
        /* Wait for vblank interrupt bit to set */
-       if (wait_for((I915_READ(pipestat_reg) &
-                     PIPE_VBLANK_INTERRUPT_STATUS),
-                    50, 0))
+       if (wait_for(I915_READ(pipestat_reg) &
+                    PIPE_VBLANK_INTERRUPT_STATUS,
+                    50))
                DRM_DEBUG_KMS("vblank wait timed out\n");
 }
 
-/**
- * intel_wait_for_vblank_off - wait for vblank after disabling a pipe
+/*
+ * intel_wait_for_pipe_off - wait for pipe to turn off
  * @dev: drm device
  * @pipe: pipe to wait for
  *
@@ -1022,28 +1026,41 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
  * spinning on the vblank interrupt status bit, since we won't actually
  * see an interrupt when the pipe is disabled.
  *
- * So this function waits for the display line value to settle (it
- * usually ends up stopping at the start of the next frame).
+ * On Gen4 and above:
+ *   wait for the pipe register state bit to turn off
+ *
+ * Otherwise:
+ *   wait for the display line value to settle (it usually
+ *   ends up stopping at the start of the next frame).
+ *
  */
-void intel_wait_for_vblank_off(struct drm_device *dev, int pipe)
+void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
-       unsigned long timeout = jiffies + msecs_to_jiffies(100);
-       u32 last_line;
-
-       /* Wait for the display line to settle */
-       do {
-               last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
-               mdelay(5);
-       } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
-                time_after(timeout, jiffies));
-
-       if (time_after(jiffies, timeout))
-               DRM_DEBUG_KMS("vblank wait timed out\n");
+
+       if (INTEL_INFO(dev)->gen >= 4) {
+               int reg = PIPECONF(pipe);
+
+               /* Wait for the Pipe State to go off */
+               if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
+                            100))
+                       DRM_DEBUG_KMS("pipe_off wait timed out\n");
+       } else {
+               u32 last_line;
+               int reg = PIPEDSL(pipe);
+               unsigned long timeout = jiffies + msecs_to_jiffies(100);
+
+               /* Wait for the display line to settle */
+               do {
+                       last_line = I915_READ(reg) & DSL_LINEMASK;
+                       mdelay(5);
+               } while (((I915_READ(reg) & DSL_LINEMASK) != last_line) &&
+                        time_after(timeout, jiffies));
+               if (time_after(jiffies, timeout))
+                       DRM_DEBUG_KMS("pipe_off wait timed out\n");
+       }
 }
 
-/* Parameters have changed, update FBC info */
 static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
        struct drm_device *dev = crtc->dev;
@@ -1055,6 +1072,14 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        int plane, i;
        u32 fbc_ctl, fbc_ctl2;
 
+       if (fb->pitch == dev_priv->cfb_pitch &&
+           obj_priv->fence_reg == dev_priv->cfb_fence &&
+           intel_crtc->plane == dev_priv->cfb_plane &&
+           I915_READ(FBC_CONTROL) & FBC_CTL_EN)
+               return;
+
+       i8xx_disable_fbc(dev);
+
        dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
 
        if (fb->pitch < dev_priv->cfb_pitch)
@@ -1088,7 +1113,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 
        DRM_DEBUG_KMS("enabled FBC, pitch %ld, yoff %d, plane %d, ",
-                 dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
+                     dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
 }
 
 void i8xx_disable_fbc(struct drm_device *dev)
@@ -1096,19 +1121,16 @@ void i8xx_disable_fbc(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 fbc_ctl;
 
-       if (!I915_HAS_FBC(dev))
-               return;
-
-       if (!(I915_READ(FBC_CONTROL) & FBC_CTL_EN))
-               return; /* Already off, just return */
-
        /* Disable compression */
        fbc_ctl = I915_READ(FBC_CONTROL);
+       if ((fbc_ctl & FBC_CTL_EN) == 0)
+               return;
+
        fbc_ctl &= ~FBC_CTL_EN;
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 
        /* Wait for compressing bit to clear */
-       if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) {
+       if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
                DRM_DEBUG_KMS("FBC idle timed out\n");
                return;
        }
@@ -1131,14 +1153,27 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA :
-                    DPFC_CTL_PLANEB);
+       int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
        unsigned long stall_watermark = 200;
        u32 dpfc_ctl;
 
+       dpfc_ctl = I915_READ(DPFC_CONTROL);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+                   dev_priv->cfb_fence == obj_priv->fence_reg &&
+                   dev_priv->cfb_plane == intel_crtc->plane &&
+                   dev_priv->cfb_y == crtc->y)
+                       return;
+
+               I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+               POSTING_READ(DPFC_CONTROL);
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       }
+
        dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
        dev_priv->cfb_fence = obj_priv->fence_reg;
        dev_priv->cfb_plane = intel_crtc->plane;
+       dev_priv->cfb_y = crtc->y;
 
        dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
        if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1148,7 +1183,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
                I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY);
        }
 
-       I915_WRITE(DPFC_CONTROL, dpfc_ctl);
        I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
                   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
                   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
@@ -1167,10 +1201,12 @@ void g4x_disable_fbc(struct drm_device *dev)
 
        /* Disable compression */
        dpfc_ctl = I915_READ(DPFC_CONTROL);
-       dpfc_ctl &= ~DPFC_CTL_EN;
-       I915_WRITE(DPFC_CONTROL, dpfc_ctl);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               dpfc_ctl &= ~DPFC_CTL_EN;
+               I915_WRITE(DPFC_CONTROL, dpfc_ctl);
 
-       DRM_DEBUG_KMS("disabled FBC\n");
+               DRM_DEBUG_KMS("disabled FBC\n");
+       }
 }
 
 static bool g4x_fbc_enabled(struct drm_device *dev)
@@ -1188,16 +1224,30 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int plane = (intel_crtc->plane == 0) ? DPFC_CTL_PLANEA :
-                                              DPFC_CTL_PLANEB;
+       int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
        unsigned long stall_watermark = 200;
        u32 dpfc_ctl;
 
+       dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+                   dev_priv->cfb_fence == obj_priv->fence_reg &&
+                   dev_priv->cfb_plane == intel_crtc->plane &&
+                   dev_priv->cfb_offset == obj_priv->gtt_offset &&
+                   dev_priv->cfb_y == crtc->y)
+                       return;
+
+               I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+               POSTING_READ(ILK_DPFC_CONTROL);
+               intel_wait_for_vblank(dev, intel_crtc->pipe);
+       }
+
        dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
        dev_priv->cfb_fence = obj_priv->fence_reg;
        dev_priv->cfb_plane = intel_crtc->plane;
+       dev_priv->cfb_offset = obj_priv->gtt_offset;
+       dev_priv->cfb_y = crtc->y;
 
-       dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
        dpfc_ctl &= DPFC_RESERVED;
        dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
        if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1207,15 +1257,13 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
                I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY);
        }
 
-       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
        I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
                   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
                   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
        I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
        I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID);
        /* enable it... */
-       I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) |
-                  DPFC_CTL_EN);
+       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
        DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
 }
@@ -1227,10 +1275,12 @@ void ironlake_disable_fbc(struct drm_device *dev)
 
        /* Disable compression */
        dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
-       dpfc_ctl &= ~DPFC_CTL_EN;
-       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+       if (dpfc_ctl & DPFC_CTL_EN) {
+               dpfc_ctl &= ~DPFC_CTL_EN;
+               I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
 
-       DRM_DEBUG_KMS("disabled FBC\n");
+               DRM_DEBUG_KMS("disabled FBC\n");
+       }
 }
 
 static bool ironlake_fbc_enabled(struct drm_device *dev)
@@ -1272,8 +1322,7 @@ void intel_disable_fbc(struct drm_device *dev)
 
 /**
  * intel_update_fbc - enable/disable FBC as needed
- * @crtc: CRTC to point the compressor at
- * @mode: mode in use
+ * @dev: the drm_device
  *
  * Set up the framebuffer compression hardware at mode set time.  We
  * enable it if possible:
@@ -1290,18 +1339,14 @@ void intel_disable_fbc(struct drm_device *dev)
  *
  * We need to enable/disable FBC on a global basis.
  */
-static void intel_update_fbc(struct drm_crtc *crtc,
-                            struct drm_display_mode *mode)
+static void intel_update_fbc(struct drm_device *dev)
 {
-       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_crtc *crtc = NULL, *tmp_crtc;
+       struct intel_crtc *intel_crtc;
+       struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
        struct drm_i915_gem_object *obj_priv;
-       struct drm_crtc *tmp_crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int plane = intel_crtc->plane;
-       int crtcs_enabled = 0;
 
        DRM_DEBUG_KMS("\n");
 
@@ -1311,12 +1356,6 @@ static void intel_update_fbc(struct drm_crtc *crtc,
        if (!I915_HAS_FBC(dev))
                return;
 
-       if (!crtc->fb)
-               return;
-
-       intel_fb = to_intel_framebuffer(fb);
-       obj_priv = to_intel_bo(intel_fb->obj);
-
        /*
         * If FBC is already on, we just have to verify that we can
         * keep it that way...
@@ -1327,35 +1366,47 @@ static void intel_update_fbc(struct drm_crtc *crtc,
         *   - going to an unsupported config (interlace, pixel multiply, etc.)
         */
        list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
-               if (tmp_crtc->enabled)
-                       crtcs_enabled++;
+               if (tmp_crtc->enabled) {
+                       if (crtc) {
+                               DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+                               dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+                               goto out_disable;
+                       }
+                       crtc = tmp_crtc;
+               }
        }
-       DRM_DEBUG_KMS("%d pipes active\n", crtcs_enabled);
-       if (crtcs_enabled > 1) {
-               DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
-               dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+
+       if (!crtc || crtc->fb == NULL) {
+               DRM_DEBUG_KMS("no output, disabling\n");
+               dev_priv->no_fbc_reason = FBC_NO_OUTPUT;
                goto out_disable;
        }
+
+       intel_crtc = to_intel_crtc(crtc);
+       fb = crtc->fb;
+       intel_fb = to_intel_framebuffer(fb);
+       obj_priv = to_intel_bo(intel_fb->obj);
+
        if (intel_fb->obj->size > dev_priv->cfb_size) {
                DRM_DEBUG_KMS("framebuffer too large, disabling "
-                               "compression\n");
+                             "compression\n");
                dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
                goto out_disable;
        }
-       if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
-           (mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
+       if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
+           (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
                DRM_DEBUG_KMS("mode incompatible with compression, "
-                               "disabling\n");
+                             "disabling\n");
                dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
                goto out_disable;
        }
-       if ((mode->hdisplay > 2048) ||
-           (mode->vdisplay > 1536)) {
+       if ((crtc->mode.hdisplay > 2048) ||
+           (crtc->mode.vdisplay > 1536)) {
                DRM_DEBUG_KMS("mode too large for compression, disabling\n");
                dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
                goto out_disable;
        }
-       if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
+       if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
                DRM_DEBUG_KMS("plane not 0, disabling compression\n");
                dev_priv->no_fbc_reason = FBC_BAD_PLANE;
                goto out_disable;
@@ -1370,18 +1421,7 @@ static void intel_update_fbc(struct drm_crtc *crtc,
        if (in_dbg_master())
                goto out_disable;
 
-       if (intel_fbc_enabled(dev)) {
-               /* We can re-enable it in this case, but need to update pitch */
-               if ((fb->pitch > dev_priv->cfb_pitch) ||
-                   (obj_priv->fence_reg != dev_priv->cfb_fence) ||
-                   (plane != dev_priv->cfb_plane))
-                       intel_disable_fbc(dev);
-       }
-
-       /* Now try to turn it back on if possible */
-       if (!intel_fbc_enabled(dev))
-               intel_enable_fbc(crtc, 500);
-
+       intel_enable_fbc(crtc, 500);
        return;
 
 out_disable:
@@ -1393,7 +1433,9 @@ out_disable:
 }
 
 int
-intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
+intel_pin_and_fence_fb_obj(struct drm_device *dev,
+                          struct drm_gem_object *obj,
+                          bool pipelined)
 {
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        u32 alignment;
@@ -1403,7 +1445,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
        case I915_TILING_NONE:
                if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
                        alignment = 128 * 1024;
-               else if (IS_I965G(dev))
+               else if (INTEL_INFO(dev)->gen >= 4)
                        alignment = 4 * 1024;
                else
                        alignment = 64 * 1024;
@@ -1421,9 +1463,13 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
        }
 
        ret = i915_gem_object_pin(obj, alignment);
-       if (ret != 0)
+       if (ret)
                return ret;
 
+       ret = i915_gem_object_set_to_display_plane(obj, pipelined);
+       if (ret)
+               goto err_unpin;
+
        /* Install a fence for tiled scan-out. Pre-i965 always needs a
         * fence, whereas 965+ only requires a fence if using
         * framebuffer compression.  For simplicity, we always install
@@ -1431,14 +1477,16 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
         */
        if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
            obj_priv->tiling_mode != I915_TILING_NONE) {
-               ret = i915_gem_object_get_fence_reg(obj);
-               if (ret != 0) {
-                       i915_gem_object_unpin(obj);
-                       return ret;
-               }
+               ret = i915_gem_object_get_fence_reg(obj, false);
+               if (ret)
+                       goto err_unpin;
        }
 
        return 0;
+
+err_unpin:
+       i915_gem_object_unpin(obj);
+       return ret;
 }
 
 /* Assume fb object is pinned & idle & fenced and just update base pointers */
@@ -1454,12 +1502,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        struct drm_gem_object *obj;
        int plane = intel_crtc->plane;
        unsigned long Start, Offset;
-       int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
-       int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
-       int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
-       int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
        u32 dspcntr;
+       u32 reg;
 
        switch (plane) {
        case 0:
@@ -1474,7 +1518,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        obj = intel_fb->obj;
        obj_priv = to_intel_bo(obj);
 
-       dspcntr = I915_READ(dspcntr_reg);
+       reg = DSPCNTR(plane);
+       dspcntr = I915_READ(reg);
        /* Mask out pixel format bits in case we change it */
        dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
        switch (fb->bits_per_pixel) {
@@ -1495,7 +1540,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                DRM_ERROR("Unknown color depth\n");
                return -EINVAL;
        }
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                if (obj_priv->tiling_mode != I915_TILING_NONE)
                        dspcntr |= DISPPLANE_TILED;
                else
@@ -1506,28 +1551,24 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                /* must disable */
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-       I915_WRITE(dspcntr_reg, dspcntr);
+       I915_WRITE(reg, dspcntr);
 
        Start = obj_priv->gtt_offset;
        Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
 
        DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
                      Start, Offset, x, y, fb->pitch);
-       I915_WRITE(dspstride, fb->pitch);
-       if (IS_I965G(dev)) {
-               I915_WRITE(dspsurf, Start);
-               I915_WRITE(dsptileoff, (y << 16) | x);
-               I915_WRITE(dspbase, Offset);
-       } else {
-               I915_WRITE(dspbase, Start + Offset);
-       }
-       POSTING_READ(dspbase);
-
-       if (IS_I965G(dev) || plane == 0)
-               intel_update_fbc(crtc, &crtc->mode);
+       I915_WRITE(DSPSTRIDE(plane), fb->pitch);
+       if (INTEL_INFO(dev)->gen >= 4) {
+               I915_WRITE(DSPSURF(plane), Start);
+               I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
+               I915_WRITE(DSPADDR(plane), Offset);
+       } else
+               I915_WRITE(DSPADDR(plane), Start + Offset);
+       POSTING_READ(reg);
 
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
-       intel_increase_pllclock(crtc, true);
+       intel_update_fbc(dev);
+       intel_increase_pllclock(crtc);
 
        return 0;
 }
@@ -1539,11 +1580,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        struct drm_device *dev = crtc->dev;
        struct drm_i915_master_private *master_priv;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_framebuffer *intel_fb;
-       struct drm_i915_gem_object *obj_priv;
-       struct drm_gem_object *obj;
-       int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
        int ret;
 
        /* no fb bound */
@@ -1552,45 +1588,41 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                return 0;
        }
 
-       switch (plane) {
+       switch (intel_crtc->plane) {
        case 0:
        case 1:
                break;
        default:
-               DRM_ERROR("Can't update plane %d in SAREA\n", plane);
                return -EINVAL;
        }
 
-       intel_fb = to_intel_framebuffer(crtc->fb);
-       obj = intel_fb->obj;
-       obj_priv = to_intel_bo(obj);
-
        mutex_lock(&dev->struct_mutex);
-       ret = intel_pin_and_fence_fb_obj(dev, obj);
+       ret = intel_pin_and_fence_fb_obj(dev,
+                                        to_intel_framebuffer(crtc->fb)->obj,
+                                        false);
        if (ret != 0) {
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
 
-       ret = i915_gem_object_set_to_display_plane(obj);
-       if (ret != 0) {
-               i915_gem_object_unpin(obj);
-               mutex_unlock(&dev->struct_mutex);
-               return ret;
+       if (old_fb) {
+               struct drm_i915_private *dev_priv = dev->dev_private;
+               struct drm_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
+               struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+
+               wait_event(dev_priv->pending_flip_queue,
+                          atomic_read(&obj_priv->pending_flip) == 0);
        }
 
        ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y);
        if (ret) {
-               i915_gem_object_unpin(obj);
+               i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
 
-       if (old_fb) {
-               intel_fb = to_intel_framebuffer(old_fb);
-               obj_priv = to_intel_bo(intel_fb->obj);
-               i915_gem_object_unpin(intel_fb->obj);
-       }
+       if (old_fb)
+               i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj);
 
        mutex_unlock(&dev->struct_mutex);
 
@@ -1601,7 +1633,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        if (!master_priv->sarea_priv)
                return 0;
 
-       if (pipe) {
+       if (intel_crtc->pipe) {
                master_priv->sarea_priv->pipeB_x = x;
                master_priv->sarea_priv->pipeB_y = y;
        } else {
@@ -1612,7 +1644,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        return 0;
 }
 
-static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
+static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1645,6 +1677,7 @@ static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
        }
        I915_WRITE(DP_A, dpa_ctl);
 
+       POSTING_READ(DP_A);
        udelay(500);
 }
 
@@ -1655,84 +1688,84 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
-       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
-       u32 temp, tries = 0;
+       u32 reg, temp, tries;
 
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
-       temp = I915_READ(fdi_rx_imr_reg);
+       reg = FDI_RX_IMR(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_RX_SYMBOL_LOCK;
        temp &= ~FDI_RX_BIT_LOCK;
-       I915_WRITE(fdi_rx_imr_reg, temp);
-       I915_READ(fdi_rx_imr_reg);
+       I915_WRITE(reg, temp);
+       I915_READ(reg);
        udelay(150);
 
        /* enable CPU FDI TX and PCH FDI RX */
-       temp = I915_READ(fdi_tx_reg);
-       temp |= FDI_TX_ENABLE;
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~(7 << 19);
        temp |= (intel_crtc->fdi_lanes - 1) << 19;
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_1;
-       I915_WRITE(fdi_tx_reg, temp);
-       I915_READ(fdi_tx_reg);
+       I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_1;
-       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-       I915_READ(fdi_rx_reg);
+       I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
        udelay(150);
 
+       reg = FDI_RX_IIR(pipe);
        for (tries = 0; tries < 5; tries++) {
-               temp = I915_READ(fdi_rx_iir_reg);
+               temp = I915_READ(reg);
                DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
                if ((temp & FDI_RX_BIT_LOCK)) {
                        DRM_DEBUG_KMS("FDI train 1 done.\n");
-                       I915_WRITE(fdi_rx_iir_reg,
-                                  temp | FDI_RX_BIT_LOCK);
+                       I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
                        break;
                }
        }
        if (tries == 5)
-               DRM_DEBUG_KMS("FDI train 1 fail!\n");
+               DRM_ERROR("FDI train 1 fail!\n");
 
        /* Train 2 */
-       temp = I915_READ(fdi_tx_reg);
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_2;
-       I915_WRITE(fdi_tx_reg, temp);
+       I915_WRITE(reg, temp);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_2;
-       I915_WRITE(fdi_rx_reg, temp);
-       udelay(150);
+       I915_WRITE(reg, temp);
 
-       tries = 0;
+       POSTING_READ(reg);
+       udelay(150);
 
+       reg = FDI_RX_IIR(pipe);
        for (tries = 0; tries < 5; tries++) {
-               temp = I915_READ(fdi_rx_iir_reg);
+               temp = I915_READ(reg);
                DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
                if (temp & FDI_RX_SYMBOL_LOCK) {
-                       I915_WRITE(fdi_rx_iir_reg,
-                                  temp | FDI_RX_SYMBOL_LOCK);
+                       I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
                        DRM_DEBUG_KMS("FDI train 2 done.\n");
                        break;
                }
        }
        if (tries == 5)
-               DRM_DEBUG_KMS("FDI train 2 fail!\n");
+               DRM_ERROR("FDI train 2 fail!\n");
 
        DRM_DEBUG_KMS("FDI train done\n");
 }
 
-static int snb_b_fdi_train_param [] = {
+static const int const snb_b_fdi_train_param [] = {
        FDI_LINK_TRAIN_400MV_0DB_SNB_B,
        FDI_LINK_TRAIN_400MV_6DB_SNB_B,
        FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
@@ -1746,24 +1779,22 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-       int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
-       int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
-       u32 temp, i;
+       u32 reg, temp, i;
 
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
-       temp = I915_READ(fdi_rx_imr_reg);
+       reg = FDI_RX_IMR(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_RX_SYMBOL_LOCK;
        temp &= ~FDI_RX_BIT_LOCK;
-       I915_WRITE(fdi_rx_imr_reg, temp);
-       I915_READ(fdi_rx_imr_reg);
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
        udelay(150);
 
        /* enable CPU FDI TX and PCH FDI RX */
-       temp = I915_READ(fdi_tx_reg);
-       temp |= FDI_TX_ENABLE;
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~(7 << 19);
        temp |= (intel_crtc->fdi_lanes - 1) << 19;
        temp &= ~FDI_LINK_TRAIN_NONE;
@@ -1771,10 +1802,10 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
        /* SNB-B */
        temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
-       I915_WRITE(fdi_tx_reg, temp);
-       I915_READ(fdi_tx_reg);
+       I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        if (HAS_PCH_CPT(dev)) {
                temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
                temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
@@ -1782,32 +1813,37 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                temp &= ~FDI_LINK_TRAIN_NONE;
                temp |= FDI_LINK_TRAIN_PATTERN_1;
        }
-       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-       I915_READ(fdi_rx_reg);
+       I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
        udelay(150);
 
        for (i = 0; i < 4; i++ ) {
-               temp = I915_READ(fdi_tx_reg);
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
                temp |= snb_b_fdi_train_param[i];
-               I915_WRITE(fdi_tx_reg, temp);
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
                udelay(500);
 
-               temp = I915_READ(fdi_rx_iir_reg);
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(reg);
                DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
                if (temp & FDI_RX_BIT_LOCK) {
-                       I915_WRITE(fdi_rx_iir_reg,
-                                  temp | FDI_RX_BIT_LOCK);
+                       I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
                        DRM_DEBUG_KMS("FDI train 1 done.\n");
                        break;
                }
        }
        if (i == 4)
-               DRM_DEBUG_KMS("FDI train 1 fail!\n");
+               DRM_ERROR("FDI train 1 fail!\n");
 
        /* Train 2 */
-       temp = I915_READ(fdi_tx_reg);
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_NONE;
        temp |= FDI_LINK_TRAIN_PATTERN_2;
        if (IS_GEN6(dev)) {
@@ -1815,9 +1851,10 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                /* SNB-B */
                temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
        }
-       I915_WRITE(fdi_tx_reg, temp);
+       I915_WRITE(reg, temp);
 
-       temp = I915_READ(fdi_rx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
        if (HAS_PCH_CPT(dev)) {
                temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
                temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
@@ -1825,446 +1862,600 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                temp &= ~FDI_LINK_TRAIN_NONE;
                temp |= FDI_LINK_TRAIN_PATTERN_2;
        }
-       I915_WRITE(fdi_rx_reg, temp);
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
        udelay(150);
 
        for (i = 0; i < 4; i++ ) {
-               temp = I915_READ(fdi_tx_reg);
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
                temp |= snb_b_fdi_train_param[i];
-               I915_WRITE(fdi_tx_reg, temp);
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
                udelay(500);
 
-               temp = I915_READ(fdi_rx_iir_reg);
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(reg);
                DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
                if (temp & FDI_RX_SYMBOL_LOCK) {
-                       I915_WRITE(fdi_rx_iir_reg,
-                                  temp | FDI_RX_SYMBOL_LOCK);
+                       I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
                        DRM_DEBUG_KMS("FDI train 2 done.\n");
                        break;
                }
        }
        if (i == 4)
-               DRM_DEBUG_KMS("FDI train 2 fail!\n");
+               DRM_ERROR("FDI train 2 fail!\n");
 
        DRM_DEBUG_KMS("FDI train done.\n");
 }
 
-static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void ironlake_fdi_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
-       int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-       int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
-       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-       int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
-       int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-       int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-       int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-       int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-       int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-       int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-       int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B;
-       int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B;
-       int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B;
-       int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
-       int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
-       int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
-       int trans_dpll_sel = (pipe == 0) ? 0 : 1;
-       u32 temp;
-       u32 pipe_bpc;
-
-       temp = I915_READ(pipeconf_reg);
-       pipe_bpc = temp & PIPE_BPC_MASK;
+       u32 reg, temp;
 
-       /* XXX: When our outputs are all unaware of DPMS modes other than off
-        * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
-        */
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-               DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+       /* Write the TU size bits so error detection works */
+       I915_WRITE(FDI_RX_TUSIZE1(pipe),
+                  I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
 
-               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-                       temp = I915_READ(PCH_LVDS);
-                       if ((temp & LVDS_PORT_EN) == 0) {
-                               I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
-                               POSTING_READ(PCH_LVDS);
-                       }
-               }
+       /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~((0x7 << 19) | (0x7 << 16));
+       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+       temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+       I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
 
-               if (!HAS_eDP) {
+       POSTING_READ(reg);
+       udelay(200);
 
-                       /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
-                       temp = I915_READ(fdi_rx_reg);
-                       /*
-                        * make the BPC in FDI Rx be consistent with that in
-                        * pipeconf reg.
-                        */
-                       temp &= ~(0x7 << 16);
-                       temp |= (pipe_bpc << 11);
-                       temp &= ~(7 << 19);
-                       temp |= (intel_crtc->fdi_lanes - 1) << 19;
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
-                       I915_READ(fdi_rx_reg);
-                       udelay(200);
+       /* Switch from Rawclk to PCDclk */
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp | FDI_PCDCLK);
 
-                       /* Switch from Rawclk to PCDclk */
-                       temp = I915_READ(fdi_rx_reg);
-                       I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
-                       I915_READ(fdi_rx_reg);
-                       udelay(200);
+       POSTING_READ(reg);
+       udelay(200);
 
-                       /* Enable CPU FDI TX PLL, always on for Ironlake */
-                       temp = I915_READ(fdi_tx_reg);
-                       if ((temp & FDI_TX_PLL_ENABLE) == 0) {
-                               I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
-                               I915_READ(fdi_tx_reg);
-                               udelay(100);
-                       }
-               }
+       /* Enable CPU FDI TX PLL, always on for Ironlake */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+               I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
 
-               /* Enable panel fitting for LVDS */
-               if (dev_priv->pch_pf_size &&
-                   (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
-                   || HAS_eDP || intel_pch_has_edp(crtc))) {
-                       /* Force use of hard-coded filter coefficients
-                        * as some pre-programmed values are broken,
-                        * e.g. x201.
-                        */
-                       I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
-                                  PF_ENABLE | PF_FILTER_MED_3x3);
-                       I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
-                                  dev_priv->pch_pf_pos);
-                       I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
-                                  dev_priv->pch_pf_size);
-               }
+               POSTING_READ(reg);
+               udelay(100);
+       }
+}
 
-               /* Enable CPU pipe */
-               temp = I915_READ(pipeconf_reg);
-               if ((temp & PIPEACONF_ENABLE) == 0) {
-                       I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
-                       I915_READ(pipeconf_reg);
-                       udelay(100);
-               }
+static void intel_flush_display_plane(struct drm_device *dev,
+                                     int plane)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg = DSPADDR(plane);
+       I915_WRITE(reg, I915_READ(reg));
+}
 
-               /* configure and enable CPU plane */
-               temp = I915_READ(dspcntr_reg);
-               if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-                       I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
-                       /* Flush the plane changes */
-                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-               }
+/*
+ * When we disable a pipe, we need to clear any pending scanline wait events
+ * to avoid hanging the ring, which we assume we are waiting on.
+ */
+static void intel_clear_scanline_wait(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp;
 
-               if (!HAS_eDP) {
-                       /* For PCH output, training FDI link */
-                       if (IS_GEN6(dev))
-                               gen6_fdi_link_train(crtc);
-                       else
-                               ironlake_fdi_link_train(crtc);
+       if (IS_GEN2(dev))
+               /* Can't break the hang on i8xx */
+               return;
 
-                       /* enable PCH DPLL */
-                       temp = I915_READ(pch_dpll_reg);
-                       if ((temp & DPLL_VCO_ENABLE) == 0) {
-                               I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
-                               I915_READ(pch_dpll_reg);
-                       }
-                       udelay(200);
+       tmp = I915_READ(PRB0_CTL);
+       if (tmp & RING_WAIT) {
+               I915_WRITE(PRB0_CTL, tmp);
+               POSTING_READ(PRB0_CTL);
+       }
+}
 
-                       if (HAS_PCH_CPT(dev)) {
-                               /* Be sure PCH DPLL SEL is set */
-                               temp = I915_READ(PCH_DPLL_SEL);
-                               if (trans_dpll_sel == 0 &&
-                                               (temp & TRANSA_DPLL_ENABLE) == 0)
-                                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
-                               else if (trans_dpll_sel == 1 &&
-                                               (temp & TRANSB_DPLL_ENABLE) == 0)
-                                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
-                               I915_WRITE(PCH_DPLL_SEL, temp);
-                               I915_READ(PCH_DPLL_SEL);
-                       }
+static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
+{
+       struct drm_i915_gem_object *obj_priv;
+       struct drm_i915_private *dev_priv;
 
-                       /* set transcoder timing */
-                       I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
-                       I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
-                       I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
-
-                       I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
-                       I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
-                       I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
-
-                       /* enable normal train */
-                       temp = I915_READ(fdi_tx_reg);
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
-                                       FDI_TX_ENHANCE_FRAME_ENABLE);
-                       I915_READ(fdi_tx_reg);
-
-                       temp = I915_READ(fdi_rx_reg);
-                       if (HAS_PCH_CPT(dev)) {
-                               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-                               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
-                       } else {
-                               temp &= ~FDI_LINK_TRAIN_NONE;
-                               temp |= FDI_LINK_TRAIN_NONE;
-                       }
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
-                       I915_READ(fdi_rx_reg);
+       if (crtc->fb == NULL)
+               return;
 
-                       /* wait one idle pattern time */
-                       udelay(100);
+       obj_priv = to_intel_bo(to_intel_framebuffer(crtc->fb)->obj);
+       dev_priv = crtc->dev->dev_private;
+       wait_event(dev_priv->pending_flip_queue,
+                  atomic_read(&obj_priv->pending_flip) == 0);
+}
 
-                       /* For PCH DP, enable TRANS_DP_CTL */
-                       if (HAS_PCH_CPT(dev) &&
-                           intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
-                               int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
-                               int reg;
-
-                               reg = I915_READ(trans_dp_ctl);
-                               reg &= ~(TRANS_DP_PORT_SEL_MASK |
-                                        TRANS_DP_SYNC_MASK);
-                               reg |= (TRANS_DP_OUTPUT_ENABLE |
-                                       TRANS_DP_ENH_FRAMING);
-
-                               if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
-                                     reg |= TRANS_DP_HSYNC_ACTIVE_HIGH;
-                               if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
-                                     reg |= TRANS_DP_VSYNC_ACTIVE_HIGH;
-
-                               switch (intel_trans_dp_port_sel(crtc)) {
-                               case PCH_DP_B:
-                                       reg |= TRANS_DP_PORT_SEL_B;
-                                       break;
-                               case PCH_DP_C:
-                                       reg |= TRANS_DP_PORT_SEL_C;
-                                       break;
-                               case PCH_DP_D:
-                                       reg |= TRANS_DP_PORT_SEL_D;
-                                       break;
-                               default:
-                                       DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
-                                       reg |= TRANS_DP_PORT_SEL_B;
-                                       break;
-                               }
+static void ironlake_crtc_enable(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+       u32 reg, temp;
 
-                               I915_WRITE(trans_dp_ctl, reg);
-                               POSTING_READ(trans_dp_ctl);
-                       }
+       if (intel_crtc->active)
+               return;
 
-                       /* enable PCH transcoder */
-                       temp = I915_READ(transconf_reg);
-                       /*
-                        * make the BPC in transcoder be consistent with
-                        * that in pipeconf reg.
-                        */
-                       temp &= ~PIPE_BPC_MASK;
-                       temp |= pipe_bpc;
-                       I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
-                       I915_READ(transconf_reg);
+       intel_crtc->active = true;
+       intel_update_watermarks(dev);
 
-                       if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100, 1))
-                               DRM_ERROR("failed to enable transcoder\n");
-               }
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+               temp = I915_READ(PCH_LVDS);
+               if ((temp & LVDS_PORT_EN) == 0)
+                       I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
+       }
 
-               intel_crtc_load_lut(crtc);
+       ironlake_fdi_enable(crtc);
 
-               intel_update_fbc(crtc, &crtc->mode);
-               break;
+       /* Enable panel fitting for LVDS */
+       if (dev_priv->pch_pf_size &&
+           (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
+            || HAS_eDP || intel_pch_has_edp(crtc))) {
+               /* Force use of hard-coded filter coefficients
+                * as some pre-programmed values are broken,
+                * e.g. x201.
+                */
+               I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
+                          PF_ENABLE | PF_FILTER_MED_3x3);
+               I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
+                          dev_priv->pch_pf_pos);
+               I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
+                          dev_priv->pch_pf_size);
+       }
+
+       /* Enable CPU pipe */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if ((temp & PIPECONF_ENABLE) == 0) {
+               I915_WRITE(reg, temp | PIPECONF_ENABLE);
+               POSTING_READ(reg);
+               udelay(100);
+       }
 
-       case DRM_MODE_DPMS_OFF:
-               DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+       /* configure and enable CPU plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+               I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+               intel_flush_display_plane(dev, plane);
+       }
 
-               drm_vblank_off(dev, pipe);
-               /* Disable display plane */
-               temp = I915_READ(dspcntr_reg);
-               if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-                       I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
-                       /* Flush the plane changes */
-                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-                       I915_READ(dspbase_reg);
+       /* For PCH output, training FDI link */
+       if (IS_GEN6(dev))
+               gen6_fdi_link_train(crtc);
+       else
+               ironlake_fdi_link_train(crtc);
+
+       /* enable PCH DPLL */
+       reg = PCH_DPLL(pipe);
+       temp = I915_READ(reg);
+       if ((temp & DPLL_VCO_ENABLE) == 0) {
+               I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+               POSTING_READ(reg);
+               udelay(200);
+       }
+
+       if (HAS_PCH_CPT(dev)) {
+               /* Be sure PCH DPLL SEL is set */
+               temp = I915_READ(PCH_DPLL_SEL);
+               if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0)
+                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+               else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0)
+                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+               I915_WRITE(PCH_DPLL_SEL, temp);
+       }
+
+       /* set transcoder timing */
+       I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe)));
+       I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe)));
+       I915_WRITE(TRANS_HSYNC(pipe),  I915_READ(HSYNC(pipe)));
+
+       I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
+       I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
+       I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
+
+       /* enable normal train */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       I915_WRITE(reg, temp);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_NONE;
+       }
+       I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+
+       /* wait one idle pattern time */
+       POSTING_READ(reg);
+       udelay(100);
+
+       /* For PCH DP, enable TRANS_DP_CTL */
+       if (HAS_PCH_CPT(dev) &&
+           intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+               reg = TRANS_DP_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~(TRANS_DP_PORT_SEL_MASK |
+                         TRANS_DP_SYNC_MASK);
+               temp |= (TRANS_DP_OUTPUT_ENABLE |
+                        TRANS_DP_ENH_FRAMING);
+
+               if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
+                       temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
+               if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
+                       temp |= TRANS_DP_VSYNC_ACTIVE_HIGH;
+
+               switch (intel_trans_dp_port_sel(crtc)) {
+               case PCH_DP_B:
+                       temp |= TRANS_DP_PORT_SEL_B;
+                       break;
+               case PCH_DP_C:
+                       temp |= TRANS_DP_PORT_SEL_C;
+                       break;
+               case PCH_DP_D:
+                       temp |= TRANS_DP_PORT_SEL_D;
+                       break;
+               default:
+                       DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
+                       temp |= TRANS_DP_PORT_SEL_B;
+                       break;
                }
 
-               if (dev_priv->cfb_plane == plane &&
-                   dev_priv->display.disable_fbc)
-                       dev_priv->display.disable_fbc(dev);
+               I915_WRITE(reg, temp);
+       }
 
-               /* disable cpu pipe, disable after all planes disabled */
-               temp = I915_READ(pipeconf_reg);
-               if ((temp & PIPEACONF_ENABLE) != 0) {
-                       I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+       /* enable PCH transcoder */
+       reg = TRANSCONF(pipe);
+       temp = I915_READ(reg);
+       /*
+        * make the BPC in transcoder be consistent with
+        * that in pipeconf reg.
+        */
+       temp &= ~PIPE_BPC_MASK;
+       temp |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
+       I915_WRITE(reg, temp | TRANS_ENABLE);
+       if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
+               DRM_ERROR("failed to enable transcoder\n");
 
-                       /* wait for cpu pipe off, pipe state */
-                       if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1))
-                               DRM_ERROR("failed to turn off cpu pipe\n");
-               } else
-                       DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
+       intel_crtc_load_lut(crtc);
+       intel_update_fbc(dev);
+       intel_crtc_update_cursor(crtc, true);
+}
 
-               udelay(100);
+static void ironlake_crtc_disable(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+       u32 reg, temp;
+
+       if (!intel_crtc->active)
+               return;
 
-               /* Disable PF */
-               I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
-               I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+       intel_crtc_wait_for_pending_flips(crtc);
+       drm_vblank_off(dev, pipe);
+       intel_crtc_update_cursor(crtc, false);
 
-               /* disable CPU FDI tx and PCH FDI rx */
-               temp = I915_READ(fdi_tx_reg);
-               I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
-               I915_READ(fdi_tx_reg);
+       /* Disable display plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if (temp & DISPLAY_PLANE_ENABLE) {
+               I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+               intel_flush_display_plane(dev, plane);
+       }
 
-               temp = I915_READ(fdi_rx_reg);
-               /* BPC in FDI rx is consistent with that in pipeconf */
-               temp &= ~(0x07 << 16);
-               temp |= (pipe_bpc << 11);
-               I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
-               I915_READ(fdi_rx_reg);
+       if (dev_priv->cfb_plane == plane &&
+           dev_priv->display.disable_fbc)
+               dev_priv->display.disable_fbc(dev);
 
-               udelay(100);
+       /* disable cpu pipe, disable after all planes disabled */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if (temp & PIPECONF_ENABLE) {
+               I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
+               /* wait for cpu pipe off, pipe state */
+               if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0, 50))
+                       DRM_ERROR("failed to turn off cpu pipe\n");
+       }
+
+       /* Disable PF */
+       I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
+       I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+
+       /* disable CPU FDI tx and PCH FDI rx */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
+       POSTING_READ(reg);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~(0x7 << 16);
+       temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+       I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
+       udelay(100);
+
+       /* still set train pattern 1 */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_PATTERN_1;
+       I915_WRITE(reg, temp);
 
-               /* still set train pattern 1 */
-               temp = I915_READ(fdi_tx_reg);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+       } else {
                temp &= ~FDI_LINK_TRAIN_NONE;
                temp |= FDI_LINK_TRAIN_PATTERN_1;
-               I915_WRITE(fdi_tx_reg, temp);
-               POSTING_READ(fdi_tx_reg);
-
-               temp = I915_READ(fdi_rx_reg);
-               if (HAS_PCH_CPT(dev)) {
-                       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-                       temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
-               } else {
-                       temp &= ~FDI_LINK_TRAIN_NONE;
-                       temp |= FDI_LINK_TRAIN_PATTERN_1;
-               }
-               I915_WRITE(fdi_rx_reg, temp);
-               POSTING_READ(fdi_rx_reg);
+       }
+       /* BPC in FDI rx is consistent with that in PIPECONF */
+       temp &= ~(0x07 << 16);
+       temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+       I915_WRITE(reg, temp);
 
-               udelay(100);
+       POSTING_READ(reg);
+       udelay(100);
 
-               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-                       temp = I915_READ(PCH_LVDS);
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+               temp = I915_READ(PCH_LVDS);
+               if (temp & LVDS_PORT_EN) {
                        I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
-                       I915_READ(PCH_LVDS);
+                       POSTING_READ(PCH_LVDS);
                        udelay(100);
                }
+       }
 
-               /* disable PCH transcoder */
-               temp = I915_READ(transconf_reg);
-               if ((temp & TRANS_ENABLE) != 0) {
-                       I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
+       /* disable PCH transcoder */
+       reg = TRANSCONF(plane);
+       temp = I915_READ(reg);
+       if (temp & TRANS_ENABLE) {
+               I915_WRITE(reg, temp & ~TRANS_ENABLE);
+               /* wait for PCH transcoder off, transcoder state */
+               if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
+                       DRM_ERROR("failed to disable transcoder\n");
+       }
 
-                       /* wait for PCH transcoder off, transcoder state */
-                       if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1))
-                               DRM_ERROR("failed to disable transcoder\n");
-               }
+       if (HAS_PCH_CPT(dev)) {
+               /* disable TRANS_DP_CTL */
+               reg = TRANS_DP_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
+               I915_WRITE(reg, temp);
 
-               temp = I915_READ(transconf_reg);
-               /* BPC in transcoder is consistent with that in pipeconf */
-               temp &= ~PIPE_BPC_MASK;
-               temp |= pipe_bpc;
-               I915_WRITE(transconf_reg, temp);
-               I915_READ(transconf_reg);
-               udelay(100);
+               /* disable DPLL_SEL */
+               temp = I915_READ(PCH_DPLL_SEL);
+               if (pipe == 0)
+                       temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
+               else
+                       temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+               I915_WRITE(PCH_DPLL_SEL, temp);
+       }
 
-               if (HAS_PCH_CPT(dev)) {
-                       /* disable TRANS_DP_CTL */
-                       int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
-                       int reg;
+       /* disable PCH DPLL */
+       reg = PCH_DPLL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
 
-                       reg = I915_READ(trans_dp_ctl);
-                       reg &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
-                       I915_WRITE(trans_dp_ctl, reg);
-                       POSTING_READ(trans_dp_ctl);
+       /* Switch from PCDclk to Rawclk */
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_PCDCLK);
 
-                       /* disable DPLL_SEL */
-                       temp = I915_READ(PCH_DPLL_SEL);
-                       if (trans_dpll_sel == 0)
-                               temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
-                       else
-                               temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
-                       I915_WRITE(PCH_DPLL_SEL, temp);
-                       I915_READ(PCH_DPLL_SEL);
+       /* Disable CPU FDI TX PLL */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
 
-               }
+       POSTING_READ(reg);
+       udelay(100);
 
-               /* disable PCH DPLL */
-               temp = I915_READ(pch_dpll_reg);
-               I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
-               I915_READ(pch_dpll_reg);
-
-               /* Switch from PCDclk to Rawclk */
-               temp = I915_READ(fdi_rx_reg);
-               temp &= ~FDI_SEL_PCDCLK;
-               I915_WRITE(fdi_rx_reg, temp);
-               I915_READ(fdi_rx_reg);
-
-               /* Disable CPU FDI TX PLL */
-               temp = I915_READ(fdi_tx_reg);
-               I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
-               I915_READ(fdi_tx_reg);
-               udelay(100);
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
 
-               temp = I915_READ(fdi_rx_reg);
-               temp &= ~FDI_RX_PLL_ENABLE;
-               I915_WRITE(fdi_rx_reg, temp);
-               I915_READ(fdi_rx_reg);
+       /* Wait for the clocks to turn off. */
+       POSTING_READ(reg);
+       udelay(100);
 
-               /* Wait for the clocks to turn off. */
-               udelay(100);
+       intel_crtc->active = false;
+       intel_update_watermarks(dev);
+       intel_update_fbc(dev);
+       intel_clear_scanline_wait(dev);
+}
+
+static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+
+       /* XXX: When our outputs are all unaware of DPMS modes other than off
+        * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+        */
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+               DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+               ironlake_crtc_enable(crtc);
+               break;
+
+       case DRM_MODE_DPMS_OFF:
+               DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+               ironlake_crtc_disable(crtc);
                break;
        }
 }
 
 static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
 {
-       struct intel_overlay *overlay;
-       int ret;
+       if (!enable && intel_crtc->overlay) {
+               struct drm_device *dev = intel_crtc->base.dev;
+
+               mutex_lock(&dev->struct_mutex);
+               (void) intel_overlay_switch_off(intel_crtc->overlay, false);
+               mutex_unlock(&dev->struct_mutex);
+       }
+
+       /* Let userspace switch the overlay on again. In most cases userspace
+        * has to recompute where to put it anyway.
+        */
+}
+
+static void i9xx_crtc_enable(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+       u32 reg, temp;
+
+       if (intel_crtc->active)
+               return;
+
+       intel_crtc->active = true;
+       intel_update_watermarks(dev);
+
+       /* Enable the DPLL */
+       reg = DPLL(pipe);
+       temp = I915_READ(reg);
+       if ((temp & DPLL_VCO_ENABLE) == 0) {
+               I915_WRITE(reg, temp);
+
+               /* Wait for the clocks to stabilize. */
+               POSTING_READ(reg);
+               udelay(150);
+
+               I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+
+               /* Wait for the clocks to stabilize. */
+               POSTING_READ(reg);
+               udelay(150);
+
+               I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+
+               /* Wait for the clocks to stabilize. */
+               POSTING_READ(reg);
+               udelay(150);
+       }
+
+       /* Enable the pipe */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if ((temp & PIPECONF_ENABLE) == 0)
+               I915_WRITE(reg, temp | PIPECONF_ENABLE);
+
+       /* Enable the plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+               I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+               intel_flush_display_plane(dev, plane);
+       }
+
+       intel_crtc_load_lut(crtc);
+       intel_update_fbc(dev);
+
+       /* Give the overlay scaler a chance to enable if it's on this pipe */
+       intel_crtc_dpms_overlay(intel_crtc, true);
+       intel_crtc_update_cursor(crtc, true);
+}
+
+static void i9xx_crtc_disable(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+       u32 reg, temp;
+
+       if (!intel_crtc->active)
+               return;
+
+       /* Give the overlay scaler a chance to disable if it's on this pipe */
+       intel_crtc_wait_for_pending_flips(crtc);
+       drm_vblank_off(dev, pipe);
+       intel_crtc_dpms_overlay(intel_crtc, false);
+       intel_crtc_update_cursor(crtc, false);
+
+       if (dev_priv->cfb_plane == plane &&
+           dev_priv->display.disable_fbc)
+               dev_priv->display.disable_fbc(dev);
+
+       /* Disable display plane */
+       reg = DSPCNTR(plane);
+       temp = I915_READ(reg);
+       if (temp & DISPLAY_PLANE_ENABLE) {
+               I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+               /* Flush the plane changes */
+               intel_flush_display_plane(dev, plane);
+
+               /* Wait for vblank for the disable to take effect */
+               if (IS_GEN2(dev))
+                       intel_wait_for_vblank(dev, pipe);
+       }
+
+       /* Don't disable pipe A or pipe A PLLs if needed */
+       if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+               goto done;
 
-       if (!enable && intel_crtc->overlay) {
-               overlay = intel_crtc->overlay;
-               mutex_lock(&overlay->dev->struct_mutex);
-               for (;;) {
-                       ret = intel_overlay_switch_off(overlay);
-                       if (ret == 0)
-                               break;
+       /* Next, disable display pipes */
+       reg = PIPECONF(pipe);
+       temp = I915_READ(reg);
+       if (temp & PIPECONF_ENABLE) {
+               I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
 
-                       ret = intel_overlay_recover_from_interrupt(overlay, 0);
-                       if (ret != 0) {
-                               /* overlay doesn't react anymore. Usually
-                                * results in a black screen and an unkillable
-                                * X server. */
-                               BUG();
-                               overlay->hw_wedged = HW_WEDGED;
-                               break;
-                       }
-               }
-               mutex_unlock(&overlay->dev->struct_mutex);
+               /* Wait for the pipe to turn off */
+               POSTING_READ(reg);
+               intel_wait_for_pipe_off(dev, pipe);
        }
-       /* Let userspace switch the overlay on again. In most cases userspace
-        * has to recompute where to put it anyway. */
 
-       return;
+       reg = DPLL(pipe);
+       temp = I915_READ(reg);
+       if (temp & DPLL_VCO_ENABLE) {
+               I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
+
+               /* Wait for the clocks to turn off. */
+               POSTING_READ(reg);
+               udelay(150);
+       }
+
+done:
+       intel_crtc->active = false;
+       intel_update_fbc(dev);
+       intel_update_watermarks(dev);
+       intel_clear_scanline_wait(dev);
 }
 
 static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
-       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-       int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       u32 temp;
-
        /* XXX: When our outputs are all unaware of DPMS modes other than off
         * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
         */
@@ -2272,88 +2463,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
        case DRM_MODE_DPMS_ON:
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
-               /* Enable the DPLL */
-               temp = I915_READ(dpll_reg);
-               if ((temp & DPLL_VCO_ENABLE) == 0) {
-                       I915_WRITE(dpll_reg, temp);
-                       I915_READ(dpll_reg);
-                       /* Wait for the clocks to stabilize. */
-                       udelay(150);
-                       I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
-                       I915_READ(dpll_reg);
-                       /* Wait for the clocks to stabilize. */
-                       udelay(150);
-                       I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
-                       I915_READ(dpll_reg);
-                       /* Wait for the clocks to stabilize. */
-                       udelay(150);
-               }
-
-               /* Enable the pipe */
-               temp = I915_READ(pipeconf_reg);
-               if ((temp & PIPEACONF_ENABLE) == 0)
-                       I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
-
-               /* Enable the plane */
-               temp = I915_READ(dspcntr_reg);
-               if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-                       I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
-                       /* Flush the plane changes */
-                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-               }
-
-               intel_crtc_load_lut(crtc);
-
-               if ((IS_I965G(dev) || plane == 0))
-                       intel_update_fbc(crtc, &crtc->mode);
-
-               /* Give the overlay scaler a chance to enable if it's on this pipe */
-               intel_crtc_dpms_overlay(intel_crtc, true);
-       break;
+               i9xx_crtc_enable(crtc);
+               break;
        case DRM_MODE_DPMS_OFF:
-               /* Give the overlay scaler a chance to disable if it's on this pipe */
-               intel_crtc_dpms_overlay(intel_crtc, false);
-               drm_vblank_off(dev, pipe);
-
-               if (dev_priv->cfb_plane == plane &&
-                   dev_priv->display.disable_fbc)
-                       dev_priv->display.disable_fbc(dev);
-
-               /* Disable display plane */
-               temp = I915_READ(dspcntr_reg);
-               if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-                       I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
-                       /* Flush the plane changes */
-                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-                       I915_READ(dspbase_reg);
-               }
-
-               /* Wait for vblank for the disable to take effect */
-               intel_wait_for_vblank_off(dev, pipe);
-
-               /* Don't disable pipe A or pipe A PLLs if needed */
-               if (pipeconf_reg == PIPEACONF &&
-                   (dev_priv->quirks & QUIRK_PIPEA_FORCE))
-                       goto skip_pipe_off;
-
-               /* Next, disable display pipes */
-               temp = I915_READ(pipeconf_reg);
-               if ((temp & PIPEACONF_ENABLE) != 0) {
-                       I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
-                       I915_READ(pipeconf_reg);
-               }
-
-               /* Wait for vblank for the disable to take effect. */
-               intel_wait_for_vblank_off(dev, pipe);
-
-               temp = I915_READ(dpll_reg);
-               if ((temp & DPLL_VCO_ENABLE) != 0) {
-                       I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
-                       I915_READ(dpll_reg);
-               }
-       skip_pipe_off:
-               /* Wait for the clocks to turn off. */
-               udelay(150);
+               i9xx_crtc_disable(crtc);
                break;
        }
 }
@@ -2374,26 +2487,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
                return;
 
        intel_crtc->dpms_mode = mode;
-       intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON;
-
-       /* When switching on the display, ensure that SR is disabled
-        * with multiple pipes prior to enabling to new pipe.
-        *
-        * When switching off the display, make sure the cursor is
-        * properly hidden prior to disabling the pipe.
-        */
-       if (mode == DRM_MODE_DPMS_ON)
-               intel_update_watermarks(dev);
-       else
-               intel_crtc_update_cursor(crtc);
 
        dev_priv->display.dpms(crtc, mode);
 
-       if (mode == DRM_MODE_DPMS_ON)
-               intel_crtc_update_cursor(crtc);
-       else
-               intel_update_watermarks(dev);
-
        if (!dev->primary->master)
                return;
 
@@ -2418,16 +2514,46 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
        }
 }
 
-static void intel_crtc_prepare (struct drm_crtc *crtc)
+static void intel_crtc_disable(struct drm_crtc *crtc)
 {
        struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       struct drm_device *dev = crtc->dev;
+
        crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+
+       if (crtc->fb) {
+               mutex_lock(&dev->struct_mutex);
+               i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+               mutex_unlock(&dev->struct_mutex);
+       }
 }
 
-static void intel_crtc_commit (struct drm_crtc *crtc)
+/* Prepare for a mode set.
+ *
+ * Note we could be a lot smarter here.  We need to figure out which outputs
+ * will be enabled, which disabled (in short, how the config will changes)
+ * and perform the minimum necessary steps to accomplish that, e.g. updating
+ * watermarks, FBC configuration, making sure PLLs are programmed correctly,
+ * panel fitting is in the proper state, etc.
+ */
+static void i9xx_crtc_prepare(struct drm_crtc *crtc)
 {
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+       i9xx_crtc_disable(crtc);
+}
+
+static void i9xx_crtc_commit(struct drm_crtc *crtc)
+{
+       i9xx_crtc_enable(crtc);
+}
+
+static void ironlake_crtc_prepare(struct drm_crtc *crtc)
+{
+       ironlake_crtc_disable(crtc);
+}
+
+static void ironlake_crtc_commit(struct drm_crtc *crtc)
+{
+       ironlake_crtc_enable(crtc);
 }
 
 void intel_encoder_prepare (struct drm_encoder *encoder)
@@ -2446,13 +2572,7 @@ void intel_encoder_commit (struct drm_encoder *encoder)
 
 void intel_encoder_destroy(struct drm_encoder *encoder)
 {
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
-       if (intel_encoder->ddc_bus)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
-
-       if (intel_encoder->i2c_bus)
-               intel_i2c_destroy(intel_encoder->i2c_bus);
+       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 
        drm_encoder_cleanup(encoder);
        kfree(intel_encoder);
@@ -2543,33 +2663,6 @@ static int i830_get_display_clock_speed(struct drm_device *dev)
        return 133000;
 }
 
-/**
- * Return the pipe currently connected to the panel fitter,
- * or -1 if the panel fitter is not present or not in use
- */
-int intel_panel_fitter_pipe (struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32  pfit_control;
-
-       /* i830 doesn't have a panel fitter */
-       if (IS_I830(dev))
-               return -1;
-
-       pfit_control = I915_READ(PFIT_CONTROL);
-
-       /* See if the panel fitter is in use */
-       if ((pfit_control & PFIT_ENABLE) == 0)
-               return -1;
-
-       /* 965 can place panel fitter on either pipe */
-       if (IS_I965G(dev))
-               return (pfit_control >> 29) & 0x3;
-
-       /* older chips can only use pipe 1 */
-       return 1;
-}
-
 struct fdi_m_n {
        u32        tu;
        u32        gmch_m;
@@ -2888,7 +2981,7 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
                size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A", size);
+                     plane ? "B" : "A", size);
 
        return size;
 }
@@ -2905,7 +2998,7 @@ static int i85x_get_fifo_size(struct drm_device *dev, int plane)
        size >>= 1; /* Convert to cachelines */
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A", size);
+                     plane ? "B" : "A", size);
 
        return size;
 }
@@ -2920,8 +3013,8 @@ static int i845_get_fifo_size(struct drm_device *dev, int plane)
        size >>= 2; /* Convert to cachelines */
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A",
-                 size);
+                     plane ? "B" : "A",
+                     size);
 
        return size;
 }
@@ -2936,14 +3029,14 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane)
        size >>= 1; /* Convert to cachelines */
 
        DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                       plane ? "B" : "A", size);
+                     plane ? "B" : "A", size);
 
        return size;
 }
 
 static void pineview_update_wm(struct drm_device *dev,  int planea_clock,
-                         int planeb_clock, int sr_hdisplay, int unused,
-                         int pixel_size)
+                              int planeb_clock, int sr_hdisplay, int unused,
+                              int pixel_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        const struct cxsr_latency *latency;
@@ -3055,13 +3148,13 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
 
                /* Use ns/us then divide to preserve precision */
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                             pixel_size * sr_hdisplay;
+                       pixel_size * sr_hdisplay;
                sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
 
                entries_required = (((sr_latency_ns / line_time_us) +
                                     1000) / 1000) * pixel_size * 64;
                entries_required = DIV_ROUND_UP(entries_required,
-                                          g4x_cursor_wm_info.cacheline_size);
+                                               g4x_cursor_wm_info.cacheline_size);
                cursor_sr = entries_required + g4x_cursor_wm_info.guard_size;
 
                if (cursor_sr > g4x_cursor_wm_info.max_wm)
@@ -3073,7 +3166,7 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
        } else {
                /* Turn off self refresh if both pipes are enabled */
                I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
-                                       & ~FW_BLC_SELF_EN);
+                          & ~FW_BLC_SELF_EN);
        }
 
        DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
@@ -3111,7 +3204,7 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
 
                /* Use ns/us then divide to preserve precision */
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                             pixel_size * sr_hdisplay;
+                       pixel_size * sr_hdisplay;
                sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE);
                DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
                srwm = I965_FIFO_SIZE - sr_entries;
@@ -3120,11 +3213,11 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
                srwm &= 0x1ff;
 
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                            pixel_size * 64;
+                       pixel_size * 64;
                sr_entries = DIV_ROUND_UP(sr_entries,
                                          i965_cursor_wm_info.cacheline_size);
                cursor_sr = i965_cursor_wm_info.fifo_size -
-                           (sr_entries + i965_cursor_wm_info.guard_size);
+                       (sr_entries + i965_cursor_wm_info.guard_size);
 
                if (cursor_sr > i965_cursor_wm_info.max_wm)
                        cursor_sr = i965_cursor_wm_info.max_wm;
@@ -3132,11 +3225,11 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
                DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
                              "cursor %d\n", srwm, cursor_sr);
 
-               if (IS_I965GM(dev))
+               if (IS_CRESTLINE(dev))
                        I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
        } else {
                /* Turn off self refresh if both pipes are enabled */
-               if (IS_I965GM(dev))
+               if (IS_CRESTLINE(dev))
                        I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
                                   & ~FW_BLC_SELF_EN);
        }
@@ -3166,9 +3259,9 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
        int sr_clock, sr_entries = 0;
 
        /* Create copies of the base settings for each pipe */
-       if (IS_I965GM(dev) || IS_I945GM(dev))
+       if (IS_CRESTLINE(dev) || IS_I945GM(dev))
                planea_params = planeb_params = i945_wm_info;
-       else if (IS_I9XX(dev))
+       else if (!IS_GEN2(dev))
                planea_params = planeb_params = i915_wm_info;
        else
                planea_params = planeb_params = i855_wm_info;
@@ -3203,7 +3296,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
 
                /* Use ns/us then divide to preserve precision */
                sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                             pixel_size * sr_hdisplay;
+                       pixel_size * sr_hdisplay;
                sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
                DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries);
                srwm = total_size - sr_entries;
@@ -3228,7 +3321,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
        }
 
        DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
-                 planea_wm, planeb_wm, cwm, srwm);
+                     planea_wm, planeb_wm, cwm, srwm);
 
        fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
        fwater_hi = (cwm & 0x1f);
@@ -3262,146 +3355,130 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
 #define ILK_LP0_PLANE_LATENCY          700
 #define ILK_LP0_CURSOR_LATENCY         1300
 
-static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
-                      int planeb_clock, int sr_hdisplay, int sr_htotal,
-                      int pixel_size)
+static bool ironlake_compute_wm0(struct drm_device *dev,
+                                int pipe,
+                                int *plane_wm,
+                                int *cursor_wm)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
-       int sr_wm, cursor_wm;
-       unsigned long line_time_us;
-       int sr_clock, entries_required;
-       u32 reg_value;
-       int line_count;
-       int planea_htotal = 0, planeb_htotal = 0;
        struct drm_crtc *crtc;
+       int htotal, hdisplay, clock, pixel_size = 0;
+       int line_time_us, line_count, entries;
 
-       /* Need htotal for all active display plane */
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
-                       if (intel_crtc->plane == 0)
-                               planea_htotal = crtc->mode.htotal;
-                       else
-                               planeb_htotal = crtc->mode.htotal;
-               }
-       }
-
-       /* Calculate and update the watermark for plane A */
-       if (planea_clock) {
-               entries_required = ((planea_clock / 1000) * pixel_size *
-                                    ILK_LP0_PLANE_LATENCY) / 1000;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_display_wm_info.cacheline_size);
-               planea_wm = entries_required +
-                           ironlake_display_wm_info.guard_size;
-
-               if (planea_wm > (int)ironlake_display_wm_info.max_wm)
-                       planea_wm = ironlake_display_wm_info.max_wm;
-
-               /* Use the large buffer method to calculate cursor watermark */
-               line_time_us = (planea_htotal * 1000) / planea_clock;
-
-               /* Use ns/us then divide to preserve precision */
-               line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
-
-               /* calculate the cursor watermark for cursor A */
-               entries_required = line_count * 64 * pixel_size;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_cursor_wm_info.cacheline_size);
-               cursora_wm = entries_required + ironlake_cursor_wm_info.guard_size;
-               if (cursora_wm > ironlake_cursor_wm_info.max_wm)
-                       cursora_wm = ironlake_cursor_wm_info.max_wm;
-
-               reg_value = I915_READ(WM0_PIPEA_ILK);
-               reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) |
-                            (cursora_wm & WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEA_ILK, reg_value);
-               DRM_DEBUG_KMS("FIFO watermarks For pipe A - plane %d, "
-                               "cursor: %d\n", planea_wm, cursora_wm);
-       }
-       /* Calculate and update the watermark for plane B */
-       if (planeb_clock) {
-               entries_required = ((planeb_clock / 1000) * pixel_size *
-                                    ILK_LP0_PLANE_LATENCY) / 1000;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_display_wm_info.cacheline_size);
-               planeb_wm = entries_required +
-                           ironlake_display_wm_info.guard_size;
-
-               if (planeb_wm > (int)ironlake_display_wm_info.max_wm)
-                       planeb_wm = ironlake_display_wm_info.max_wm;
+       crtc = intel_get_crtc_for_pipe(dev, pipe);
+       if (crtc->fb == NULL || !crtc->enabled)
+               return false;
 
-               /* Use the large buffer method to calculate cursor watermark */
-               line_time_us = (planeb_htotal * 1000) / planeb_clock;
+       htotal = crtc->mode.htotal;
+       hdisplay = crtc->mode.hdisplay;
+       clock = crtc->mode.clock;
+       pixel_size = crtc->fb->bits_per_pixel / 8;
+
+       /* Use the small buffer method to calculate plane watermark */
+       entries = ((clock * pixel_size / 1000) * ILK_LP0_PLANE_LATENCY) / 1000;
+       entries = DIV_ROUND_UP(entries,
+                              ironlake_display_wm_info.cacheline_size);
+       *plane_wm = entries + ironlake_display_wm_info.guard_size;
+       if (*plane_wm > (int)ironlake_display_wm_info.max_wm)
+               *plane_wm = ironlake_display_wm_info.max_wm;
+
+       /* Use the large buffer method to calculate cursor watermark */
+       line_time_us = ((htotal * 1000) / clock);
+       line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+       entries = line_count * 64 * pixel_size;
+       entries = DIV_ROUND_UP(entries,
+                              ironlake_cursor_wm_info.cacheline_size);
+       *cursor_wm = entries + ironlake_cursor_wm_info.guard_size;
+       if (*cursor_wm > ironlake_cursor_wm_info.max_wm)
+               *cursor_wm = ironlake_cursor_wm_info.max_wm;
 
-               /* Use ns/us then divide to preserve precision */
-               line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+       return true;
+}
 
-               /* calculate the cursor watermark for cursor B */
-               entries_required = line_count * 64 * pixel_size;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_cursor_wm_info.cacheline_size);
-               cursorb_wm = entries_required + ironlake_cursor_wm_info.guard_size;
-               if (cursorb_wm > ironlake_cursor_wm_info.max_wm)
-                       cursorb_wm = ironlake_cursor_wm_info.max_wm;
+static void ironlake_update_wm(struct drm_device *dev,
+                              int planea_clock, int planeb_clock,
+                              int sr_hdisplay, int sr_htotal,
+                              int pixel_size)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int plane_wm, cursor_wm, enabled;
+       int tmp;
+
+       enabled = 0;
+       if (ironlake_compute_wm0(dev, 0, &plane_wm, &cursor_wm)) {
+               I915_WRITE(WM0_PIPEA_ILK,
+                          (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
+                             " plane %d, " "cursor: %d\n",
+                             plane_wm, cursor_wm);
+               enabled++;
+       }
 
-               reg_value = I915_READ(WM0_PIPEB_ILK);
-               reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) |
-                            (cursorb_wm & WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEB_ILK, reg_value);
-               DRM_DEBUG_KMS("FIFO watermarks For pipe B - plane %d, "
-                               "cursor: %d\n", planeb_wm, cursorb_wm);
+       if (ironlake_compute_wm0(dev, 1, &plane_wm, &cursor_wm)) {
+               I915_WRITE(WM0_PIPEB_ILK,
+                          (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
+                             " plane %d, cursor: %d\n",
+                             plane_wm, cursor_wm);
+               enabled++;
        }
 
        /*
         * Calculate and update the self-refresh watermark only when one
         * display plane is used.
         */
-       if (!planea_clock || !planeb_clock) {
-
+       tmp = 0;
+       if (enabled == 1 && /* XXX disabled due to buggy implmentation? */ 0) {
+               unsigned long line_time_us;
+               int small, large, plane_fbc;
+               int sr_clock, entries;
+               int line_count, line_size;
                /* Read the self-refresh latency. The unit is 0.5us */
                int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
 
                sr_clock = planea_clock ? planea_clock : planeb_clock;
-               line_time_us = ((sr_htotal * 1000) / sr_clock);
+               line_time_us = (sr_htotal * 1000) / sr_clock;
 
                /* Use ns/us then divide to preserve precision */
                line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
-                              / 1000;
+                       / 1000;
+               line_size = sr_hdisplay * pixel_size;
 
-               /* calculate the self-refresh watermark for display plane */
-               entries_required = line_count * sr_hdisplay * pixel_size;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_display_srwm_info.cacheline_size);
-               sr_wm = entries_required +
-                       ironlake_display_srwm_info.guard_size;
+               /* Use the minimum of the small and large buffer method for primary */
+               small = ((sr_clock * pixel_size / 1000) * (ilk_sr_latency * 500)) / 1000;
+               large = line_count * line_size;
 
-               /* calculate the self-refresh watermark for display cursor */
-               entries_required = line_count * pixel_size * 64;
-               entries_required = DIV_ROUND_UP(entries_required,
-                                               ironlake_cursor_srwm_info.cacheline_size);
-               cursor_wm = entries_required +
-                           ironlake_cursor_srwm_info.guard_size;
+               entries = DIV_ROUND_UP(min(small, large),
+                                      ironlake_display_srwm_info.cacheline_size);
 
-               /* configure watermark and enable self-refresh */
-               reg_value = I915_READ(WM1_LP_ILK);
-               reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK |
-                              WM1_LP_CURSOR_MASK);
-               reg_value |= (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
-                            (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm;
+               plane_fbc = entries * 64;
+               plane_fbc = DIV_ROUND_UP(plane_fbc, line_size);
 
-               I915_WRITE(WM1_LP_ILK, reg_value);
-               DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
-                               "cursor %d\n", sr_wm, cursor_wm);
+               plane_wm = entries + ironlake_display_srwm_info.guard_size;
+               if (plane_wm > (int)ironlake_display_srwm_info.max_wm)
+                       plane_wm = ironlake_display_srwm_info.max_wm;
 
-       } else {
-               /* Turn off self refresh if both pipes are enabled */
-               I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
-       }
+               /* calculate the self-refresh watermark for display cursor */
+               entries = line_count * pixel_size * 64;
+               entries = DIV_ROUND_UP(entries,
+                                      ironlake_cursor_srwm_info.cacheline_size);
+
+               cursor_wm = entries + ironlake_cursor_srwm_info.guard_size;
+               if (cursor_wm > (int)ironlake_cursor_srwm_info.max_wm)
+                       cursor_wm = ironlake_cursor_srwm_info.max_wm;
+
+               /* configure watermark and enable self-refresh */
+               tmp = (WM1_LP_SR_EN |
+                      (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
+                      (plane_fbc << WM1_LP_FBC_SHIFT) |
+                      (plane_wm << WM1_LP_SR_SHIFT) |
+                      cursor_wm);
+               DRM_DEBUG_KMS("self-refresh watermark: display plane %d, fbc lines %d,"
+                             " cursor %d\n", plane_wm, plane_fbc, cursor_wm);
+       }
+       I915_WRITE(WM1_LP_ILK, tmp);
+       /* XXX setup WM2 and WM3 */
 }
+
 /**
  * intel_update_watermarks - update FIFO watermark values based on current modes
  *
@@ -3433,7 +3510,7 @@ static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
  *
  * We don't use the sprite, so we can ignore that.  And on Crestline we have
  * to set the non-SR watermarks to 8.
 */
+ */
 static void intel_update_watermarks(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3449,15 +3526,15 @@ static void intel_update_watermarks(struct drm_device *dev)
        /* Get the clock config from both planes */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
+               if (intel_crtc->active) {
                        enabled++;
                        if (intel_crtc->plane == 0) {
                                DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n",
-                                         intel_crtc->pipe, crtc->mode.clock);
+                                             intel_crtc->pipe, crtc->mode.clock);
                                planea_clock = crtc->mode.clock;
                        } else {
                                DRM_DEBUG_KMS("plane B (pipe %d) clock: %d\n",
-                                         intel_crtc->pipe, crtc->mode.clock);
+                                             intel_crtc->pipe, crtc->mode.clock);
                                planeb_clock = crtc->mode.clock;
                        }
                        sr_hdisplay = crtc->mode.hdisplay;
@@ -3488,62 +3565,35 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       int fp_reg = (pipe == 0) ? FPA0 : FPB0;
-       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
-       int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
-       int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-       int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-       int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-       int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-       int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-       int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-       int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
-       int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
-       int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+       u32 fp_reg, dpll_reg;
        int refclk, num_connectors = 0;
        intel_clock_t clock, reduced_clock;
-       u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf;
+       u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
        bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
        bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
        struct intel_encoder *has_edp_encoder = NULL;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_encoder *encoder;
+       struct intel_encoder *encoder;
        const intel_limit_t *limit;
        int ret;
        struct fdi_m_n m_n = {0};
-       int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1;
-       int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1;
-       int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1;
-       int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1;
-       int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
-       int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
-       int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-       int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-       int trans_dpll_sel = (pipe == 0) ? 0 : 1;
-       int lvds_reg = LVDS;
-       u32 temp;
-       int sdvo_pixel_multiply;
+       u32 reg, temp;
        int target_clock;
 
        drm_vblank_pre_modeset(dev, pipe);
 
-       list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-               struct intel_encoder *intel_encoder;
-
-               if (encoder->crtc != crtc)
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
                        continue;
 
-               intel_encoder = enc_to_intel_encoder(encoder);
-               switch (intel_encoder->type) {
+               switch (encoder->type) {
                case INTEL_OUTPUT_LVDS:
                        is_lvds = true;
                        break;
                case INTEL_OUTPUT_SDVO:
                case INTEL_OUTPUT_HDMI:
                        is_sdvo = true;
-                       if (intel_encoder->needs_tv_clock)
+                       if (encoder->needs_tv_clock)
                                is_tv = true;
                        break;
                case INTEL_OUTPUT_DVO:
@@ -3559,7 +3609,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        is_dp = true;
                        break;
                case INTEL_OUTPUT_EDP:
-                       has_edp_encoder = intel_encoder;
+                       has_edp_encoder = encoder;
                        break;
                }
 
@@ -3569,15 +3619,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
                refclk = dev_priv->lvds_ssc_freq * 1000;
                DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
-                                       refclk / 1000);
-       } else if (IS_I9XX(dev)) {
+                             refclk / 1000);
+       } else if (!IS_GEN2(dev)) {
                refclk = 96000;
                if (HAS_PCH_SPLIT(dev))
                        refclk = 120000; /* 120Mhz refclk */
        } else {
                refclk = 48000;
        }
-       
 
        /*
         * Returns a set of divisors for the desired target clock with the given
@@ -3593,13 +3642,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        }
 
        /* Ensure that the cursor is valid for the new mode before changing... */
-       intel_crtc_update_cursor(crtc);
+       intel_crtc_update_cursor(crtc, true);
 
        if (is_lvds && dev_priv->lvds_downclock_avail) {
                has_reduced_clock = limit->find_pll(limit, crtc,
-                                                           dev_priv->lvds_downclock,
-                                                           refclk,
-                                                           &reduced_clock);
+                                                   dev_priv->lvds_downclock,
+                                                   refclk,
+                                                   &reduced_clock);
                if (has_reduced_clock && (clock.p != reduced_clock.p)) {
                        /*
                         * If the different P is found, it means that we can't
@@ -3608,7 +3657,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                         * feature.
                         */
                        DRM_DEBUG_KMS("Different P is found for "
-                                               "LVDS clock/downclock\n");
+                                     "LVDS clock/downclock\n");
                        has_reduced_clock = 0;
                }
        }
@@ -3616,14 +3665,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
           this mirrors vbios setting. */
        if (is_sdvo && is_tv) {
                if (adjusted_mode->clock >= 100000
-                               && adjusted_mode->clock < 140500) {
+                   && adjusted_mode->clock < 140500) {
                        clock.p1 = 2;
                        clock.p2 = 10;
                        clock.n = 3;
                        clock.m1 = 16;
                        clock.m2 = 8;
                } else if (adjusted_mode->clock >= 140500
-                               && adjusted_mode->clock <= 200000) {
+                          && adjusted_mode->clock <= 200000) {
                        clock.p1 = 1;
                        clock.p2 = 10;
                        clock.n = 6;
@@ -3648,21 +3697,28 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                target_clock = mode->clock;
                        else
                                target_clock = adjusted_mode->clock;
-                       link_bw = 270000;
+
+                       /* FDI is a binary signal running at ~2.7GHz, encoding
+                        * each output octet as 10 bits. The actual frequency
+                        * is stored as a divider into a 100MHz clock, and the
+                        * mode pixel clock is stored in units of 1KHz.
+                        * Hence the bw of each lane in terms of the mode signal
+                        * is:
+                        */
+                       link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
                }
 
                /* determine panel color depth */
-               temp = I915_READ(pipeconf_reg);
+               temp = I915_READ(PIPECONF(pipe));
                temp &= ~PIPE_BPC_MASK;
                if (is_lvds) {
-                       int lvds_reg = I915_READ(PCH_LVDS);
                        /* the BPC will be 6 if it is 18-bit LVDS panel */
-                       if ((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
+                       if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
                                temp |= PIPE_8BPC;
                        else
                                temp |= PIPE_6BPC;
                } else if (has_edp_encoder || (is_dp && intel_pch_has_edp(crtc))) {
-                       switch (dev_priv->edp_bpp/3) {
+                       switch (dev_priv->edp.bpp/3) {
                        case 8:
                                temp |= PIPE_8BPC;
                                break;
@@ -3678,8 +3734,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        }
                } else
                        temp |= PIPE_8BPC;
-               I915_WRITE(pipeconf_reg, temp);
-               I915_READ(pipeconf_reg);
+               I915_WRITE(PIPECONF(pipe), temp);
 
                switch (temp & PIPE_BPC_MASK) {
                case PIPE_8BPC:
@@ -3724,33 +3779,27 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                /* Always enable nonspread source */
                temp &= ~DREF_NONSPREAD_SOURCE_MASK;
                temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
-
                temp &= ~DREF_SSC_SOURCE_MASK;
                temp |= DREF_SSC_SOURCE_ENABLE;
                I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
 
+               POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
 
                if (has_edp_encoder) {
                        if (dev_priv->lvds_use_ssc) {
                                temp |= DREF_SSC1_ENABLE;
                                I915_WRITE(PCH_DREF_CONTROL, temp);
-                               POSTING_READ(PCH_DREF_CONTROL);
 
+                               POSTING_READ(PCH_DREF_CONTROL);
                                udelay(200);
 
                                temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
                                temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-                               I915_WRITE(PCH_DREF_CONTROL, temp);
-                               POSTING_READ(PCH_DREF_CONTROL);
                        } else {
                                temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-                               I915_WRITE(PCH_DREF_CONTROL, temp);
-                               POSTING_READ(PCH_DREF_CONTROL);
                        }
+                       I915_WRITE(PCH_DREF_CONTROL, temp);
                }
        }
 
@@ -3766,21 +3815,24 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                reduced_clock.m2;
        }
 
+       dpll = 0;
        if (!HAS_PCH_SPLIT(dev))
                dpll = DPLL_VGA_MODE_DIS;
 
-       if (IS_I9XX(dev)) {
+       if (!IS_GEN2(dev)) {
                if (is_lvds)
                        dpll |= DPLLB_MODE_LVDS;
                else
                        dpll |= DPLLB_MODE_DAC_SERIAL;
                if (is_sdvo) {
+                       int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+                       if (pixel_multiplier > 1) {
+                               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+                                       dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+                               else if (HAS_PCH_SPLIT(dev))
+                                       dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+                       }
                        dpll |= DPLL_DVO_HIGH_SPEED;
-                       sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
-                       if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-                               dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
-                       else if (HAS_PCH_SPLIT(dev))
-                               dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                }
                if (is_dp)
                        dpll |= DPLL_DVO_HIGH_SPEED;
@@ -3810,7 +3862,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
                        break;
                }
-               if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
                        dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
        } else {
                if (is_lvds) {
@@ -3837,7 +3889,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                dpll |= PLL_REF_INPUT_DREFCLK;
 
        /* setup pipeconf */
-       pipeconf = I915_READ(pipeconf_reg);
+       pipeconf = I915_READ(PIPECONF(pipe));
 
        /* Set up the display plane register */
        dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -3851,7 +3903,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dspcntr |= DISPPLANE_SEL_PIPE_B;
        }
 
-       if (pipe == 0 && !IS_I965G(dev)) {
+       if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
                /* Enable pixel doubling when the dot clock is > 90% of the (display)
                 * core speed.
                 *
@@ -3860,51 +3912,46 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                 */
                if (mode->clock >
                    dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
-                       pipeconf |= PIPEACONF_DOUBLE_WIDE;
+                       pipeconf |= PIPECONF_DOUBLE_WIDE;
                else
-                       pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
+                       pipeconf &= ~PIPECONF_DOUBLE_WIDE;
        }
 
        dspcntr |= DISPLAY_PLANE_ENABLE;
-       pipeconf |= PIPEACONF_ENABLE;
+       pipeconf |= PIPECONF_ENABLE;
        dpll |= DPLL_VCO_ENABLE;
 
-
-       /* Disable the panel fitter if it was on our pipe */
-       if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe)
-               I915_WRITE(PFIT_CONTROL, 0);
-
        DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
        drm_mode_debug_printmodeline(mode);
 
        /* assign to Ironlake registers */
        if (HAS_PCH_SPLIT(dev)) {
-               fp_reg = pch_fp_reg;
-               dpll_reg = pch_dpll_reg;
+               fp_reg = PCH_FP0(pipe);
+               dpll_reg = PCH_DPLL(pipe);
+       } else {
+               fp_reg = FP0(pipe);
+               dpll_reg = DPLL(pipe);
        }
 
        if (!has_edp_encoder) {
                I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
-               I915_READ(dpll_reg);
+
+               POSTING_READ(dpll_reg);
                udelay(150);
        }
 
        /* enable transcoder DPLL */
        if (HAS_PCH_CPT(dev)) {
                temp = I915_READ(PCH_DPLL_SEL);
-               if (trans_dpll_sel == 0)
-                       temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+               if (pipe == 0)
+                       temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
                else
-                       temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+                       temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
                I915_WRITE(PCH_DPLL_SEL, temp);
-               I915_READ(PCH_DPLL_SEL);
-               udelay(150);
-       }
 
-       if (HAS_PCH_SPLIT(dev)) {
-               pipeconf &= ~PIPE_ENABLE_DITHER;
-               pipeconf &= ~PIPE_DITHER_TYPE_MASK;
+               POSTING_READ(PCH_DPLL_SEL);
+               udelay(150);
        }
 
        /* The LVDS pin pair needs to be on before the DPLLs are enabled.
@@ -3912,55 +3959,57 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
         * things on.
         */
        if (is_lvds) {
-               u32 lvds;
-
+               reg = LVDS;
                if (HAS_PCH_SPLIT(dev))
-                       lvds_reg = PCH_LVDS;
+                       reg = PCH_LVDS;
 
-               lvds = I915_READ(lvds_reg);
-               lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+               temp = I915_READ(reg);
+               temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
                if (pipe == 1) {
                        if (HAS_PCH_CPT(dev))
-                               lvds |= PORT_TRANS_B_SEL_CPT;
+                               temp |= PORT_TRANS_B_SEL_CPT;
                        else
-                               lvds |= LVDS_PIPEB_SELECT;
+                               temp |= LVDS_PIPEB_SELECT;
                } else {
                        if (HAS_PCH_CPT(dev))
-                               lvds &= ~PORT_TRANS_SEL_MASK;
+                               temp &= ~PORT_TRANS_SEL_MASK;
                        else
-                               lvds &= ~LVDS_PIPEB_SELECT;
+                               temp &= ~LVDS_PIPEB_SELECT;
                }
                /* set the corresponsding LVDS_BORDER bit */
-               lvds |= dev_priv->lvds_border_bits;
+               temp |= dev_priv->lvds_border_bits;
                /* Set the B0-B3 data pairs corresponding to whether we're going to
                 * set the DPLLs for dual-channel mode or not.
                 */
                if (clock.p2 == 7)
-                       lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+                       temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
                else
-                       lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+                       temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
 
                /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
                 * appropriately here, but we need to look more thoroughly into how
                 * panels behave in the two modes.
                 */
-               /* set the dithering flag */
-               if (IS_I965G(dev)) {
-                       if (dev_priv->lvds_dither) {
-                               if (HAS_PCH_SPLIT(dev)) {
-                                       pipeconf |= PIPE_ENABLE_DITHER;
-                                       pipeconf |= PIPE_DITHER_TYPE_ST01;
-                               } else
-                                       lvds |= LVDS_ENABLE_DITHER;
-                       } else {
-                               if (!HAS_PCH_SPLIT(dev)) {
-                                       lvds &= ~LVDS_ENABLE_DITHER;
-                               }
-                       }
+               /* set the dithering flag on non-PCH LVDS as needed */
+               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+                       if (dev_priv->lvds_dither)
+                               temp |= LVDS_ENABLE_DITHER;
+                       else
+                               temp &= ~LVDS_ENABLE_DITHER;
+               }
+               I915_WRITE(reg, temp);
+       }
+
+       /* set the dithering flag and clear for anything other than a panel. */
+       if (HAS_PCH_SPLIT(dev)) {
+               pipeconf &= ~PIPECONF_DITHER_EN;
+               pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+               if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
+                       pipeconf |= PIPECONF_DITHER_EN;
+                       pipeconf |= PIPECONF_DITHER_TYPE_ST1;
                }
-               I915_WRITE(lvds_reg, lvds);
-               I915_READ(lvds_reg);
        }
+
        if (is_dp)
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
        else if (HAS_PCH_SPLIT(dev)) {
@@ -3981,26 +4030,32 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        if (!has_edp_encoder) {
                I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll);
-               I915_READ(dpll_reg);
+
                /* Wait for the clocks to stabilize. */
+               POSTING_READ(dpll_reg);
                udelay(150);
 
-               if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+                       temp = 0;
                        if (is_sdvo) {
-                               sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
-                               I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
-                                       ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
-                       } else
-                               I915_WRITE(dpll_md_reg, 0);
+                               temp = intel_mode_get_pixel_multiplier(adjusted_mode);
+                               if (temp > 1)
+                                       temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+                               else
+                                       temp = 0;
+                       }
+                       I915_WRITE(DPLL_MD(pipe), temp);
                } else {
                        /* write it again -- the BIOS does, after all */
                        I915_WRITE(dpll_reg, dpll);
                }
-               I915_READ(dpll_reg);
+
                /* Wait for the clocks to stabilize. */
+               POSTING_READ(dpll_reg);
                udelay(150);
        }
 
+       intel_crtc->lowfreq_avail = false;
        if (is_lvds && has_reduced_clock && i915_powersave) {
                I915_WRITE(fp_reg + 4, fp2);
                intel_crtc->lowfreq_avail = true;
@@ -4010,7 +4065,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        } else {
                I915_WRITE(fp_reg + 4, fp);
-               intel_crtc->lowfreq_avail = false;
                if (HAS_PIPE_CXSR(dev)) {
                        DRM_DEBUG_KMS("disabling CxSR downclocking\n");
                        pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
@@ -4029,58 +4083,72 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        } else
                pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
 
-       I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+       I915_WRITE(HTOTAL(pipe),
+                  (adjusted_mode->crtc_hdisplay - 1) |
                   ((adjusted_mode->crtc_htotal - 1) << 16));
-       I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+       I915_WRITE(HBLANK(pipe),
+                  (adjusted_mode->crtc_hblank_start - 1) |
                   ((adjusted_mode->crtc_hblank_end - 1) << 16));
-       I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+       I915_WRITE(HSYNC(pipe),
+                  (adjusted_mode->crtc_hsync_start - 1) |
                   ((adjusted_mode->crtc_hsync_end - 1) << 16));
-       I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+
+       I915_WRITE(VTOTAL(pipe),
+                  (adjusted_mode->crtc_vdisplay - 1) |
                   ((adjusted_mode->crtc_vtotal - 1) << 16));
-       I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+       I915_WRITE(VBLANK(pipe),
+                  (adjusted_mode->crtc_vblank_start - 1) |
                   ((adjusted_mode->crtc_vblank_end - 1) << 16));
-       I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+       I915_WRITE(VSYNC(pipe),
+                  (adjusted_mode->crtc_vsync_start - 1) |
                   ((adjusted_mode->crtc_vsync_end - 1) << 16));
-       /* pipesrc and dspsize control the size that is scaled from, which should
-        * always be the user's requested size.
+
+       /* pipesrc and dspsize control the size that is scaled from,
+        * which should always be the user's requested size.
         */
        if (!HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
-                               (mode->hdisplay - 1));
-               I915_WRITE(dsppos_reg, 0);
+               I915_WRITE(DSPSIZE(plane),
+                          ((mode->vdisplay - 1) << 16) |
+                          (mode->hdisplay - 1));
+               I915_WRITE(DSPPOS(plane), 0);
        }
-       I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+       I915_WRITE(PIPESRC(pipe),
+                  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 
        if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
-               I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
-               I915_WRITE(link_m1_reg, m_n.link_m);
-               I915_WRITE(link_n1_reg, m_n.link_n);
+               I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
+               I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
+               I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
+               I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
 
                if (has_edp_encoder) {
                        ironlake_set_pll_edp(crtc, adjusted_mode->clock);
                } else {
                        /* enable FDI RX PLL too */
-                       temp = I915_READ(fdi_rx_reg);
-                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
-                       I915_READ(fdi_rx_reg);
+                       reg = FDI_RX_CTL(pipe);
+                       temp = I915_READ(reg);
+                       I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
+
+                       POSTING_READ(reg);
                        udelay(200);
 
                        /* enable FDI TX PLL too */
-                       temp = I915_READ(fdi_tx_reg);
-                       I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
-                       I915_READ(fdi_tx_reg);
+                       reg = FDI_TX_CTL(pipe);
+                       temp = I915_READ(reg);
+                       I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
 
                        /* enable FDI RX PCDCLK */
-                       temp = I915_READ(fdi_rx_reg);
-                       I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
-                       I915_READ(fdi_rx_reg);
+                       reg = FDI_RX_CTL(pipe);
+                       temp = I915_READ(reg);
+                       I915_WRITE(reg, temp | FDI_PCDCLK);
+
+                       POSTING_READ(reg);
                        udelay(200);
                }
        }
 
-       I915_WRITE(pipeconf_reg, pipeconf);
-       I915_READ(pipeconf_reg);
+       I915_WRITE(PIPECONF(pipe), pipeconf);
+       POSTING_READ(PIPECONF(pipe));
 
        intel_wait_for_vblank(dev, pipe);
 
@@ -4090,9 +4158,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
        }
 
-       I915_WRITE(dspcntr_reg, dspcntr);
+       I915_WRITE(DSPCNTR(plane), dspcntr);
 
-       /* Flush the plane changes */
        ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
        intel_update_watermarks(dev);
@@ -4185,7 +4252,8 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
 }
 
 /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
-static void intel_crtc_update_cursor(struct drm_crtc *crtc)
+static void intel_crtc_update_cursor(struct drm_crtc *crtc,
+                                    bool on)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4198,7 +4266,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc)
 
        pos = 0;
 
-       if (intel_crtc->cursor_on && crtc->fb) {
+       if (on && crtc->enabled && crtc->fb) {
                base = intel_crtc->cursor_addr;
                if (x > (int) crtc->fb->width)
                        base = 0;
@@ -4310,7 +4378,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                addr = obj_priv->phys_obj->handle->busaddr;
        }
 
-       if (!IS_I9XX(dev))
+       if (IS_GEN2(dev))
                I915_WRITE(CURSIZE, (height << 12) | width);
 
  finish:
@@ -4330,7 +4398,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        intel_crtc->cursor_width = width;
        intel_crtc->cursor_height = height;
 
-       intel_crtc_update_cursor(crtc);
+       intel_crtc_update_cursor(crtc, true);
 
        return 0;
 fail_unpin:
@@ -4349,7 +4417,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        intel_crtc->cursor_x = x;
        intel_crtc->cursor_y = y;
 
-       intel_crtc_update_cursor(crtc);
+       intel_crtc_update_cursor(crtc, true);
 
        return 0;
 }
@@ -4418,7 +4486,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
        struct intel_crtc *intel_crtc;
        struct drm_crtc *possible_crtc;
        struct drm_crtc *supported_crtc =NULL;
-       struct drm_encoder *encoder = &intel_encoder->enc;
+       struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = NULL;
        struct drm_device *dev = encoder->dev;
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4499,7 +4567,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
 void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
                                    struct drm_connector *connector, int dpms_mode)
 {
-       struct drm_encoder *encoder = &intel_encoder->enc;
+       struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_device *dev = encoder->dev;
        struct drm_crtc *crtc = encoder->crtc;
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4545,7 +4613,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
                clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
        }
 
-       if (IS_I9XX(dev)) {
+       if (!IS_GEN2(dev)) {
                if (IS_PINEVIEW(dev))
                        clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >>
                                DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW);
@@ -4649,8 +4717,6 @@ static void intel_gpu_idle_timer(unsigned long arg)
        struct drm_device *dev = (struct drm_device *)arg;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       DRM_DEBUG_DRIVER("idle timer fired, downclocking\n");
-
        dev_priv->busy = false;
 
        queue_work(dev_priv->wq, &dev_priv->idle_work);
@@ -4664,14 +4730,12 @@ static void intel_crtc_idle_timer(unsigned long arg)
        struct drm_crtc *crtc = &intel_crtc->base;
        drm_i915_private_t *dev_priv = crtc->dev->dev_private;
 
-       DRM_DEBUG_DRIVER("idle timer fired, downclocking\n");
-
        intel_crtc->busy = false;
 
        queue_work(dev_priv->wq, &dev_priv->idle_work);
 }
 
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
+static void intel_increase_pllclock(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -4706,9 +4770,8 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
        }
 
        /* Schedule downclock */
-       if (schedule)
-               mod_timer(&intel_crtc->idle_timer, jiffies +
-                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+       mod_timer(&intel_crtc->idle_timer, jiffies +
+                 msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
 }
 
 static void intel_decrease_pllclock(struct drm_crtc *crtc)
@@ -4844,7 +4907,7 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
                                        I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
                                }
                                /* Non-busy -> busy, upclock */
-                               intel_increase_pllclock(crtc, true);
+                               intel_increase_pllclock(crtc);
                                intel_crtc->busy = true;
                        } else {
                                /* Busy -> busy, put off timer */
@@ -4858,8 +4921,22 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
 static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct intel_unpin_work *work;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       work = intel_crtc->unpin_work;
+       intel_crtc->unpin_work = NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       if (work) {
+               cancel_work_sync(&work->work);
+               kfree(work);
+       }
 
        drm_crtc_cleanup(crtc);
+
        kfree(intel_crtc);
 }
 
@@ -4919,7 +4996,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
        /* Initial scanout buffer will have a 0 pending flip count */
        if ((atomic_read(&obj_priv->pending_flip) == 0) ||
            atomic_dec_and_test(&obj_priv->pending_flip))
-               DRM_WAKEUP(&dev_priv->pending_flip_queue);
+               wake_up(&dev_priv->pending_flip_queue);
        schedule_work(&work->work);
 
        trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
@@ -5000,7 +5077,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        obj = intel_fb->obj;
 
        mutex_lock(&dev->struct_mutex);
-       ret = intel_pin_and_fence_fb_obj(dev, obj);
+       ret = intel_pin_and_fence_fb_obj(dev, obj, true);
        if (ret)
                goto cleanup_work;
 
@@ -5009,9 +5086,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        drm_gem_object_reference(obj);
 
        crtc->fb = fb;
-       ret = i915_gem_object_flush_write_domain(obj);
-       if (ret)
-               goto cleanup_objs;
 
        ret = drm_vblank_get(dev, intel_crtc->pipe);
        if (ret)
@@ -5024,14 +5098,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        if (IS_GEN3(dev) || IS_GEN2(dev)) {
                u32 flip_mask;
 
+               /* Can't queue multiple flips, so wait for the previous
+                * one to finish before executing the next.
+                */
+               BEGIN_LP_RING(2);
                if (intel_crtc->plane)
                        flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
                else
                        flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-
-               BEGIN_LP_RING(2);
                OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
-               OUT_RING(0);
+               OUT_RING(MI_NOOP);
                ADVANCE_LP_RING();
        }
 
@@ -5112,15 +5188,14 @@ cleanup_work:
        return ret;
 }
 
-static const struct drm_crtc_helper_funcs intel_helper_funcs = {
+static struct drm_crtc_helper_funcs intel_helper_funcs = {
        .dpms = intel_crtc_dpms,
        .mode_fixup = intel_crtc_mode_fixup,
        .mode_set = intel_crtc_mode_set,
        .mode_set_base = intel_pipe_set_base,
        .mode_set_base_atomic = intel_pipe_set_base_atomic,
-       .prepare = intel_crtc_prepare,
-       .commit = intel_crtc_commit,
        .load_lut = intel_crtc_load_lut,
+       .disable = intel_crtc_disable,
 };
 
 static const struct drm_crtc_funcs intel_crtc_funcs = {
@@ -5146,8 +5221,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
 
        drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
-       intel_crtc->pipe = pipe;
-       intel_crtc->plane = pipe;
        for (i = 0; i < 256; i++) {
                intel_crtc->lut_r[i] = i;
                intel_crtc->lut_g[i] = i;
@@ -5157,9 +5230,9 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        /* Swap pipes & planes for FBC on pre-965 */
        intel_crtc->pipe = pipe;
        intel_crtc->plane = pipe;
-       if (IS_MOBILE(dev) && (IS_I9XX(dev) && !IS_I965G(dev))) {
+       if (IS_MOBILE(dev) && IS_GEN3(dev)) {
                DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
-               intel_crtc->plane = ((pipe == 0) ? 1 : 0);
+               intel_crtc->plane = !pipe;
        }
 
        BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
@@ -5169,6 +5242,16 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        intel_crtc->cursor_addr = 0;
        intel_crtc->dpms_mode = -1;
+       intel_crtc->active = true; /* force the pipe off on setup_init_config */
+
+       if (HAS_PCH_SPLIT(dev)) {
+               intel_helper_funcs.prepare = ironlake_crtc_prepare;
+               intel_helper_funcs.commit = ironlake_crtc_commit;
+       } else {
+               intel_helper_funcs.prepare = i9xx_crtc_prepare;
+               intel_helper_funcs.commit = i9xx_crtc_commit;
+       }
+
        drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
        intel_crtc->busy = false;
@@ -5204,38 +5287,25 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
        return 0;
 }
 
-struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
-{
-       struct drm_crtc *crtc = NULL;
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-               if (intel_crtc->pipe == pipe)
-                       break;
-       }
-       return crtc;
-}
-
 static int intel_encoder_clones(struct drm_device *dev, int type_mask)
 {
+       struct intel_encoder *encoder;
        int index_mask = 0;
-       struct drm_encoder *encoder;
        int entry = 0;
 
-        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-               if (type_mask & intel_encoder->clone_mask)
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               if (type_mask & encoder->clone_mask)
                        index_mask |= (1 << entry);
                entry++;
        }
+
        return index_mask;
 }
 
-
 static void intel_setup_outputs(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_encoder *encoder;
+       struct intel_encoder *encoder;
        bool dpd_is_edp = false;
 
        if (IS_MOBILE(dev) && !IS_I830(dev))
@@ -5324,12 +5394,10 @@ static void intel_setup_outputs(struct drm_device *dev)
        if (SUPPORTS_TV(dev))
                intel_tv_init(dev);
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
-               encoder->possible_crtcs = intel_encoder->crtc_mask;
-               encoder->possible_clones = intel_encoder_clones(dev,
-                                               intel_encoder->clone_mask);
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               encoder->base.possible_crtcs = encoder->crtc_mask;
+               encoder->base.possible_clones =
+                       intel_encoder_clones(dev, encoder->clone_mask);
        }
 }
 
@@ -5363,8 +5431,25 @@ int intel_framebuffer_init(struct drm_device *dev,
                           struct drm_mode_fb_cmd *mode_cmd,
                           struct drm_gem_object *obj)
 {
+       struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        int ret;
 
+       if (obj_priv->tiling_mode == I915_TILING_Y)
+               return -EINVAL;
+
+       if (mode_cmd->pitch & 63)
+               return -EINVAL;
+
+       switch (mode_cmd->bpp) {
+       case 8:
+       case 16:
+       case 24:
+       case 32:
+               break;
+       default:
+               return -EINVAL;
+       }
+
        ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
        if (ret) {
                DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -5473,6 +5558,10 @@ void ironlake_enable_drps(struct drm_device *dev)
        u32 rgvmodectl = I915_READ(MEMMODECTL);
        u8 fmax, fmin, fstart, vstart;
 
+       /* Enable temp reporting */
+       I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
+       I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
+
        /* 100ms RC evaluation intervals */
        I915_WRITE(RCUPEI, 100000);
        I915_WRITE(RCDNEI, 100000);
@@ -5515,7 +5604,7 @@ void ironlake_enable_drps(struct drm_device *dev)
        rgvmodectl |= MEMMODE_SWMODE_EN;
        I915_WRITE(MEMMODECTL, rgvmodectl);
 
-       if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
+       if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
                DRM_ERROR("stuck trying to change perf mode\n");
        msleep(1);
 
@@ -5714,20 +5803,20 @@ void intel_init_clock_gating(struct drm_device *dev)
                if (IS_GM45(dev))
                        dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
                I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
-       } else if (IS_I965GM(dev)) {
+       } else if (IS_CRESTLINE(dev)) {
                I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
                I915_WRITE(RENCLK_GATE_D2, 0);
                I915_WRITE(DSPCLK_GATE_D, 0);
                I915_WRITE(RAMCLK_GATE_D, 0);
                I915_WRITE16(DEUC, 0);
-       } else if (IS_I965G(dev)) {
+       } else if (IS_BROADWATER(dev)) {
                I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
                       I965_RCC_CLOCK_GATE_DISABLE |
                       I965_RCPB_CLOCK_GATE_DISABLE |
                       I965_ISC_CLOCK_GATE_DISABLE |
                       I965_FBC_CLOCK_GATE_DISABLE);
                I915_WRITE(RENCLK_GATE_D2, 0);
-       } else if (IS_I9XX(dev)) {
+       } else if (IS_GEN3(dev)) {
                u32 dstate = I915_READ(D_STATE);
 
                dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
@@ -5809,7 +5898,7 @@ static void intel_init_display(struct drm_device *dev)
                        dev_priv->display.fbc_enabled = g4x_fbc_enabled;
                        dev_priv->display.enable_fbc = g4x_enable_fbc;
                        dev_priv->display.disable_fbc = g4x_disable_fbc;
-               } else if (IS_I965GM(dev)) {
+               } else if (IS_CRESTLINE(dev)) {
                        dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
                        dev_priv->display.enable_fbc = i8xx_enable_fbc;
                        dev_priv->display.disable_fbc = i8xx_disable_fbc;
@@ -5869,9 +5958,9 @@ static void intel_init_display(struct drm_device *dev)
                        dev_priv->display.update_wm = pineview_update_wm;
        } else if (IS_G4X(dev))
                dev_priv->display.update_wm = g4x_update_wm;
-       else if (IS_I965G(dev))
+       else if (IS_GEN4(dev))
                dev_priv->display.update_wm = i965_update_wm;
-       else if (IS_I9XX(dev)) {
+       else if (IS_GEN3(dev)) {
                dev_priv->display.update_wm = i9xx_update_wm;
                dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
        } else if (IS_I85X(dev)) {
@@ -5985,24 +6074,24 @@ void intel_modeset_init(struct drm_device *dev)
 
        intel_init_display(dev);
 
-       if (IS_I965G(dev)) {
-               dev->mode_config.max_width = 8192;
-               dev->mode_config.max_height = 8192;
-       } else if (IS_I9XX(dev)) {
+       if (IS_GEN2(dev)) {
+               dev->mode_config.max_width = 2048;
+               dev->mode_config.max_height = 2048;
+       } else if (IS_GEN3(dev)) {
                dev->mode_config.max_width = 4096;
                dev->mode_config.max_height = 4096;
        } else {
-               dev->mode_config.max_width = 2048;
-               dev->mode_config.max_height = 2048;
+               dev->mode_config.max_width = 8192;
+               dev->mode_config.max_height = 8192;
        }
 
        /* set memory base */
-       if (IS_I9XX(dev))
-               dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
-       else
+       if (IS_GEN2(dev))
                dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
+       else
+               dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
 
-       if (IS_MOBILE(dev) || IS_I9XX(dev))
+       if (IS_MOBILE(dev) || !IS_GEN2(dev))
                dev_priv->num_pipe = 2;
        else
                dev_priv->num_pipe = 1;
@@ -6038,10 +6127,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
        struct drm_crtc *crtc;
        struct intel_crtc *intel_crtc;
 
-       mutex_lock(&dev->struct_mutex);
-
        drm_kms_helper_poll_fini(dev);
-       intel_fbdev_fini(dev);
+       mutex_lock(&dev->struct_mutex);
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                /* Skip inactive CRTCs */
@@ -6049,12 +6136,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
                        continue;
 
                intel_crtc = to_intel_crtc(crtc);
-               intel_increase_pllclock(crtc, false);
-               del_timer_sync(&intel_crtc->idle_timer);
+               intel_increase_pllclock(crtc);
        }
 
-       del_timer_sync(&dev_priv->idle_timer);
-
        if (dev_priv->display.disable_fbc)
                dev_priv->display.disable_fbc(dev);
 
@@ -6083,33 +6167,36 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        mutex_unlock(&dev->struct_mutex);
 
+       /* Disable the irq before mode object teardown, for the irq might
+        * enqueue unpin/hotplug work. */
+       drm_irq_uninstall(dev);
+       cancel_work_sync(&dev_priv->hotplug_work);
+
+       /* Shut off idle work before the crtcs get freed. */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               intel_crtc = to_intel_crtc(crtc);
+               del_timer_sync(&intel_crtc->idle_timer);
+       }
+       del_timer_sync(&dev_priv->idle_timer);
+       cancel_work_sync(&dev_priv->idle_work);
+
        drm_mode_config_cleanup(dev);
 }
 
-
 /*
  * Return which encoder is currently attached for connector.
  */
-struct drm_encoder *intel_attached_encoder (struct drm_connector *connector)
+struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
 {
-       struct drm_mode_object *obj;
-       struct drm_encoder *encoder;
-       int i;
-
-       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-               if (connector->encoder_ids[i] == 0)
-                       break;
-
-               obj = drm_mode_object_find(connector->dev,
-                                           connector->encoder_ids[i],
-                                           DRM_MODE_OBJECT_ENCODER);
-               if (!obj)
-                       continue;
+       return &intel_attached_encoder(connector)->base;
+}
 
-               encoder = obj_to_encoder(obj);
-               return encoder;
-       }
-       return NULL;
+void intel_connector_attach_encoder(struct intel_connector *connector,
+                                   struct intel_encoder *encoder)
+{
+       connector->encoder = encoder;
+       drm_mode_connector_attach_encoder(&connector->base,
+                                         &encoder->base);
 }
 
 /*
index 1a51ee07de3e72daf3a3c59ffdb15f70d5c95959..152d94507b79170e651a35374d2238968c7a637d 100644 (file)
@@ -58,14 +58,23 @@ struct intel_dp {
        struct i2c_adapter adapter;
        struct i2c_algo_dp_aux_data algo;
        bool is_pch_edp;
+       uint8_t train_set[4];
+       uint8_t link_status[DP_LINK_STATUS_SIZE];
 };
 
 static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_dp, base);
+       return container_of(encoder, struct intel_dp, base.base);
+}
+
+static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
+{
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_dp, base);
 }
 
-static void intel_dp_link_train(struct intel_dp *intel_dp);
+static void intel_dp_start_link_train(struct intel_dp *intel_dp);
+static void intel_dp_complete_link_train(struct intel_dp *intel_dp);
 static void intel_dp_link_down(struct intel_dp *intel_dp);
 
 void
@@ -130,7 +139,7 @@ intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pi
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-               return (pixel_clock * dev_priv->edp_bpp) / 8;
+               return (pixel_clock * dev_priv->edp.bpp + 7) / 8;
        else
                return pixel_clock * 3;
 }
@@ -145,8 +154,7 @@ static int
 intel_dp_mode_valid(struct drm_connector *connector,
                    struct drm_display_mode *mode)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
@@ -233,7 +241,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                uint8_t *recv, int recv_size)
 {
        uint32_t output_reg = intel_dp->output_reg;
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t ch_ctl = output_reg + 0x10;
        uint32_t ch_data = ch_ctl + 4;
@@ -246,8 +254,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        /* The clock divider is based off the hrawclk,
         * and would like to run at 2MHz. So, take the
         * hrawclk value and divide by 2 and use that
+        *
+        * Note that PCH attached eDP panels should use a 125MHz input
+        * clock divider.
         */
-       if (IS_eDP(intel_dp)) {
+       if (IS_eDP(intel_dp) && !IS_PCH_eDP(intel_dp)) {
                if (IS_GEN6(dev))
                        aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
                else
@@ -642,7 +653,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
                if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) {
                        lane_count = intel_dp->lane_count;
                        if (IS_PCH_eDP(intel_dp))
-                               bpp = dev_priv->edp_bpp;
+                               bpp = dev_priv->edp.bpp;
                        break;
                }
        }
@@ -698,7 +709,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 {
        struct drm_device *dev = encoder->dev;
        struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_crtc *crtc = intel_dp->base.enc.crtc;
+       struct drm_crtc *crtc = intel_dp->base.base.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
        intel_dp->DP = (DP_VOLTAGE_0_4 |
@@ -754,13 +765,14 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        }
 }
 
-static void ironlake_edp_panel_on (struct drm_device *dev)
+/* Returns true if the panel was already on when called */
+static bool ironlake_edp_panel_on (struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 pp;
 
        if (I915_READ(PCH_PP_STATUS) & PP_ON)
-               return;
+               return true;
 
        pp = I915_READ(PCH_PP_CONTROL);
 
@@ -769,17 +781,24 @@ static void ironlake_edp_panel_on (struct drm_device *dev)
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
 
-       pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
+       pp |= POWER_TARGET_ON;
        I915_WRITE(PCH_PP_CONTROL, pp);
 
-       if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10))
+       /* Ouch. We need to wait here for some panels, like Dell e6510
+        * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
+        */
+       msleep(300);
+
+       if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000))
                DRM_ERROR("panel on wait timed out: 0x%08x\n",
                          I915_READ(PCH_PP_STATUS));
 
-       pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD);
+       pp &= ~(PANEL_UNLOCK_REGS);
        pp |= PANEL_POWER_RESET; /* restore panel reset bit */
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
+
+       return false;
 }
 
 static void ironlake_edp_panel_off (struct drm_device *dev)
@@ -797,14 +816,43 @@ static void ironlake_edp_panel_off (struct drm_device *dev)
        pp &= ~POWER_TARGET_ON;
        I915_WRITE(PCH_PP_CONTROL, pp);
 
-       if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10))
+       if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000))
                DRM_ERROR("panel off wait timed out: 0x%08x\n",
                          I915_READ(PCH_PP_STATUS));
 
        /* Make sure VDD is enabled so DP AUX will work */
-       pp |= EDP_FORCE_VDD | PANEL_POWER_RESET; /* restore panel reset bit */
+       pp |= PANEL_POWER_RESET; /* restore panel reset bit */
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
+
+       /* Ouch. We need to wait here for some panels, like Dell e6510
+        * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
+        */
+       msleep(300);
+}
+
+static void ironlake_edp_panel_vdd_on(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pp;
+
+       pp = I915_READ(PCH_PP_CONTROL);
+       pp |= EDP_FORCE_VDD;
+       I915_WRITE(PCH_PP_CONTROL, pp);
+       POSTING_READ(PCH_PP_CONTROL);
+       msleep(300);
+}
+
+static void ironlake_edp_panel_vdd_off(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pp;
+
+       pp = I915_READ(PCH_PP_CONTROL);
+       pp &= ~EDP_FORCE_VDD;
+       I915_WRITE(PCH_PP_CONTROL, pp);
+       POSTING_READ(PCH_PP_CONTROL);
+       msleep(300);
 }
 
 static void ironlake_edp_backlight_on (struct drm_device *dev)
@@ -850,6 +898,7 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder)
        dpa_ctl = I915_READ(DP_A);
        dpa_ctl |= DP_PLL_ENABLE;
        I915_WRITE(DP_A, dpa_ctl);
+       POSTING_READ(DP_A);
        udelay(200);
 }
 
@@ -860,9 +909,10 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
-       if (IS_eDP(intel_dp)) {
+       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+               ironlake_edp_panel_off(dev);
                ironlake_edp_backlight_off(dev);
-               ironlake_edp_panel_on(dev);
+               ironlake_edp_panel_vdd_on(dev);
                ironlake_edp_pll_on(encoder);
        }
        if (dp_reg & DP_PORT_EN)
@@ -873,14 +923,17 @@ static void intel_dp_commit(struct drm_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
        struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
-       if (!(dp_reg & DP_PORT_EN)) {
-               intel_dp_link_train(intel_dp);
-       }
+       intel_dp_start_link_train(intel_dp);
+
+       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+               ironlake_edp_panel_on(dev);
+
+       intel_dp_complete_link_train(intel_dp);
+
        if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
                ironlake_edp_backlight_on(dev);
+       intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
 }
 
 static void
@@ -902,9 +955,10 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
                        ironlake_edp_pll_off(encoder);
        } else {
                if (!(dp_reg & DP_PORT_EN)) {
+                       intel_dp_start_link_train(intel_dp);
                        if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
                                ironlake_edp_panel_on(dev);
-                       intel_dp_link_train(intel_dp);
+                       intel_dp_complete_link_train(intel_dp);
                        if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
                                ironlake_edp_backlight_on(dev);
                }
@@ -917,14 +971,13 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
  * link status information
  */
 static bool
-intel_dp_get_link_status(struct intel_dp *intel_dp,
-                        uint8_t link_status[DP_LINK_STATUS_SIZE])
+intel_dp_get_link_status(struct intel_dp *intel_dp)
 {
        int ret;
 
        ret = intel_dp_aux_native_read(intel_dp,
                                       DP_LANE0_1_STATUS,
-                                      link_status, DP_LINK_STATUS_SIZE);
+                                      intel_dp->link_status, DP_LINK_STATUS_SIZE);
        if (ret != DP_LINK_STATUS_SIZE)
                return false;
        return true;
@@ -999,18 +1052,15 @@ intel_dp_pre_emphasis_max(uint8_t voltage_swing)
 }
 
 static void
-intel_get_adjust_train(struct intel_dp *intel_dp,
-                      uint8_t link_status[DP_LINK_STATUS_SIZE],
-                      int lane_count,
-                      uint8_t train_set[4])
+intel_get_adjust_train(struct intel_dp *intel_dp)
 {
        uint8_t v = 0;
        uint8_t p = 0;
        int lane;
 
-       for (lane = 0; lane < lane_count; lane++) {
-               uint8_t this_v = intel_get_adjust_request_voltage(link_status, lane);
-               uint8_t this_p = intel_get_adjust_request_pre_emphasis(link_status, lane);
+       for (lane = 0; lane < intel_dp->lane_count; lane++) {
+               uint8_t this_v = intel_get_adjust_request_voltage(intel_dp->link_status, lane);
+               uint8_t this_p = intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane);
 
                if (this_v > v)
                        v = this_v;
@@ -1025,7 +1075,7 @@ intel_get_adjust_train(struct intel_dp *intel_dp,
                p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
 
        for (lane = 0; lane < 4; lane++)
-               train_set[lane] = v | p;
+               intel_dp->train_set[lane] = v | p;
 }
 
 static uint32_t
@@ -1116,18 +1166,18 @@ intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count
                         DP_LANE_CHANNEL_EQ_DONE|\
                         DP_LANE_SYMBOL_LOCKED)
 static bool
-intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+intel_channel_eq_ok(struct intel_dp *intel_dp)
 {
        uint8_t lane_align;
        uint8_t lane_status;
        int lane;
 
-       lane_align = intel_dp_link_status(link_status,
+       lane_align = intel_dp_link_status(intel_dp->link_status,
                                          DP_LANE_ALIGN_STATUS_UPDATED);
        if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
                return false;
-       for (lane = 0; lane < lane_count; lane++) {
-               lane_status = intel_get_lane_status(link_status, lane);
+       for (lane = 0; lane < intel_dp->lane_count; lane++) {
+               lane_status = intel_get_lane_status(intel_dp->link_status, lane);
                if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
                        return false;
        }
@@ -1137,48 +1187,47 @@ intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
 static bool
 intel_dp_set_link_train(struct intel_dp *intel_dp,
                        uint32_t dp_reg_value,
-                       uint8_t dp_train_pat,
-                       uint8_t train_set[4],
-                       bool first)
+                       uint8_t dp_train_pat)
 {
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);
        int ret;
 
        I915_WRITE(intel_dp->output_reg, dp_reg_value);
        POSTING_READ(intel_dp->output_reg);
-       if (first)
-               intel_wait_for_vblank(dev, intel_crtc->pipe);
 
        intel_dp_aux_native_write_1(intel_dp,
                                    DP_TRAINING_PATTERN_SET,
                                    dp_train_pat);
 
        ret = intel_dp_aux_native_write(intel_dp,
-                                       DP_TRAINING_LANE0_SET, train_set, 4);
+                                       DP_TRAINING_LANE0_SET,
+                                       intel_dp->train_set, 4);
        if (ret != 4)
                return false;
 
        return true;
 }
 
+/* Enable corresponding port and start training pattern 1 */
 static void
-intel_dp_link_train(struct intel_dp *intel_dp)
+intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint8_t train_set[4];
-       uint8_t link_status[DP_LINK_STATUS_SIZE];
+       struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
        int i;
        uint8_t voltage;
        bool clock_recovery = false;
-       bool channel_eq = false;
-       bool first = true;
        int tries;
        u32 reg;
        uint32_t DP = intel_dp->DP;
 
+       /* Enable output, wait for it to become active */
+       I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+       POSTING_READ(intel_dp->output_reg);
+       intel_wait_for_vblank(dev, intel_crtc->pipe);
+
        /* Write the link configuration data */
        intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
                                  intel_dp->link_configuration,
@@ -1189,18 +1238,18 @@ intel_dp_link_train(struct intel_dp *intel_dp)
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
        else
                DP &= ~DP_LINK_TRAIN_MASK;
-       memset(train_set, 0, 4);
+       memset(intel_dp->train_set, 0, 4);
        voltage = 0xff;
        tries = 0;
        clock_recovery = false;
        for (;;) {
-               /* Use train_set[0] to set the voltage and pre emphasis values */
+               /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
                uint32_t    signal_levels;
                if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
-                       signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+                       signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
                        DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
                } else {
-                       signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count);
+                       signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
 
@@ -1210,52 +1259,64 @@ intel_dp_link_train(struct intel_dp *intel_dp)
                        reg = DP | DP_LINK_TRAIN_PAT_1;
 
                if (!intel_dp_set_link_train(intel_dp, reg,
-                                            DP_TRAINING_PATTERN_1, train_set, first))
+                                            DP_TRAINING_PATTERN_1))
                        break;
-               first = false;
                /* Set training pattern 1 */
 
                udelay(100);
-               if (!intel_dp_get_link_status(intel_dp, link_status))
+               if (!intel_dp_get_link_status(intel_dp))
                        break;
 
-               if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) {
+               if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
                        clock_recovery = true;
                        break;
                }
 
                /* Check to see if we've tried the max voltage */
                for (i = 0; i < intel_dp->lane_count; i++)
-                       if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+                       if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
                                break;
                if (i == intel_dp->lane_count)
                        break;
 
                /* Check to see if we've tried the same voltage 5 times */
-               if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+               if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
                        ++tries;
                        if (tries == 5)
                                break;
                } else
                        tries = 0;
-               voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+               voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
-               /* Compute new train_set as requested by target */
-               intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set);
+               /* Compute new intel_dp->train_set as requested by target */
+               intel_get_adjust_train(intel_dp);
        }
 
+       intel_dp->DP = DP;
+}
+
+static void
+intel_dp_complete_link_train(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       bool channel_eq = false;
+       int tries;
+       u32 reg;
+       uint32_t DP = intel_dp->DP;
+
        /* channel equalization */
        tries = 0;
        channel_eq = false;
        for (;;) {
-               /* Use train_set[0] to set the voltage and pre emphasis values */
+               /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
                uint32_t    signal_levels;
 
                if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
-                       signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+                       signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
                        DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
                } else {
-                       signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count);
+                       signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
 
@@ -1266,15 +1327,14 @@ intel_dp_link_train(struct intel_dp *intel_dp)
 
                /* channel eq pattern */
                if (!intel_dp_set_link_train(intel_dp, reg,
-                                            DP_TRAINING_PATTERN_2, train_set,
-                                            false))
+                                            DP_TRAINING_PATTERN_2))
                        break;
 
                udelay(400);
-               if (!intel_dp_get_link_status(intel_dp, link_status))
+               if (!intel_dp_get_link_status(intel_dp))
                        break;
 
-               if (intel_channel_eq_ok(link_status, intel_dp->lane_count)) {
+               if (intel_channel_eq_ok(intel_dp)) {
                        channel_eq = true;
                        break;
                }
@@ -1283,8 +1343,8 @@ intel_dp_link_train(struct intel_dp *intel_dp)
                if (tries > 5)
                        break;
 
-               /* Compute new train_set as requested by target */
-               intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set);
+               /* Compute new intel_dp->train_set as requested by target */
+               intel_get_adjust_train(intel_dp);
                ++tries;
        }
 
@@ -1302,7 +1362,7 @@ intel_dp_link_train(struct intel_dp *intel_dp)
 static void
 intel_dp_link_down(struct intel_dp *intel_dp)
 {
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t DP = intel_dp->DP;
 
@@ -1318,14 +1378,13 @@ intel_dp_link_down(struct intel_dp *intel_dp)
        if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) {
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
-               POSTING_READ(intel_dp->output_reg);
        } else {
                DP &= ~DP_LINK_TRAIN_MASK;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
-               POSTING_READ(intel_dp->output_reg);
        }
+       POSTING_READ(intel_dp->output_reg);
 
-       udelay(17000);
+       msleep(17);
 
        if (IS_eDP(intel_dp))
                DP |= DP_LINK_TRAIN_OFF;
@@ -1345,27 +1404,29 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 static void
 intel_dp_check_link_status(struct intel_dp *intel_dp)
 {
-       uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-       if (!intel_dp->base.enc.crtc)
+       if (!intel_dp->base.base.crtc)
                return;
 
-       if (!intel_dp_get_link_status(intel_dp, link_status)) {
+       if (!intel_dp_get_link_status(intel_dp)) {
                intel_dp_link_down(intel_dp);
                return;
        }
 
-       if (!intel_channel_eq_ok(link_status, intel_dp->lane_count))
-               intel_dp_link_train(intel_dp);
+       if (!intel_channel_eq_ok(intel_dp)) {
+               intel_dp_start_link_train(intel_dp);
+               intel_dp_complete_link_train(intel_dp);
+       }
 }
 
 static enum drm_connector_status
 ironlake_dp_detect(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
        enum drm_connector_status status;
 
+       /* Panel needs power for AUX to work */
+       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+               ironlake_edp_panel_vdd_on(connector->dev);
        status = connector_status_disconnected;
        if (intel_dp_aux_native_read(intel_dp,
                                     0x000, intel_dp->dpcd,
@@ -1376,6 +1437,8 @@ ironlake_dp_detect(struct drm_connector *connector)
        }
        DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0],
                      intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]);
+       if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+               ironlake_edp_panel_vdd_off(connector->dev);
        return status;
 }
 
@@ -1388,9 +1451,8 @@ ironlake_dp_detect(struct drm_connector *connector)
 static enum drm_connector_status
 intel_dp_detect(struct drm_connector *connector, bool force)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t temp, bit;
        enum drm_connector_status status;
@@ -1432,16 +1494,15 @@ intel_dp_detect(struct drm_connector *connector, bool force)
 
 static int intel_dp_get_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_device *dev = intel_dp->base.enc.dev;
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct drm_device *dev = intel_dp->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
        /* We should parse the EDID data and find out if it has an audio sink
         */
 
-       ret = intel_ddc_get_modes(connector, intel_dp->base.ddc_bus);
+       ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
        if (ret) {
                if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
                    !dev_priv->panel_fixed_mode) {
@@ -1479,6 +1540,15 @@ intel_dp_destroy (struct drm_connector *connector)
        kfree(connector);
 }
 
+static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+       i2c_del_adapter(&intel_dp->adapter);
+       drm_encoder_cleanup(encoder);
+       kfree(intel_dp);
+}
+
 static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
        .dpms = intel_dp_dpms,
        .mode_fixup = intel_dp_mode_fixup,
@@ -1497,14 +1567,14 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
        .get_modes = intel_dp_get_modes,
        .mode_valid = intel_dp_mode_valid,
-       .best_encoder = intel_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_dp_enc_funcs = {
-       .destroy = intel_encoder_destroy,
+       .destroy = intel_dp_encoder_destroy,
 };
 
-void
+static void
 intel_dp_hot_plug(struct intel_encoder *intel_encoder)
 {
        struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
@@ -1613,12 +1683,11 @@ intel_dp_init(struct drm_device *dev, int output_reg)
        intel_dp->has_audio = false;
        intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
 
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_dp_enc_funcs,
+       drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs,
                         DRM_MODE_ENCODER_TMDS);
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_dp_helper_funcs);
+       drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs);
 
-       drm_mode_connector_attach_encoder(&intel_connector->base,
-                                         &intel_encoder->enc);
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
        drm_sysfs_connector_add(connector);
 
        /* Set up the DDC bus. */
@@ -1648,7 +1717,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
 
        intel_dp_i2c_init(intel_dp, intel_connector, name);
 
-       intel_encoder->ddc_bus = &intel_dp->adapter;
        intel_encoder->hot_plug = intel_dp_hot_plug;
 
        if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
index ad312ca6b3e570125732168b3c2f670467264beb..40e99bf27ff7e23a59a838d37ce5cbd85783dff2 100644 (file)
 #define __INTEL_DRV_H__
 
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
-#include <linux/i2c-algo-bit.h>
 #include "i915_drv.h"
 #include "drm_crtc.h"
-
 #include "drm_crtc_helper.h"
+#include "drm_fb_helper.h"
 
-#define wait_for(COND, MS, W) ({ \
+#define _wait_for(COND, MS, W) ({ \
        unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);       \
        int ret__ = 0;                                                  \
        while (! (COND)) {                                              \
                        ret__ = -ETIMEDOUT;                             \
                        break;                                          \
                }                                                       \
-               if (W) msleep(W);                                       \
+               if (W && !in_dbg_master()) msleep(W);                   \
        }                                                               \
        ret__;                                                          \
 })
 
+#define wait_for(COND, MS) _wait_for(COND, MS, 1)
+#define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0)
+
+#define MSLEEP(x) do { \
+       if (in_dbg_master()) \
+               mdelay(x); \
+       else \
+               msleep(x); \
+} while(0)
+
+#define KHz(x) (1000*x)
+#define MHz(x) KHz(1000*x)
+
 /*
  * Display related stuff
  */
 #define INTEL_DVO_CHIP_TMDS 2
 #define INTEL_DVO_CHIP_TVOUT 4
 
-struct intel_i2c_chan {
-       struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */
-       u32 reg; /* GPIO reg */
-       struct i2c_adapter adapter;
-       struct i2c_algo_bit_data algo;
-};
+/* drm_display_mode->private_flags */
+#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
+#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
+
+static inline void
+intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
+                               int multiplier)
+{
+       mode->clock *= multiplier;
+       mode->private_flags |= multiplier;
+}
+
+static inline int
+intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
+{
+       return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
+}
 
 struct intel_framebuffer {
        struct drm_framebuffer base;
        struct drm_gem_object *obj;
 };
 
+struct intel_fbdev {
+       struct drm_fb_helper helper;
+       struct intel_framebuffer ifb;
+       struct list_head fbdev_list;
+       struct drm_display_mode *our_mode;
+};
 
 struct intel_encoder {
-       struct drm_encoder enc;
+       struct drm_encoder base;
        int type;
-       struct i2c_adapter *i2c_bus;
-       struct i2c_adapter *ddc_bus;
        bool load_detect_temp;
        bool needs_tv_clock;
        void (*hot_plug)(struct intel_encoder *);
@@ -123,32 +149,7 @@ struct intel_encoder {
 
 struct intel_connector {
        struct drm_connector base;
-};
-
-struct intel_crtc;
-struct intel_overlay {
-       struct drm_device *dev;
-       struct intel_crtc *crtc;
-       struct drm_i915_gem_object *vid_bo;
-       struct drm_i915_gem_object *old_vid_bo;
-       int active;
-       int pfit_active;
-       u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
-       u32 color_key;
-       u32 brightness, contrast, saturation;
-       u32 old_xscale, old_yscale;
-       /* register access */
-       u32 flip_addr;
-       struct drm_i915_gem_object *reg_bo;
-       void *virt_addr;
-       /* flip handling */
-       uint32_t last_flip_req;
-       int hw_wedged;
-#define HW_WEDGED              1
-#define NEEDS_WAIT_FOR_FLIP    2
-#define RELEASE_OLD_VID                3
-#define SWITCH_OFF_STAGE_1     4
-#define SWITCH_OFF_STAGE_2     5
+       struct intel_encoder *encoder;
 };
 
 struct intel_crtc {
@@ -157,6 +158,7 @@ struct intel_crtc {
        enum plane plane;
        u8 lut_r[256], lut_g[256], lut_b[256];
        int dpms_mode;
+       bool active; /* is the crtc on? independent of the dpms mode */
        bool busy; /* is scanout buffer being updated frequently? */
        struct timer_list idle_timer;
        bool lowfreq_avail;
@@ -168,14 +170,21 @@ struct intel_crtc {
        uint32_t cursor_addr;
        int16_t cursor_x, cursor_y;
        int16_t cursor_width, cursor_height;
-       bool cursor_visible, cursor_on;
+       bool cursor_visible;
 };
 
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
 #define to_intel_connector(x) container_of(x, struct intel_connector, base)
-#define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc)
+#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 
+static inline struct drm_crtc *
+intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       return dev_priv->pipe_to_crtc_mapping[pipe];
+}
+
 struct intel_unpin_work {
        struct work_struct work;
        struct drm_device *dev;
@@ -186,13 +195,8 @@ struct intel_unpin_work {
        bool enable_stall_check;
 };
 
-struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
-                                    const char *name);
-void intel_i2c_destroy(struct i2c_adapter *adapter);
 int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
-extern bool intel_ddc_probe(struct intel_encoder *intel_encoder);
-void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
-void intel_i2c_reset_gmbus(struct drm_device *dev);
+extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
 
 extern void intel_crt_init(struct drm_device *dev);
 extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
@@ -209,29 +213,37 @@ extern bool intel_pch_has_edp(struct drm_crtc *crtc);
 extern bool intel_dpd_is_edp(struct drm_device *dev);
 extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
 
-
+/* intel_panel.c */
 extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
                                   struct drm_display_mode *adjusted_mode);
 extern void intel_pch_panel_fitting(struct drm_device *dev,
                                    int fitting_mode,
                                    struct drm_display_mode *mode,
                                    struct drm_display_mode *adjusted_mode);
+extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
+extern u32 intel_panel_get_backlight(struct drm_device *dev);
+extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
 
-extern int intel_panel_fitter_pipe (struct drm_device *dev);
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_encoder_prepare (struct drm_encoder *encoder);
 extern void intel_encoder_commit (struct drm_encoder *encoder);
 extern void intel_encoder_destroy(struct drm_encoder *encoder);
 
-extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector);
+static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
+{
+       return to_intel_connector(connector)->encoder;
+}
+
+extern void intel_connector_attach_encoder(struct intel_connector *connector,
+                                          struct intel_encoder *encoder);
+extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
 
 extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
                                                    struct drm_crtc *crtc);
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
-extern void intel_wait_for_vblank_off(struct drm_device *dev, int pipe);
 extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
+extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
 extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
                                                   struct drm_connector *connector,
                                                   struct drm_display_mode *mode,
@@ -253,7 +265,8 @@ extern void ironlake_enable_drps(struct drm_device *dev);
 extern void ironlake_disable_drps(struct drm_device *dev);
 
 extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
-                                     struct drm_gem_object *obj);
+                                     struct drm_gem_object *obj,
+                                     bool pipelined);
 
 extern int intel_framebuffer_init(struct drm_device *dev,
                                  struct intel_framebuffer *ifb,
@@ -268,9 +281,8 @@ extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
 
 extern void intel_setup_overlay(struct drm_device *dev);
 extern void intel_cleanup_overlay(struct drm_device *dev);
-extern int intel_overlay_switch_off(struct intel_overlay *overlay);
-extern int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
-                                               int interruptible);
+extern int intel_overlay_switch_off(struct intel_overlay *overlay,
+                                   bool interruptible);
 extern int intel_overlay_put_image(struct drm_device *dev, void *data,
                                   struct drm_file *file_priv);
 extern int intel_overlay_attrs(struct drm_device *dev, void *data,
index 7c9ec1472d46ab3cbb08f6bffc8257af952a64b0..ea373283c93be6e16edabd4714ae0eb1c89b0da9 100644 (file)
@@ -72,7 +72,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
                .name = "ch7017",
                .dvo_reg = DVOC,
                .slave_addr = 0x75,
-               .gpio = GPIOE,
+               .gpio = GMBUS_PORT_DPB,
                .dev_ops = &ch7017_ops,
        }
 };
@@ -88,7 +88,13 @@ struct intel_dvo {
 
 static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_dvo, base);
+       return container_of(encoder, struct intel_dvo, base.base);
+}
+
+static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
+{
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_dvo, base);
 }
 
 static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
@@ -112,8 +118,7 @@ static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
 static int intel_dvo_mode_valid(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
@@ -224,23 +229,22 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
 static enum drm_connector_status
 intel_dvo_detect(struct drm_connector *connector, bool force)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
-
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
        return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
 }
 
 static int intel_dvo_get_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
        /* We should probably have an i2c driver get_modes function for those
         * devices which will have a fixed set of modes determined by the chip
         * (TV-out, for example), but for now with just TMDS and LVDS,
         * that's not the case.
         */
-       intel_ddc_get_modes(connector, intel_dvo->base.ddc_bus);
+       intel_ddc_get_modes(connector,
+                           &dev_priv->gmbus[GMBUS_PORT_DPC].adapter);
        if (!list_empty(&connector->probed_modes))
                return 1;
 
@@ -281,7 +285,7 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
        .mode_valid = intel_dvo_mode_valid,
        .get_modes = intel_dvo_get_modes,
-       .best_encoder = intel_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
@@ -311,8 +315,7 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+       struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
        uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg);
        struct drm_display_mode *mode = NULL;
 
@@ -323,7 +326,7 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
                struct drm_crtc *crtc;
                int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;
 
-               crtc = intel_get_crtc_from_pipe(dev, pipe);
+               crtc = intel_get_crtc_for_pipe(dev, pipe);
                if (crtc) {
                        mode = intel_crtc_mode_get(dev, crtc);
                        if (mode) {
@@ -341,11 +344,10 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
 
 void intel_dvo_init(struct drm_device *dev)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *intel_encoder;
        struct intel_dvo *intel_dvo;
        struct intel_connector *intel_connector;
-       struct i2c_adapter *i2cbus = NULL;
-       int ret = 0;
        int i;
        int encoder_type = DRM_MODE_ENCODER_NONE;
 
@@ -360,16 +362,14 @@ void intel_dvo_init(struct drm_device *dev)
        }
 
        intel_encoder = &intel_dvo->base;
-
-       /* Set up the DDC bus */
-       intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D");
-       if (!intel_encoder->ddc_bus)
-               goto free_intel;
+       drm_encoder_init(dev, &intel_encoder->base,
+                        &intel_dvo_enc_funcs, encoder_type);
 
        /* Now, try to find a controller */
        for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
                struct drm_connector *connector = &intel_connector->base;
                const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
+               struct i2c_adapter *i2c;
                int gpio;
 
                /* Allow the I2C driver info to specify the GPIO to be used in
@@ -379,24 +379,18 @@ void intel_dvo_init(struct drm_device *dev)
                if (dvo->gpio != 0)
                        gpio = dvo->gpio;
                else if (dvo->type == INTEL_DVO_CHIP_LVDS)
-                       gpio = GPIOB;
+                       gpio = GMBUS_PORT_SSC;
                else
-                       gpio = GPIOE;
+                       gpio = GMBUS_PORT_DPB;
 
                /* Set up the I2C bus necessary for the chip we're probing.
                 * It appears that everything is on GPIOE except for panels
                 * on i830 laptops, which are on GPIOB (DVOA).
                 */
-               if (i2cbus != NULL)
-                       intel_i2c_destroy(i2cbus);
-               if (!(i2cbus = intel_i2c_create(dev, gpio,
-                       gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
-                       continue;
-               }
+               i2c = &dev_priv->gmbus[gpio].adapter;
 
                intel_dvo->dev = *dvo;
-               ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus);
-               if (!ret)
+               if (!dvo->dev_ops->init(&intel_dvo->dev, i2c))
                        continue;
 
                intel_encoder->type = INTEL_OUTPUT_DVO;
@@ -427,13 +421,10 @@ void intel_dvo_init(struct drm_device *dev)
                connector->interlace_allowed = false;
                connector->doublescan_allowed = false;
 
-               drm_encoder_init(dev, &intel_encoder->enc,
-                                &intel_dvo_enc_funcs, encoder_type);
-               drm_encoder_helper_add(&intel_encoder->enc,
+               drm_encoder_helper_add(&intel_encoder->base,
                                       &intel_dvo_helper_funcs);
 
-               drm_mode_connector_attach_encoder(&intel_connector->base,
-                                                 &intel_encoder->enc);
+               intel_connector_attach_encoder(intel_connector, intel_encoder);
                if (dvo->type == INTEL_DVO_CHIP_LVDS) {
                        /* For our LVDS chipsets, we should hopefully be able
                         * to dig the fixed panel mode out of the BIOS data.
@@ -451,11 +442,7 @@ void intel_dvo_init(struct drm_device *dev)
                return;
        }
 
-       intel_i2c_destroy(intel_encoder->ddc_bus);
-       /* Didn't find a chip, so tear down. */
-       if (i2cbus != NULL)
-               intel_i2c_destroy(i2cbus);
-free_intel:
+       drm_encoder_cleanup(&intel_encoder->base);
        kfree(intel_dvo);
        kfree(intel_connector);
 }
index 7bdc96256bf55b6e87d102377b428a871792be91..b937ccfa7bec9a037ae7b6fddf6d635552a4aba1 100644 (file)
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-struct intel_fbdev {
-       struct drm_fb_helper helper;
-       struct intel_framebuffer ifb;
-       struct list_head fbdev_list;
-       struct drm_display_mode *our_mode;
-};
-
 static struct fb_ops intelfb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
@@ -75,7 +68,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
        struct drm_gem_object *fbo = NULL;
        struct drm_i915_gem_object *obj_priv;
        struct device *device = &dev->pdev->dev;
-       int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1;
+       int size, ret, mmio_bar = IS_GEN2(dev) ? 1 : 0;
 
        /* we don't do packed 24bpp */
        if (sizes->surface_bpp == 24)
@@ -100,19 +93,13 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
 
        mutex_lock(&dev->struct_mutex);
 
-       ret = intel_pin_and_fence_fb_obj(dev, fbo);
+       /* Flush everything out, we'll be doing GTT only from now on */
+       ret = intel_pin_and_fence_fb_obj(dev, fbo, false);
        if (ret) {
                DRM_ERROR("failed to pin fb: %d\n", ret);
                goto out_unref;
        }
 
-       /* Flush everything out, we'll be doing GTT only from now on */
-       ret = i915_gem_object_set_to_gtt_domain(fbo, 1);
-       if (ret) {
-               DRM_ERROR("failed to bind fb: %d.\n", ret);
-               goto out_unpin;
-       }
-
        info = framebuffer_alloc(0, device);
        if (!info) {
                ret = -ENOMEM;
@@ -142,7 +129,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
                goto out_unpin;
        }
        info->apertures->ranges[0].base = dev->mode_config.fb_base;
-       if (IS_I9XX(dev))
+       if (!IS_GEN2(dev))
                info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2);
        else
                info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
@@ -219,8 +206,8 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
        .fb_probe = intel_fb_find_or_create_single,
 };
 
-int intel_fbdev_destroy(struct drm_device *dev,
-                       struct intel_fbdev *ifbdev)
+static void intel_fbdev_destroy(struct drm_device *dev,
+                               struct intel_fbdev *ifbdev)
 {
        struct fb_info *info;
        struct intel_framebuffer *ifb = &ifbdev->ifb;
@@ -237,10 +224,10 @@ int intel_fbdev_destroy(struct drm_device *dev,
        drm_fb_helper_fini(&ifbdev->helper);
 
        drm_framebuffer_cleanup(&ifb->base);
-       if (ifb->obj)
-               drm_gem_object_unreference(ifb->obj);
-
-       return 0;
+       if (ifb->obj) {
+               drm_gem_object_handle_unreference_unlocked(ifb->obj);
+               drm_gem_object_unreference_unlocked(ifb->obj);
+       }
 }
 
 int intel_fbdev_init(struct drm_device *dev)
index 926934a482ec085c63256567e27f0309b51b24cf..9fb9501f2d0751e0c863e575c987203de1b42e70 100644 (file)
 struct intel_hdmi {
        struct intel_encoder base;
        u32 sdvox_reg;
+       int ddc_bus;
        bool has_hdmi_sink;
 };
 
 static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base);
+       return container_of(encoder, struct intel_hdmi, base.base);
+}
+
+static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
+{
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_hdmi, base);
 }
 
 static void intel_hdmi_mode_set(struct drm_encoder *encoder,
@@ -141,13 +148,14 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-       struct edid *edid = NULL;
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       struct edid *edid;
        enum drm_connector_status status = connector_status_disconnected;
 
        intel_hdmi->has_hdmi_sink = false;
-       edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus);
+       edid = drm_get_edid(connector,
+                           &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
 
        if (edid) {
                if (edid->input & DRM_EDID_INPUT_DIGITAL) {
@@ -163,14 +171,15 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
 
 static int intel_hdmi_get_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
        /* We should parse the EDID data and find out if it's an HDMI sink so
         * we can send audio to it.
         */
 
-       return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus);
+       return intel_ddc_get_modes(connector,
+                                  &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
 }
 
 static void intel_hdmi_destroy(struct drm_connector *connector)
@@ -198,7 +207,7 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
        .get_modes = intel_hdmi_get_modes,
        .mode_valid = intel_hdmi_mode_valid,
-       .best_encoder = intel_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
@@ -224,6 +233,9 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
        }
 
        intel_encoder = &intel_hdmi->base;
+       drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+
        connector = &intel_connector->base;
        drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
                           DRM_MODE_CONNECTOR_HDMIA);
@@ -239,39 +251,31 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
        /* Set up the DDC bus. */
        if (sdvox_reg == SDVOB) {
                intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
-               intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
+               intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
                dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == SDVOC) {
                intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
-               intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
+               intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
                dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == HDMIB) {
                intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
-               intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
-                                                               "HDMIB");
+               intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
                dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == HDMIC) {
                intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
-               intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
-                                                               "HDMIC");
+               intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
                dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
        } else if (sdvox_reg == HDMID) {
                intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
-               intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
-                                                               "HDMID");
+               intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
                dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
        }
-       if (!intel_encoder->ddc_bus)
-               goto err_connector;
 
        intel_hdmi->sdvox_reg = sdvox_reg;
 
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs,
-                        DRM_MODE_ENCODER_TMDS);
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_hdmi_helper_funcs);
+       drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
 
-       drm_mode_connector_attach_encoder(&intel_connector->base,
-                                         &intel_encoder->enc);
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
        drm_sysfs_connector_add(connector);
 
        /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
@@ -282,13 +286,4 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
                u32 temp = I915_READ(PEG_BAND_GAP_DATA);
                I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
        }
-
-       return;
-
-err_connector:
-       drm_connector_cleanup(connector);
-       kfree(intel_hdmi);
-       kfree(intel_connector);
-
-       return;
 }
index c2649c7df14c7e654aba8eb495c3874c698707b5..2449a74d4d8030c3222006bd96b46566aac1f819 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
- * Copyright Â© 2006-2008 Intel Corporation
+ * Copyright Â© 2006-2008,2010 Intel Corporation
  *   Jesse Barnes <jesse.barnes@intel.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  *
  * Authors:
  *     Eric Anholt <eric@anholt.net>
+ *     Chris Wilson <chris@chris-wilson.co.uk>
  */
 #include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
 #include "drmP.h"
 #include "drm.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-void intel_i2c_quirk_set(struct drm_device *dev, bool enable)
+/* Intel GPIO access functions */
+
+#define I2C_RISEFALL_TIME 20
+
+static inline struct intel_gmbus *
+to_intel_gmbus(struct i2c_adapter *i2c)
+{
+       return container_of(i2c, struct intel_gmbus, adapter);
+}
+
+struct intel_gpio {
+       struct i2c_adapter adapter;
+       struct i2c_algo_bit_data algo;
+       struct drm_i915_private *dev_priv;
+       u32 reg;
+};
+
+void
+intel_i2c_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       if (HAS_PCH_SPLIT(dev))
+               I915_WRITE(PCH_GMBUS0, 0);
+       else
+               I915_WRITE(GMBUS0, 0);
+}
+
+static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable)
+{
+       u32 val;
 
        /* When using bit bashing for I2C, this bit needs to be set to 1 */
-       if (!IS_PINEVIEW(dev))
+       if (!IS_PINEVIEW(dev_priv->dev))
                return;
+
+       val = I915_READ(DSPCLK_GATE_D);
        if (enable)
-               I915_WRITE(DSPCLK_GATE_D,
-                       I915_READ(DSPCLK_GATE_D) | DPCUNIT_CLOCK_GATE_DISABLE);
+               val |= DPCUNIT_CLOCK_GATE_DISABLE;
        else
-               I915_WRITE(DSPCLK_GATE_D,
-                       I915_READ(DSPCLK_GATE_D) & (~DPCUNIT_CLOCK_GATE_DISABLE));
+               val &= ~DPCUNIT_CLOCK_GATE_DISABLE;
+       I915_WRITE(DSPCLK_GATE_D, val);
 }
 
-/*
- * Intel GPIO access functions
- */
+static u32 get_reserved(struct intel_gpio *gpio)
+{
+       struct drm_i915_private *dev_priv = gpio->dev_priv;
+       struct drm_device *dev = dev_priv->dev;
+       u32 reserved = 0;
 
-#define I2C_RISEFALL_TIME 20
+       /* On most chips, these bits must be preserved in software. */
+       if (!IS_I830(dev) && !IS_845G(dev))
+               reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE |
+                                                  GPIO_CLOCK_PULLUP_DISABLE);
+
+       return reserved;
+}
 
 static int get_clock(void *data)
 {
-       struct intel_i2c_chan *chan = data;
-       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-       u32 val;
-
-       val = I915_READ(chan->reg);
-       return ((val & GPIO_CLOCK_VAL_IN) != 0);
+       struct intel_gpio *gpio = data;
+       struct drm_i915_private *dev_priv = gpio->dev_priv;
+       u32 reserved = get_reserved(gpio);
+       I915_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
+       I915_WRITE(gpio->reg, reserved);
+       return (I915_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
 }
 
 static int get_data(void *data)
 {
-       struct intel_i2c_chan *chan = data;
-       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-       u32 val;
-
-       val = I915_READ(chan->reg);
-       return ((val & GPIO_DATA_VAL_IN) != 0);
+       struct intel_gpio *gpio = data;
+       struct drm_i915_private *dev_priv = gpio->dev_priv;
+       u32 reserved = get_reserved(gpio);
+       I915_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
+       I915_WRITE(gpio->reg, reserved);
+       return (I915_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
 }
 
 static void set_clock(void *data, int state_high)
 {
-       struct intel_i2c_chan *chan = data;
-       struct drm_device *dev = chan->drm_dev;
-       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-       u32 reserved = 0, clock_bits;
-
-       /* On most chips, these bits must be preserved in software. */
-       if (!IS_I830(dev) && !IS_845G(dev))
-               reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
-                                                  GPIO_CLOCK_PULLUP_DISABLE);
+       struct intel_gpio *gpio = data;
+       struct drm_i915_private *dev_priv = gpio->dev_priv;
+       u32 reserved = get_reserved(gpio);
+       u32 clock_bits;
 
        if (state_high)
                clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
        else
                clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
                        GPIO_CLOCK_VAL_MASK;
-       I915_WRITE(chan->reg, reserved | clock_bits);
-       udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+
+       I915_WRITE(gpio->reg, reserved | clock_bits);
+       POSTING_READ(gpio->reg);
 }
 
 static void set_data(void *data, int state_high)
 {
-       struct intel_i2c_chan *chan = data;
-       struct drm_device *dev = chan->drm_dev;
-       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-       u32 reserved = 0, data_bits;
-
-       /* On most chips, these bits must be preserved in software. */
-       if (!IS_I830(dev) && !IS_845G(dev))
-               reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
-                                                  GPIO_CLOCK_PULLUP_DISABLE);
+       struct intel_gpio *gpio = data;
+       struct drm_i915_private *dev_priv = gpio->dev_priv;
+       u32 reserved = get_reserved(gpio);
+       u32 data_bits;
 
        if (state_high)
                data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
@@ -115,109 +141,312 @@ static void set_data(void *data, int state_high)
                data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
                        GPIO_DATA_VAL_MASK;
 
-       I915_WRITE(chan->reg, reserved | data_bits);
-       udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+       I915_WRITE(gpio->reg, reserved | data_bits);
+       POSTING_READ(gpio->reg);
 }
 
-/* Clears the GMBUS setup.  Our driver doesn't make use of the GMBUS I2C
- * engine, but if the BIOS leaves it enabled, then that can break our use
- * of the bit-banging I2C interfaces.  This is notably the case with the
- * Mac Mini in EFI mode.
- */
-void
-intel_i2c_reset_gmbus(struct drm_device *dev)
+static struct i2c_adapter *
+intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       static const int map_pin_to_reg[] = {
+               0,
+               GPIOB,
+               GPIOA,
+               GPIOC,
+               GPIOD,
+               GPIOE,
+               GPIOF,
+       };
+       struct intel_gpio *gpio;
 
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PCH_GMBUS0, 0);
-       } else {
-               I915_WRITE(GMBUS0, 0);
+       if (pin < 1 || pin > 7)
+               return NULL;
+
+       gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
+       if (gpio == NULL)
+               return NULL;
+
+       gpio->reg = map_pin_to_reg[pin];
+       if (HAS_PCH_SPLIT(dev_priv->dev))
+               gpio->reg += PCH_GPIOA - GPIOA;
+       gpio->dev_priv = dev_priv;
+
+       snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO%c", "?BACDEF?"[pin]);
+       gpio->adapter.owner = THIS_MODULE;
+       gpio->adapter.algo_data = &gpio->algo;
+       gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev;
+       gpio->algo.setsda = set_data;
+       gpio->algo.setscl = set_clock;
+       gpio->algo.getsda = get_data;
+       gpio->algo.getscl = get_clock;
+       gpio->algo.udelay = I2C_RISEFALL_TIME;
+       gpio->algo.timeout = usecs_to_jiffies(2200);
+       gpio->algo.data = gpio;
+
+       if (i2c_bit_add_bus(&gpio->adapter))
+               goto out_free;
+
+       return &gpio->adapter;
+
+out_free:
+       kfree(gpio);
+       return NULL;
+}
+
+static int
+intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv,
+                    struct i2c_adapter *adapter,
+                    struct i2c_msg *msgs,
+                    int num)
+{
+       struct intel_gpio *gpio = container_of(adapter,
+                                              struct intel_gpio,
+                                              adapter);
+       int ret;
+
+       intel_i2c_reset(dev_priv->dev);
+
+       intel_i2c_quirk_set(dev_priv, true);
+       set_data(gpio, 1);
+       set_clock(gpio, 1);
+       udelay(I2C_RISEFALL_TIME);
+
+       ret = adapter->algo->master_xfer(adapter, msgs, num);
+
+       set_data(gpio, 1);
+       set_clock(gpio, 1);
+       intel_i2c_quirk_set(dev_priv, false);
+
+       return ret;
+}
+
+static int
+gmbus_xfer(struct i2c_adapter *adapter,
+          struct i2c_msg *msgs,
+          int num)
+{
+       struct intel_gmbus *bus = container_of(adapter,
+                                              struct intel_gmbus,
+                                              adapter);
+       struct drm_i915_private *dev_priv = adapter->algo_data;
+       int i, reg_offset;
+
+       if (bus->force_bit)
+               return intel_i2c_quirk_xfer(dev_priv,
+                                           bus->force_bit, msgs, num);
+
+       reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
+
+       I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
+
+       for (i = 0; i < num; i++) {
+               u16 len = msgs[i].len;
+               u8 *buf = msgs[i].buf;
+
+               if (msgs[i].flags & I2C_M_RD) {
+                       I915_WRITE(GMBUS1 + reg_offset,
+                                  GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
+                                  (len << GMBUS_BYTE_COUNT_SHIFT) |
+                                  (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+                                  GMBUS_SLAVE_READ | GMBUS_SW_RDY);
+                       POSTING_READ(GMBUS2+reg_offset);
+                       do {
+                               u32 val, loop = 0;
+
+                               if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+                                       goto timeout;
+                               if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+                                       return 0;
+
+                               val = I915_READ(GMBUS3 + reg_offset);
+                               do {
+                                       *buf++ = val & 0xff;
+                                       val >>= 8;
+                               } while (--len && ++loop < 4);
+                       } while (len);
+               } else {
+                       u32 val, loop;
+
+                       val = loop = 0;
+                       do {
+                               val |= *buf++ << (8 * loop);
+                       } while (--len && ++loop < 4);
+
+                       I915_WRITE(GMBUS3 + reg_offset, val);
+                       I915_WRITE(GMBUS1 + reg_offset,
+                                  (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) |
+                                  (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
+                                  (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+                                  GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
+                       POSTING_READ(GMBUS2+reg_offset);
+
+                       while (len) {
+                               if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+                                       goto timeout;
+                               if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+                                       return 0;
+
+                               val = loop = 0;
+                               do {
+                                       val |= *buf++ << (8 * loop);
+                               } while (--len && ++loop < 4);
+
+                               I915_WRITE(GMBUS3 + reg_offset, val);
+                               POSTING_READ(GMBUS2+reg_offset);
+                       }
+               }
+
+               if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
+                       goto timeout;
+               if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+                       return 0;
        }
+
+       return num;
+
+timeout:
+       DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
+                bus->reg0 & 0xff, bus->adapter.name);
+       /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
+       bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
+       if (!bus->force_bit)
+               return -ENOMEM;
+
+       return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
 }
 
+static u32 gmbus_func(struct i2c_adapter *adapter)
+{
+       struct intel_gmbus *bus = container_of(adapter,
+                                              struct intel_gmbus,
+                                              adapter);
+
+       if (bus->force_bit)
+               bus->force_bit->algo->functionality(bus->force_bit);
+
+       return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+               /* I2C_FUNC_10BIT_ADDR | */
+               I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+               I2C_FUNC_SMBUS_BLOCK_PROC_CALL);
+}
+
+static const struct i2c_algorithm gmbus_algorithm = {
+       .master_xfer    = gmbus_xfer,
+       .functionality  = gmbus_func
+};
+
 /**
- * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg
+ * intel_gmbus_setup - instantiate all Intel i2c GMBuses
  * @dev: DRM device
- * @output: driver specific output device
- * @reg: GPIO reg to use
- * @name: name for this bus
- * @slave_addr: slave address (if fixed)
- *
- * Creates and registers a new i2c bus with the Linux i2c layer, for use
- * in output probing and control (e.g. DDC or SDVO control functions).
- *
- * Possible values for @reg include:
- *   %GPIOA
- *   %GPIOB
- *   %GPIOC
- *   %GPIOD
- *   %GPIOE
- *   %GPIOF
- *   %GPIOG
- *   %GPIOH
- * see PRM for details on how these different busses are used.
  */
-struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
-                                    const char *name)
+int intel_setup_gmbus(struct drm_device *dev)
 {
-       struct intel_i2c_chan *chan;
+       static const char *names[GMBUS_NUM_PORTS] = {
+               "disabled",
+               "ssc",
+               "vga",
+               "panel",
+               "dpc",
+               "dpb",
+               "reserved"
+               "dpd",
+       };
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret, i;
 
-       chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL);
-       if (!chan)
-               goto out_free;
+       dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
+                                 GFP_KERNEL);
+       if (dev_priv->gmbus == NULL)
+               return -ENOMEM;
 
-       chan->drm_dev = dev;
-       chan->reg = reg;
-       snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name);
-       chan->adapter.owner = THIS_MODULE;
-       chan->adapter.algo_data = &chan->algo;
-       chan->adapter.dev.parent = &dev->pdev->dev;
-       chan->algo.setsda = set_data;
-       chan->algo.setscl = set_clock;
-       chan->algo.getsda = get_data;
-       chan->algo.getscl = get_clock;
-       chan->algo.udelay = 20;
-       chan->algo.timeout = usecs_to_jiffies(2200);
-       chan->algo.data = chan;
-
-       i2c_set_adapdata(&chan->adapter, chan);
-
-       if(i2c_bit_add_bus(&chan->adapter))
-               goto out_free;
+       for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+               struct intel_gmbus *bus = &dev_priv->gmbus[i];
 
-       intel_i2c_reset_gmbus(dev);
+               bus->adapter.owner = THIS_MODULE;
+               bus->adapter.class = I2C_CLASS_DDC;
+               snprintf(bus->adapter.name,
+                        I2C_NAME_SIZE,
+                        "gmbus %s",
+                        names[i]);
 
-       /* JJJ:  raise SCL and SDA? */
-       intel_i2c_quirk_set(dev, true);
-       set_data(chan, 1);
-       set_clock(chan, 1);
-       intel_i2c_quirk_set(dev, false);
-       udelay(20);
+               bus->adapter.dev.parent = &dev->pdev->dev;
+               bus->adapter.algo_data  = dev_priv;
 
-       return &chan->adapter;
+               bus->adapter.algo = &gmbus_algorithm;
+               ret = i2c_add_adapter(&bus->adapter);
+               if (ret)
+                       goto err;
 
-out_free:
-       kfree(chan);
-       return NULL;
+               /* By default use a conservative clock rate */
+               bus->reg0 = i | GMBUS_RATE_100KHZ;
+
+               /* XXX force bit banging until GMBUS is fully debugged */
+               bus->force_bit = intel_gpio_create(dev_priv, i);
+       }
+
+       intel_i2c_reset(dev_priv->dev);
+
+       return 0;
+
+err:
+       while (--i) {
+               struct intel_gmbus *bus = &dev_priv->gmbus[i];
+               i2c_del_adapter(&bus->adapter);
+       }
+       kfree(dev_priv->gmbus);
+       dev_priv->gmbus = NULL;
+       return ret;
 }
 
-/**
- * intel_i2c_destroy - unregister and free i2c bus resources
- * @output: channel to free
- *
- * Unregister the adapter from the i2c layer, then free the structure.
- */
-void intel_i2c_destroy(struct i2c_adapter *adapter)
+void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed)
+{
+       struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+       /* speed:
+        * 0x0 = 100 KHz
+        * 0x1 = 50 KHz
+        * 0x2 = 400 KHz
+        * 0x3 = 1000 Khz
+        */
+       bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | (speed << 8);
+}
+
+void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
+{
+       struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+       if (force_bit) {
+               if (bus->force_bit == NULL) {
+                       struct drm_i915_private *dev_priv = adapter->algo_data;
+                       bus->force_bit = intel_gpio_create(dev_priv,
+                                                          bus->reg0 & 0xff);
+               }
+       } else {
+               if (bus->force_bit) {
+                       i2c_del_adapter(bus->force_bit);
+                       kfree(bus->force_bit);
+                       bus->force_bit = NULL;
+               }
+       }
+}
+
+void intel_teardown_gmbus(struct drm_device *dev)
 {
-       struct intel_i2c_chan *chan;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
 
-       if (!adapter)
+       if (dev_priv->gmbus == NULL)
                return;
 
-       chan = container_of(adapter,
-                           struct intel_i2c_chan,
-                           adapter);
-       i2c_del_adapter(&chan->adapter);
-       kfree(chan);
+       for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+               struct intel_gmbus *bus = &dev_priv->gmbus[i];
+               if (bus->force_bit) {
+                       i2c_del_adapter(bus->force_bit);
+                       kfree(bus->force_bit);
+               }
+               i2c_del_adapter(&bus->adapter);
+       }
+
+       kfree(dev_priv->gmbus);
+       dev_priv->gmbus = NULL;
 }
index 6ec39a86ed06d2bd6e716611f3ab4d384d950636..f1a649990ea9e61d5f7ff6f8b15e127d6fcc2f17 100644 (file)
 /* Private structure for the integrated LVDS support */
 struct intel_lvds {
        struct intel_encoder base;
+
+       struct edid *edid;
+
        int fitting_mode;
        u32 pfit_control;
        u32 pfit_pgm_ratios;
+       bool pfit_dirty;
+
+       struct drm_display_mode *fixed_mode;
 };
 
-static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
+static struct intel_lvds *to_intel_lvds(struct drm_encoder *encoder)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base);
-}
-
-/**
- * Sets the backlight level.
- *
- * \param level backlight level, from 0 to intel_lvds_get_max_backlight().
- */
-static void intel_lvds_set_backlight(struct drm_device *dev, int level)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 blc_pwm_ctl, reg;
-
-       if (HAS_PCH_SPLIT(dev))
-               reg = BLC_PWM_CPU_CTL;
-       else
-               reg = BLC_PWM_CTL;
-
-       blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-       I915_WRITE(reg, (blc_pwm_ctl |
-                                (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
+       return container_of(encoder, struct intel_lvds, base.base);
 }
 
-/**
- * Returns the maximum level of the backlight duty cycle field.
- */
-static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
+static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg;
-
-       if (HAS_PCH_SPLIT(dev))
-               reg = BLC_PWM_PCH_CTL2;
-       else
-               reg = BLC_PWM_CTL;
-
-       return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
-               BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_lvds, base);
 }
 
 /**
  * Sets the power state for the panel.
  */
-static void intel_lvds_set_power(struct drm_device *dev, bool on)
+static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on)
 {
+       struct drm_device *dev = intel_lvds->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 ctl_reg, status_reg, lvds_reg;
+       u32 ctl_reg, lvds_reg;
 
        if (HAS_PCH_SPLIT(dev)) {
                ctl_reg = PCH_PP_CONTROL;
-               status_reg = PCH_PP_STATUS;
                lvds_reg = PCH_LVDS;
        } else {
                ctl_reg = PP_CONTROL;
-               status_reg = PP_STATUS;
                lvds_reg = LVDS;
        }
 
        if (on) {
                I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
-               POSTING_READ(lvds_reg);
-
-               I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
-                          POWER_TARGET_ON);
-               if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0))
-                       DRM_ERROR("timed out waiting to enable LVDS pipe");
-
-               intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
+               I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
+               intel_panel_set_backlight(dev, dev_priv->backlight_level);
        } else {
-               intel_lvds_set_backlight(dev, 0);
+               dev_priv->backlight_level = intel_panel_get_backlight(dev);
+
+               intel_panel_set_backlight(dev, 0);
+               I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
 
-               I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
-                          ~POWER_TARGET_ON);
-               if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0))
-                       DRM_ERROR("timed out waiting for LVDS pipe to turn off");
+               if (intel_lvds->pfit_control) {
+                       if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+                               DRM_ERROR("timed out waiting for panel to power off\n");
+                       I915_WRITE(PFIT_CONTROL, 0);
+                       intel_lvds->pfit_control = 0;
+                       intel_lvds->pfit_dirty = false;
+               }
 
                I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
-               POSTING_READ(lvds_reg);
        }
+       POSTING_READ(lvds_reg);
 }
 
 static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
 {
-       struct drm_device *dev = encoder->dev;
+       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
        if (mode == DRM_MODE_DPMS_ON)
-               intel_lvds_set_power(dev, true);
+               intel_lvds_set_power(intel_lvds, true);
        else
-               intel_lvds_set_power(dev, false);
+               intel_lvds_set_power(intel_lvds, false);
 
        /* XXX: We never power down the LVDS pairs. */
 }
@@ -146,16 +120,13 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
 static int intel_lvds_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
+       struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
+       struct drm_display_mode *fixed_mode = intel_lvds->fixed_mode;
 
-       if (fixed_mode) {
-               if (mode->hdisplay > fixed_mode->hdisplay)
-                       return MODE_PANEL;
-               if (mode->vdisplay > fixed_mode->vdisplay)
-                       return MODE_PANEL;
-       }
+       if (mode->hdisplay > fixed_mode->hdisplay)
+               return MODE_PANEL;
+       if (mode->vdisplay > fixed_mode->vdisplay)
+               return MODE_PANEL;
 
        return MODE_OK;
 }
@@ -223,12 +194,12 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-       struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
        struct drm_encoder *tmp_encoder;
        u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
 
        /* Should never happen!! */
-       if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
+       if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) {
                DRM_ERROR("Can't support LVDS on pipe A\n");
                return false;
        }
@@ -241,9 +212,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                        return false;
                }
        }
-       /* If we don't have a panel mode, there is nothing we can do */
-       if (dev_priv->panel_fixed_mode == NULL)
-               return true;
 
        /*
         * We have timings from the BIOS for the panel, put them in
@@ -251,7 +219,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
         * with the panel scaling set up to source from the H/VDisplay
         * of the original mode.
         */
-       intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
+       intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode);
 
        if (HAS_PCH_SPLIT(dev)) {
                intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
@@ -260,8 +228,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        }
 
        /* Make sure pre-965s set dither correctly */
-       if (!IS_I965G(dev)) {
-               if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
+       if (INTEL_INFO(dev)->gen < 4) {
+               if (dev_priv->lvds_dither)
                        pfit_control |= PANEL_8TO6_DITHER_ENABLE;
        }
 
@@ -271,7 +239,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                goto out;
 
        /* 965+ wants fuzzy fitting */
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
                                 PFIT_FILTER_FUZZY);
 
@@ -297,7 +265,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
 
        case DRM_MODE_SCALE_ASPECT:
                /* Scale but preserve the aspect ratio */
-               if (IS_I965G(dev)) {
+               if (INTEL_INFO(dev)->gen >= 4) {
                        u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
                        u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
 
@@ -356,7 +324,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                 * Fortunately this is all done for us in hw.
                 */
                pfit_control |= PFIT_ENABLE;
-               if (IS_I965G(dev))
+               if (INTEL_INFO(dev)->gen >= 4)
                        pfit_control |= PFIT_SCALING_AUTO;
                else
                        pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
@@ -369,8 +337,12 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        }
 
 out:
-       intel_lvds->pfit_control = pfit_control;
-       intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
+       if (pfit_control != intel_lvds->pfit_control ||
+           pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
+               intel_lvds->pfit_control = pfit_control;
+               intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
+               intel_lvds->pfit_dirty = true;
+       }
        dev_priv->lvds_border_bits = border;
 
        /*
@@ -386,30 +358,60 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg;
-
-       if (HAS_PCH_SPLIT(dev))
-               reg = BLC_PWM_CPU_CTL;
-       else
-               reg = BLC_PWM_CTL;
-
-       dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
-       dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
-                                      BACKLIGHT_DUTY_CYCLE_MASK);
+       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
+
+       dev_priv->backlight_level = intel_panel_get_backlight(dev);
+
+       /* We try to do the minimum that is necessary in order to unlock
+        * the registers for mode setting.
+        *
+        * On Ironlake, this is quite simple as we just set the unlock key
+        * and ignore all subtleties. (This may cause some issues...)
+        *
+        * Prior to Ironlake, we must disable the pipe if we want to adjust
+        * the panel fitter. However at all other times we can just reset
+        * the registers regardless.
+        */
 
-       intel_lvds_set_power(dev, false);
+       if (HAS_PCH_SPLIT(dev)) {
+               I915_WRITE(PCH_PP_CONTROL,
+                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+       } else if (intel_lvds->pfit_dirty) {
+               I915_WRITE(PP_CONTROL,
+                          (I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS)
+                          & ~POWER_TARGET_ON);
+       } else {
+               I915_WRITE(PP_CONTROL,
+                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+       }
 }
 
-static void intel_lvds_commit( struct drm_encoder *encoder)
+static void intel_lvds_commit(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-       if (dev_priv->backlight_duty_cycle == 0)
-               dev_priv->backlight_duty_cycle =
-                       intel_lvds_get_max_backlight(dev);
+       if (dev_priv->backlight_level == 0)
+               dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
+
+       /* Undo any unlocking done in prepare to prevent accidental
+        * adjustment of the registers.
+        */
+       if (HAS_PCH_SPLIT(dev)) {
+               u32 val = I915_READ(PCH_PP_CONTROL);
+               if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
+                       I915_WRITE(PCH_PP_CONTROL, val & 0x3);
+       } else {
+               u32 val = I915_READ(PP_CONTROL);
+               if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
+                       I915_WRITE(PP_CONTROL, val & 0x3);
+       }
 
-       intel_lvds_set_power(dev, true);
+       /* Always do a full power on as we do not know what state
+        * we were left in.
+        */
+       intel_lvds_set_power(intel_lvds, true);
 }
 
 static void intel_lvds_mode_set(struct drm_encoder *encoder,
@@ -418,7 +420,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+       struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
        /*
         * The LVDS pin pair will already have been turned on in the
@@ -429,13 +431,23 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
        if (HAS_PCH_SPLIT(dev))
                return;
 
+       if (!intel_lvds->pfit_dirty)
+               return;
+
        /*
         * Enable automatic panel scaling so that non-native modes fill the
         * screen.  Should be enabled before the pipe is enabled, according to
         * register description and PRM.
         */
+       DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
+                     intel_lvds->pfit_control,
+                     intel_lvds->pfit_pgm_ratios);
+       if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+               DRM_ERROR("timed out waiting for panel to power off\n");
+
        I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
        I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
+       intel_lvds->pfit_dirty = false;
 }
 
 /**
@@ -465,38 +477,22 @@ intel_lvds_detect(struct drm_connector *connector, bool force)
  */
 static int intel_lvds_get_modes(struct drm_connector *connector)
 {
+       struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
        struct drm_device *dev = connector->dev;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret = 0;
-
-       if (dev_priv->lvds_edid_good) {
-               ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
+       struct drm_display_mode *mode;
 
-               if (ret)
-                       return ret;
+       if (intel_lvds->edid) {
+               drm_mode_connector_update_edid_property(connector,
+                                                       intel_lvds->edid);
+               return drm_add_edid_modes(connector, intel_lvds->edid);
        }
 
-       /* Didn't get an EDID, so
-        * Set wide sync ranges so we get all modes
-        * handed to valid_mode for checking
-        */
-       connector->display_info.min_vfreq = 0;
-       connector->display_info.max_vfreq = 200;
-       connector->display_info.min_hfreq = 0;
-       connector->display_info.max_hfreq = 200;
-
-       if (dev_priv->panel_fixed_mode != NULL) {
-               struct drm_display_mode *mode;
-
-               mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
-               drm_mode_probed_add(connector, mode);
-
-               return 1;
-       }
+       mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
+       if (mode == 0)
+               return 0;
 
-       return 0;
+       drm_mode_probed_add(connector, mode);
+       return 1;
 }
 
 static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id)
@@ -587,18 +583,17 @@ static int intel_lvds_set_property(struct drm_connector *connector,
                                   struct drm_property *property,
                                   uint64_t value)
 {
+       struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
        struct drm_device *dev = connector->dev;
 
-       if (property == dev->mode_config.scaling_mode_property &&
-                               connector->encoder) {
-               struct drm_crtc *crtc = connector->encoder->crtc;
-               struct drm_encoder *encoder = connector->encoder;
-               struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+       if (property == dev->mode_config.scaling_mode_property) {
+               struct drm_crtc *crtc = intel_lvds->base.base.crtc;
 
                if (value == DRM_MODE_SCALE_NONE) {
                        DRM_DEBUG_KMS("no scaling not supported\n");
-                       return 0;
+                       return -EINVAL;
                }
+
                if (intel_lvds->fitting_mode == value) {
                        /* the LVDS scaling property is not changed */
                        return 0;
@@ -628,7 +623,7 @@ static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
 static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
        .get_modes = intel_lvds_get_modes,
        .mode_valid = intel_lvds_mode_valid,
-       .best_encoder = intel_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static const struct drm_connector_funcs intel_lvds_connector_funcs = {
@@ -726,16 +721,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
  * Find the reduced downclock for LVDS in EDID.
  */
 static void intel_find_lvds_downclock(struct drm_device *dev,
-                               struct drm_connector *connector)
+                                     struct drm_display_mode *fixed_mode,
+                                     struct drm_connector *connector)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_display_mode *scan, *panel_fixed_mode;
+       struct drm_display_mode *scan;
        int temp_downclock;
 
-       panel_fixed_mode = dev_priv->panel_fixed_mode;
-       temp_downclock = panel_fixed_mode->clock;
-
-       mutex_lock(&dev->mode_config.mutex);
+       temp_downclock = fixed_mode->clock;
        list_for_each_entry(scan, &connector->probed_modes, head) {
                /*
                 * If one mode has the same resolution with the fixed_panel
@@ -744,14 +737,14 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
                 * case we can set the different FPx0/1 to dynamically select
                 * between low and high frequency.
                 */
-               if (scan->hdisplay == panel_fixed_mode->hdisplay &&
-                       scan->hsync_start == panel_fixed_mode->hsync_start &&
-                       scan->hsync_end == panel_fixed_mode->hsync_end &&
-                       scan->htotal == panel_fixed_mode->htotal &&
-                       scan->vdisplay == panel_fixed_mode->vdisplay &&
-                       scan->vsync_start == panel_fixed_mode->vsync_start &&
-                       scan->vsync_end == panel_fixed_mode->vsync_end &&
-                       scan->vtotal == panel_fixed_mode->vtotal) {
+               if (scan->hdisplay == fixed_mode->hdisplay &&
+                   scan->hsync_start == fixed_mode->hsync_start &&
+                   scan->hsync_end == fixed_mode->hsync_end &&
+                   scan->htotal == fixed_mode->htotal &&
+                   scan->vdisplay == fixed_mode->vdisplay &&
+                   scan->vsync_start == fixed_mode->vsync_start &&
+                   scan->vsync_end == fixed_mode->vsync_end &&
+                   scan->vtotal == fixed_mode->vtotal) {
                        if (scan->clock < temp_downclock) {
                                /*
                                 * The downclock is already found. But we
@@ -761,17 +754,14 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
                        }
                }
        }
-       mutex_unlock(&dev->mode_config.mutex);
-       if (temp_downclock < panel_fixed_mode->clock &&
-           i915_lvds_downclock) {
+       if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) {
                /* We found the downclock for LVDS. */
                dev_priv->lvds_downclock_avail = 1;
                dev_priv->lvds_downclock = temp_downclock;
                DRM_DEBUG_KMS("LVDS downclock is found in EDID. "
-                               "Normal clock %dKhz, downclock %dKhz\n",
-                               panel_fixed_mode->clock, temp_downclock);
+                             "Normal clock %dKhz, downclock %dKhz\n",
+                             fixed_mode->clock, temp_downclock);
        }
-       return;
 }
 
 /*
@@ -780,38 +770,67 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
  * If it is present, return 1.
  * If it is not present, return false.
  * If no child dev is parsed from VBT, it assumes that the LVDS is present.
- * Note: The addin_offset should also be checked for LVDS panel.
- * Only when it is non-zero, it is assumed that it is present.
  */
-static int lvds_is_present_in_vbt(struct drm_device *dev)
+static bool lvds_is_present_in_vbt(struct drm_device *dev,
+                                  u8 *i2c_pin)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct child_device_config *p_child;
-       int i, ret;
+       int i;
 
        if (!dev_priv->child_dev_num)
-               return 1;
+               return true;
 
-       ret = 0;
        for (i = 0; i < dev_priv->child_dev_num; i++) {
-               p_child = dev_priv->child_dev + i;
-               /*
-                * If the device type is not LFP, continue.
-                * If the device type is 0x22, it is also regarded as LFP.
+               struct child_device_config *child = dev_priv->child_dev + i;
+
+               /* If the device type is not LFP, continue.
+                * We have to check both the new identifiers as well as the
+                * old for compatibility with some BIOSes.
                 */
-               if (p_child->device_type != DEVICE_TYPE_INT_LFP &&
-                       p_child->device_type != DEVICE_TYPE_LFP)
+               if (child->device_type != DEVICE_TYPE_INT_LFP &&
+                   child->device_type != DEVICE_TYPE_LFP)
                        continue;
 
-               /* The addin_offset should be checked. Only when it is
-                * non-zero, it is regarded as present.
+               if (child->i2c_pin)
+                   *i2c_pin = child->i2c_pin;
+
+               /* However, we cannot trust the BIOS writers to populate
+                * the VBT correctly.  Since LVDS requires additional
+                * information from AIM blocks, a non-zero addin offset is
+                * a good indicator that the LVDS is actually present.
                 */
-               if (p_child->addin_offset) {
-                       ret = 1;
-                       break;
-               }
+               if (child->addin_offset)
+                       return true;
+
+               /* But even then some BIOS writers perform some black magic
+                * and instantiate the device without reference to any
+                * additional data.  Trust that if the VBT was written into
+                * the OpRegion then they have validated the LVDS's existence.
+                */
+               if (dev_priv->opregion.vbt)
+                       return true;
        }
-       return ret;
+
+       return false;
+}
+
+static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u8 buf = 0;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = 0xA0,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &buf,
+               },
+       };
+       struct i2c_adapter *i2c = &dev_priv->gmbus[pin].adapter;
+       /* XXX this only appears to work when using GMBUS */
+       if (intel_gmbus_is_forced_bit(i2c))
+               return true;
+       return i2c_transfer(i2c, msgs, 1) == 1;
 }
 
 /**
@@ -832,13 +851,15 @@ void intel_lvds_init(struct drm_device *dev)
        struct drm_display_mode *scan; /* *modes, *bios_mode; */
        struct drm_crtc *crtc;
        u32 lvds;
-       int pipe, gpio = GPIOC;
+       int pipe;
+       u8 pin;
 
        /* Skip init on machines we know falsely report LVDS */
        if (dmi_check_system(intel_no_lvds))
                return;
 
-       if (!lvds_is_present_in_vbt(dev)) {
+       pin = GMBUS_PORT_PANEL;
+       if (!lvds_is_present_in_vbt(dev, &pin)) {
                DRM_DEBUG_KMS("LVDS is not present in VBT\n");
                return;
        }
@@ -846,11 +867,15 @@ void intel_lvds_init(struct drm_device *dev)
        if (HAS_PCH_SPLIT(dev)) {
                if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
                        return;
-               if (dev_priv->edp_support) {
+               if (dev_priv->edp.support) {
                        DRM_DEBUG_KMS("disable LVDS for eDP support\n");
                        return;
                }
-               gpio = PCH_GPIOC;
+       }
+
+       if (!intel_lvds_ddc_probe(dev, pin)) {
+               DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n");
+               return;
        }
 
        intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL);
@@ -864,16 +889,20 @@ void intel_lvds_init(struct drm_device *dev)
                return;
        }
 
+       if (!HAS_PCH_SPLIT(dev)) {
+               intel_lvds->pfit_control = I915_READ(PFIT_CONTROL);
+       }
+
        intel_encoder = &intel_lvds->base;
-       encoder = &intel_encoder->enc;
+       encoder = &intel_encoder->base;
        connector = &intel_connector->base;
        drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
                           DRM_MODE_CONNECTOR_LVDS);
 
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_lvds_enc_funcs,
+       drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
                         DRM_MODE_ENCODER_LVDS);
 
-       drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
        intel_encoder->type = INTEL_OUTPUT_LVDS;
 
        intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
@@ -904,43 +933,41 @@ void intel_lvds_init(struct drm_device *dev)
         *    if closed, act like it's not there for now
         */
 
-       /* Set up the DDC bus. */
-       intel_encoder->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
-       if (!intel_encoder->ddc_bus) {
-               dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
-                          "failed.\n");
-               goto failed;
-       }
-
        /*
         * Attempt to get the fixed panel mode from DDC.  Assume that the
         * preferred mode is the right one.
         */
-       dev_priv->lvds_edid_good = true;
+       intel_lvds->edid = drm_get_edid(connector,
+                                       &dev_priv->gmbus[pin].adapter);
 
-       if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus))
-               dev_priv->lvds_edid_good = false;
+       if (!intel_lvds->edid) {
+               /* Didn't get an EDID, so
+                * Set wide sync ranges so we get all modes
+                * handed to valid_mode for checking
+                */
+               connector->display_info.min_vfreq = 0;
+               connector->display_info.max_vfreq = 200;
+               connector->display_info.min_hfreq = 0;
+               connector->display_info.max_hfreq = 200;
+       }
 
        list_for_each_entry(scan, &connector->probed_modes, head) {
-               mutex_lock(&dev->mode_config.mutex);
                if (scan->type & DRM_MODE_TYPE_PREFERRED) {
-                       dev_priv->panel_fixed_mode =
+                       intel_lvds->fixed_mode =
                                drm_mode_duplicate(dev, scan);
-                       mutex_unlock(&dev->mode_config.mutex);
-                       intel_find_lvds_downclock(dev, connector);
+                       intel_find_lvds_downclock(dev,
+                                                 intel_lvds->fixed_mode,
+                                                 connector);
                        goto out;
                }
-               mutex_unlock(&dev->mode_config.mutex);
        }
 
        /* Failed to get EDID, what about VBT? */
        if (dev_priv->lfp_lvds_vbt_mode) {
-               mutex_lock(&dev->mode_config.mutex);
-               dev_priv->panel_fixed_mode =
+               intel_lvds->fixed_mode =
                        drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
-               mutex_unlock(&dev->mode_config.mutex);
-               if (dev_priv->panel_fixed_mode) {
-                       dev_priv->panel_fixed_mode->type |=
+               if (intel_lvds->fixed_mode) {
+                       intel_lvds->fixed_mode->type |=
                                DRM_MODE_TYPE_PREFERRED;
                        goto out;
                }
@@ -958,19 +985,19 @@ void intel_lvds_init(struct drm_device *dev)
 
        lvds = I915_READ(LVDS);
        pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
-       crtc = intel_get_crtc_from_pipe(dev, pipe);
+       crtc = intel_get_crtc_for_pipe(dev, pipe);
 
        if (crtc && (lvds & LVDS_PORT_EN)) {
-               dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc);
-               if (dev_priv->panel_fixed_mode) {
-                       dev_priv->panel_fixed_mode->type |=
+               intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc);
+               if (intel_lvds->fixed_mode) {
+                       intel_lvds->fixed_mode->type |=
                                DRM_MODE_TYPE_PREFERRED;
                        goto out;
                }
        }
 
        /* If we still don't have a mode after all that, give up. */
-       if (!dev_priv->panel_fixed_mode)
+       if (!intel_lvds->fixed_mode)
                goto failed;
 
 out:
@@ -997,8 +1024,6 @@ out:
 
 failed:
        DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
-       if (intel_encoder->ddc_bus)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
        drm_connector_cleanup(connector);
        drm_encoder_cleanup(encoder);
        kfree(intel_lvds);
index 4b1fd3d9c73cb7b5b6d70c2576f4262e8b01fc02..f70b7cf32bffc43a4325233e0ba11ab5726ce64f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
- * Copyright (c) 2007 Intel Corporation
+ * Copyright (c) 2007, 2010 Intel Corporation
  *   Jesse Barnes <jesse.barnes@intel.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * intel_ddc_probe
  *
  */
-bool intel_ddc_probe(struct intel_encoder *intel_encoder)
+bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
 {
+       struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
        u8 out_buf[] = { 0x0, 0x0};
        u8 buf[2];
-       int ret;
        struct i2c_msg msgs[] = {
                {
                        .addr = 0x50,
@@ -54,13 +54,7 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder)
                }
        };
 
-       intel_i2c_quirk_set(intel_encoder->enc.dev, true);
-       ret = i2c_transfer(intel_encoder->ddc_bus, msgs, 2);
-       intel_i2c_quirk_set(intel_encoder->enc.dev, false);
-       if (ret == 2)
-               return true;
-
-       return false;
+       return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 2) == 2;
 }
 
 /**
@@ -76,9 +70,7 @@ int intel_ddc_get_modes(struct drm_connector *connector,
        struct edid *edid;
        int ret = 0;
 
-       intel_i2c_quirk_set(connector->dev, true);
        edid = drm_get_edid(connector, adapter);
-       intel_i2c_quirk_set(connector->dev, false);
        if (edid) {
                drm_mode_connector_update_edid_property(connector, edid);
                ret = drm_add_edid_modes(connector, edid);
similarity index 81%
rename from drivers/gpu/drm/i915/i915_opregion.c
rename to drivers/gpu/drm/i915/intel_opregion.c
index ea5d3fea4b61a2cd56dc4d2da4bad6fe3d94ea43..917c7dc3cd6b33ee151ad2e960743fe35016cec0 100644 (file)
 #include "drmP.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_drv.h"
 
 #define PCI_ASLE 0xe4
-#define PCI_LBPC 0xf4
 #define PCI_ASLS 0xfc
 
-#define OPREGION_SZ            (8*1024)
 #define OPREGION_HEADER_OFFSET 0
 #define OPREGION_ACPI_OFFSET   0x100
 #define OPREGION_SWSCI_OFFSET  0x200
 #define OPREGION_ASLE_OFFSET   0x300
-#define OPREGION_VBT_OFFSET    0x1000
+#define OPREGION_VBT_OFFSET    0x400
 
 #define OPREGION_SIGNATURE "IntelGraphicsMem"
 #define MBOX_ACPI      (1<<0)
@@ -143,40 +142,22 @@ struct opregion_asle {
 #define ACPI_DIGITAL_OUTPUT (3<<8)
 #define ACPI_LVDS_OUTPUT (4<<8)
 
+#ifdef CONFIG_ACPI
 static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct opregion_asle *asle = dev_priv->opregion.asle;
-       u32 blc_pwm_ctl, blc_pwm_ctl2;
-       u32 max_backlight, level, shift;
+       u32 max;
 
        if (!(bclp & ASLE_BCLP_VALID))
                return ASLE_BACKLIGHT_FAILED;
 
        bclp &= ASLE_BCLP_MSK;
-       if (bclp < 0 || bclp > 255)
+       if (bclp > 255)
                return ASLE_BACKLIGHT_FAILED;
 
-       blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
-       blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
-
-       if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE))
-               pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
-       else {
-               if (IS_PINEVIEW(dev)) {
-                       blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
-                       max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-                                       BACKLIGHT_MODULATION_FREQ_SHIFT;
-                       shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1;
-               } else {
-                       blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
-                       max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-                                       BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
-                       shift = BACKLIGHT_DUTY_CYCLE_SHIFT;
-               }
-               level = (bclp * max_backlight) / 255;
-               I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift));
-       }
+       max = intel_panel_get_max_backlight(dev);
+       intel_panel_set_backlight(dev, bclp * max / 255);
        asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
 
        return 0;
@@ -211,7 +192,7 @@ static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
        return 0;
 }
 
-void opregion_asle_intr(struct drm_device *dev)
+void intel_opregion_asle_intr(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct opregion_asle *asle = dev_priv->opregion.asle;
@@ -243,37 +224,8 @@ void opregion_asle_intr(struct drm_device *dev)
        asle->aslc = asle_stat;
 }
 
-static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct opregion_asle *asle = dev_priv->opregion.asle;
-       u32 cpu_pwm_ctl, pch_pwm_ctl2;
-       u32 max_backlight, level;
-
-       if (!(bclp & ASLE_BCLP_VALID))
-               return ASLE_BACKLIGHT_FAILED;
-
-       bclp &= ASLE_BCLP_MSK;
-       if (bclp < 0 || bclp > 255)
-               return ASLE_BACKLIGHT_FAILED;
-
-       cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL);
-       pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
-       /* get the max PWM frequency */
-       max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK;
-       /* calculate the expected PMW frequency */
-       level = (bclp * max_backlight) / 255;
-       /* reserve the high 16 bits */
-       cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK);
-       /* write the updated PWM frequency */
-       I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level);
-
-       asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
-
-       return 0;
-}
-
-void ironlake_opregion_gse_intr(struct drm_device *dev)
+/* Only present on Ironlake+ */
+void intel_opregion_gse_intr(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct opregion_asle *asle = dev_priv->opregion.asle;
@@ -296,7 +248,7 @@ void ironlake_opregion_gse_intr(struct drm_device *dev)
        }
 
        if (asle_req & ASLE_SET_BACKLIGHT)
-               asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp);
+               asle_stat |= asle_set_backlight(dev, asle->bclp);
 
        if (asle_req & ASLE_SET_PFIT) {
                DRM_DEBUG_DRIVER("Pfit is not supported\n");
@@ -315,7 +267,7 @@ void ironlake_opregion_gse_intr(struct drm_device *dev)
 #define ASLE_PFIT_EN   (1<<2)
 #define ASLE_PFMB_EN   (1<<3)
 
-void opregion_enable_asle(struct drm_device *dev)
+void intel_opregion_enable_asle(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct opregion_asle *asle = dev_priv->opregion.asle;
@@ -464,7 +416,58 @@ blind_set:
        goto end;
 }
 
-int intel_opregion_init(struct drm_device *dev, int resume)
+void intel_opregion_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+
+       if (!opregion->header)
+               return;
+
+       if (opregion->acpi) {
+               if (drm_core_check_feature(dev, DRIVER_MODESET))
+                       intel_didl_outputs(dev);
+
+               /* Notify BIOS we are ready to handle ACPI video ext notifs.
+                * Right now, all the events are handled by the ACPI video module.
+                * We don't actually need to do anything with them. */
+               opregion->acpi->csts = 0;
+               opregion->acpi->drdy = 1;
+
+               system_opregion = opregion;
+               register_acpi_notifier(&intel_opregion_notifier);
+       }
+
+       if (opregion->asle)
+               intel_opregion_enable_asle(dev);
+}
+
+void intel_opregion_fini(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_opregion *opregion = &dev_priv->opregion;
+
+       if (!opregion->header)
+               return;
+
+       if (opregion->acpi) {
+               opregion->acpi->drdy = 0;
+
+               system_opregion = NULL;
+               unregister_acpi_notifier(&intel_opregion_notifier);
+       }
+
+       /* just clear all opregion memory pointers now */
+       iounmap(opregion->header);
+       opregion->header = NULL;
+       opregion->acpi = NULL;
+       opregion->swsci = NULL;
+       opregion->asle = NULL;
+       opregion->vbt = NULL;
+}
+#endif
+
+int intel_opregion_setup(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_opregion *opregion = &dev_priv->opregion;
@@ -479,29 +482,23 @@ int intel_opregion_init(struct drm_device *dev, int resume)
                return -ENOTSUPP;
        }
 
-       base = ioremap(asls, OPREGION_SZ);
+       base = ioremap(asls, OPREGION_SIZE);
        if (!base)
                return -ENOMEM;
 
-       opregion->header = base;
-       if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) {
+       if (memcmp(base, OPREGION_SIGNATURE, 16)) {
                DRM_DEBUG_DRIVER("opregion signature mismatch\n");
                err = -EINVAL;
                goto err_out;
        }
+       opregion->header = base;
+       opregion->vbt = base + OPREGION_VBT_OFFSET;
 
        mboxes = opregion->header->mboxes;
        if (mboxes & MBOX_ACPI) {
                DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
                opregion->acpi = base + OPREGION_ACPI_OFFSET;
-               if (drm_core_check_feature(dev, DRIVER_MODESET))
-                       intel_didl_outputs(dev);
-       } else {
-               DRM_DEBUG_DRIVER("Public ACPI methods not supported\n");
-               err = -ENOTSUPP;
-               goto err_out;
        }
-       opregion->enabled = 1;
 
        if (mboxes & MBOX_SWSCI) {
                DRM_DEBUG_DRIVER("SWSCI supported\n");
@@ -510,53 +507,11 @@ int intel_opregion_init(struct drm_device *dev, int resume)
        if (mboxes & MBOX_ASLE) {
                DRM_DEBUG_DRIVER("ASLE supported\n");
                opregion->asle = base + OPREGION_ASLE_OFFSET;
-               opregion_enable_asle(dev);
        }
 
-       if (!resume)
-               acpi_video_register();
-
-
-       /* Notify BIOS we are ready to handle ACPI video ext notifs.
-        * Right now, all the events are handled by the ACPI video module.
-        * We don't actually need to do anything with them. */
-       opregion->acpi->csts = 0;
-       opregion->acpi->drdy = 1;
-
-       system_opregion = opregion;
-       register_acpi_notifier(&intel_opregion_notifier);
-
        return 0;
 
 err_out:
        iounmap(opregion->header);
-       opregion->header = NULL;
-       acpi_video_register();
        return err;
 }
-
-void intel_opregion_free(struct drm_device *dev, int suspend)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_opregion *opregion = &dev_priv->opregion;
-
-       if (!opregion->enabled)
-               return;
-
-       if (!suspend)
-               acpi_video_unregister();
-
-       opregion->acpi->drdy = 0;
-
-       system_opregion = NULL;
-       unregister_acpi_notifier(&intel_opregion_notifier);
-
-       /* just clear all opregion memory pointers now */
-       iounmap(opregion->header);
-       opregion->header = NULL;
-       opregion->acpi = NULL;
-       opregion->swsci = NULL;
-       opregion->asle = NULL;
-
-       opregion->enabled = 0;
-}
index 1d306a458be6463c8e1f6636d69ebf515d845889..375316a8420e84b1b49e2d0c38fd9ae57d1f0e78 100644 (file)
@@ -170,57 +170,143 @@ struct overlay_registers {
     u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
 };
 
-/* overlay flip addr flag */
-#define OFC_UPDATE             0x1
-
-#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev))
-#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev))
-
+struct intel_overlay {
+       struct drm_device *dev;
+       struct intel_crtc *crtc;
+       struct drm_i915_gem_object *vid_bo;
+       struct drm_i915_gem_object *old_vid_bo;
+       int active;
+       int pfit_active;
+       u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
+       u32 color_key;
+       u32 brightness, contrast, saturation;
+       u32 old_xscale, old_yscale;
+       /* register access */
+       u32 flip_addr;
+       struct drm_i915_gem_object *reg_bo;
+       /* flip handling */
+       uint32_t last_flip_req;
+       void (*flip_tail)(struct intel_overlay *);
+};
 
-static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
+static struct overlay_registers *
+intel_overlay_map_regs(struct intel_overlay *overlay)
 {
         drm_i915_private_t *dev_priv = overlay->dev->dev_private;
        struct overlay_registers *regs;
 
-       /* no recursive mappings */
-       BUG_ON(overlay->virt_addr);
+       if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+               regs = overlay->reg_bo->phys_obj->handle->vaddr;
+       else
+               regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping,
+                                        overlay->reg_bo->gtt_offset);
 
-       if (OVERLAY_NONPHYSICAL(overlay->dev)) {
-               regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
-                                               overlay->reg_bo->gtt_offset,
-                                               KM_USER0);
+       return regs;
+}
 
-               if (!regs) {
-                       DRM_ERROR("failed to map overlay regs in GTT\n");
-                       return NULL;
-               }
-       } else
-               regs = overlay->reg_bo->phys_obj->handle->vaddr;
+static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
+                                    struct overlay_registers *regs)
+{
+       if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+               io_mapping_unmap(regs);
+}
+
+static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
+                                        struct drm_i915_gem_request *request,
+                                        bool interruptible,
+                                        void (*tail)(struct intel_overlay *))
+{
+       struct drm_device *dev = overlay->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
+
+       BUG_ON(overlay->last_flip_req);
+       overlay->last_flip_req =
+               i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+       if (overlay->last_flip_req == 0)
+               return -ENOMEM;
 
-       return overlay->virt_addr = regs;
+       overlay->flip_tail = tail;
+       ret = i915_do_wait_request(dev,
+                                  overlay->last_flip_req, true,
+                                  &dev_priv->render_ring);
+       if (ret)
+               return ret;
+
+       overlay->last_flip_req = 0;
+       return 0;
 }
 
-static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
+/* Workaround for i830 bug where pipe a must be enable to change control regs */
+static int
+i830_activate_pipe_a(struct drm_device *dev)
 {
-       if (OVERLAY_NONPHYSICAL(overlay->dev))
-               io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0);
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct intel_crtc *crtc;
+       struct drm_crtc_helper_funcs *crtc_funcs;
+       struct drm_display_mode vesa_640x480 = {
+               DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+                        752, 800, 0, 480, 489, 492, 525, 0,
+                        DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
+       }, *mode;
+
+       crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);
+       if (crtc->dpms_mode == DRM_MODE_DPMS_ON)
+               return 0;
 
-       overlay->virt_addr = NULL;
+       /* most i8xx have pipe a forced on, so don't trust dpms mode */
+       if (I915_READ(PIPEACONF) & PIPECONF_ENABLE)
+               return 0;
 
-       return;
+       crtc_funcs = crtc->base.helper_private;
+       if (crtc_funcs->dpms == NULL)
+               return 0;
+
+       DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
+
+       mode = drm_mode_duplicate(dev, &vesa_640x480);
+       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       if(!drm_crtc_helper_set_mode(&crtc->base, mode,
+                                      crtc->base.x, crtc->base.y,
+                                      crtc->base.fb))
+               return 0;
+
+       crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);
+       return 1;
+}
+
+static void
+i830_deactivate_pipe_a(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
+       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
 }
 
 /* overlay needs to be disable in OCMD reg */
 static int intel_overlay_on(struct intel_overlay *overlay)
 {
        struct drm_device *dev = overlay->dev;
+       struct drm_i915_gem_request *request;
+       int pipe_a_quirk = 0;
        int ret;
-       drm_i915_private_t *dev_priv = dev->dev_private;
 
        BUG_ON(overlay->active);
-
        overlay->active = 1;
-       overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
+
+       if (IS_I830(dev)) {
+               pipe_a_quirk = i830_activate_pipe_a(dev);
+               if (pipe_a_quirk < 0)
+                       return pipe_a_quirk;
+       }
+
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (request == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        BEGIN_LP_RING(4);
        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
@@ -229,32 +315,30 @@ static int intel_overlay_on(struct intel_overlay *overlay)
        OUT_RING(MI_NOOP);
        ADVANCE_LP_RING();
 
-       overlay->last_flip_req =
-               i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-       if (overlay->last_flip_req == 0)
-               return -ENOMEM;
-
-       ret = i915_do_wait_request(dev,
-                       overlay->last_flip_req, 1, &dev_priv->render_ring);
-       if (ret != 0)
-               return ret;
+       ret = intel_overlay_do_wait_request(overlay, request, true, NULL);
+out:
+       if (pipe_a_quirk)
+               i830_deactivate_pipe_a(dev);
 
-       overlay->hw_wedged = 0;
-       overlay->last_flip_req = 0;
-       return 0;
+       return ret;
 }
 
 /* overlay needs to be enabled in OCMD reg */
-static void intel_overlay_continue(struct intel_overlay *overlay,
-                           bool load_polyphase_filter)
+static int intel_overlay_continue(struct intel_overlay *overlay,
+                                 bool load_polyphase_filter)
 {
        struct drm_device *dev = overlay->dev;
         drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_request *request;
        u32 flip_addr = overlay->flip_addr;
        u32 tmp;
 
        BUG_ON(!overlay->active);
 
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (request == NULL)
+               return -ENOMEM;
+
        if (load_polyphase_filter)
                flip_addr |= OFC_UPDATE;
 
@@ -269,220 +353,132 @@ static void intel_overlay_continue(struct intel_overlay *overlay,
         ADVANCE_LP_RING();
 
        overlay->last_flip_req =
-               i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
+               i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+       return 0;
 }
 
-static int intel_overlay_wait_flip(struct intel_overlay *overlay)
+static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
 {
-       struct drm_device *dev = overlay->dev;
-        drm_i915_private_t *dev_priv = dev->dev_private;
-       int ret;
-       u32 tmp;
-
-       if (overlay->last_flip_req != 0) {
-               ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                               1, &dev_priv->render_ring);
-               if (ret == 0) {
-                       overlay->last_flip_req = 0;
+       struct drm_gem_object *obj = &overlay->old_vid_bo->base;
 
-                       tmp = I915_READ(ISR);
-
-                       if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT))
-                               return 0;
-               }
-       }
+       i915_gem_object_unpin(obj);
+       drm_gem_object_unreference(obj);
 
-       /* synchronous slowpath */
-       overlay->hw_wedged = RELEASE_OLD_VID;
+       overlay->old_vid_bo = NULL;
+}
 
-       BEGIN_LP_RING(2);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
-        ADVANCE_LP_RING();
+static void intel_overlay_off_tail(struct intel_overlay *overlay)
+{
+       struct drm_gem_object *obj;
 
-       overlay->last_flip_req =
-               i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-       if (overlay->last_flip_req == 0)
-               return -ENOMEM;
+       /* never have the overlay hw on without showing a frame */
+       BUG_ON(!overlay->vid_bo);
+       obj = &overlay->vid_bo->base;
 
-       ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                       1, &dev_priv->render_ring);
-       if (ret != 0)
-               return ret;
+       i915_gem_object_unpin(obj);
+       drm_gem_object_unreference(obj);
+       overlay->vid_bo = NULL;
 
-       overlay->hw_wedged = 0;
-       overlay->last_flip_req = 0;
-       return 0;
+       overlay->crtc->overlay = NULL;
+       overlay->crtc = NULL;
+       overlay->active = 0;
 }
 
 /* overlay needs to be disabled in OCMD reg */
-static int intel_overlay_off(struct intel_overlay *overlay)
+static int intel_overlay_off(struct intel_overlay *overlay,
+                            bool interruptible)
 {
-       u32 flip_addr = overlay->flip_addr;
        struct drm_device *dev = overlay->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       int ret;
+       u32 flip_addr = overlay->flip_addr;
+       struct drm_i915_gem_request *request;
 
        BUG_ON(!overlay->active);
 
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (request == NULL)
+               return -ENOMEM;
+
        /* According to intel docs the overlay hw may hang (when switching
         * off) without loading the filter coeffs. It is however unclear whether
         * this applies to the disabling of the overlay or to the switching off
         * of the hw. Do it in both cases */
        flip_addr |= OFC_UPDATE;
 
+       BEGIN_LP_RING(6);
        /* wait for overlay to go idle */
-       overlay->hw_wedged = SWITCH_OFF_STAGE_1;
-
-       BEGIN_LP_RING(4);
        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
        OUT_RING(flip_addr);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
-        ADVANCE_LP_RING();
-
-       overlay->last_flip_req =
-               i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-       if (overlay->last_flip_req == 0)
-               return -ENOMEM;
-
-       ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                       1, &dev_priv->render_ring);
-       if (ret != 0)
-               return ret;
-
+       OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
        /* turn overlay off */
-       overlay->hw_wedged = SWITCH_OFF_STAGE_2;
-
-       BEGIN_LP_RING(4);
-        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
+       OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
        OUT_RING(flip_addr);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
+       OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
        ADVANCE_LP_RING();
 
-       overlay->last_flip_req =
-               i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-       if (overlay->last_flip_req == 0)
-               return -ENOMEM;
-
-       ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                       1, &dev_priv->render_ring);
-       if (ret != 0)
-               return ret;
-
-       overlay->hw_wedged = 0;
-       overlay->last_flip_req = 0;
-       return ret;
-}
-
-static void intel_overlay_off_tail(struct intel_overlay *overlay)
-{
-       struct drm_gem_object *obj;
-
-       /* never have the overlay hw on without showing a frame */
-       BUG_ON(!overlay->vid_bo);
-       obj = &overlay->vid_bo->base;
-
-       i915_gem_object_unpin(obj);
-       drm_gem_object_unreference(obj);
-       overlay->vid_bo = NULL;
-
-       overlay->crtc->overlay = NULL;
-       overlay->crtc = NULL;
-       overlay->active = 0;
+       return intel_overlay_do_wait_request(overlay, request, interruptible,
+                                            intel_overlay_off_tail);
 }
 
 /* recover from an interruption due to a signal
  * We have to be careful not to repeat work forever an make forward progess. */
-int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
-                                        int interruptible)
+static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
+                                               bool interruptible)
 {
        struct drm_device *dev = overlay->dev;
-       struct drm_gem_object *obj;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       u32 flip_addr;
        int ret;
 
-       if (overlay->hw_wedged == HW_WEDGED)
-               return -EIO;
-
-       if (overlay->last_flip_req == 0) {
-               overlay->last_flip_req =
-                       i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-               if (overlay->last_flip_req == 0)
-                       return -ENOMEM;
-       }
+       if (overlay->last_flip_req == 0)
+               return 0;
 
        ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                       interruptible, &dev_priv->render_ring);
-       if (ret != 0)
+                                  interruptible, &dev_priv->render_ring);
+       if (ret)
                return ret;
 
-       switch (overlay->hw_wedged) {
-               case RELEASE_OLD_VID:
-                       obj = &overlay->old_vid_bo->base;
-                       i915_gem_object_unpin(obj);
-                       drm_gem_object_unreference(obj);
-                       overlay->old_vid_bo = NULL;
-                       break;
-               case SWITCH_OFF_STAGE_1:
-                       flip_addr = overlay->flip_addr;
-                       flip_addr |= OFC_UPDATE;
-
-                       overlay->hw_wedged = SWITCH_OFF_STAGE_2;
-
-                       BEGIN_LP_RING(4);
-                       OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
-                       OUT_RING(flip_addr);
-                       OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-                       OUT_RING(MI_NOOP);
-                       ADVANCE_LP_RING();
-
-                       overlay->last_flip_req = i915_add_request(dev, NULL,
-                                       0, &dev_priv->render_ring);
-                       if (overlay->last_flip_req == 0)
-                               return -ENOMEM;
-
-                       ret = i915_do_wait_request(dev, overlay->last_flip_req,
-                                       interruptible, &dev_priv->render_ring);
-                       if (ret != 0)
-                               return ret;
-
-               case SWITCH_OFF_STAGE_2:
-                       intel_overlay_off_tail(overlay);
-                       break;
-               default:
-                       BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP);
-       }
+       if (overlay->flip_tail)
+               overlay->flip_tail(overlay);
 
-       overlay->hw_wedged = 0;
        overlay->last_flip_req = 0;
        return 0;
 }
 
 /* Wait for pending overlay flip and release old frame.
  * Needs to be called before the overlay register are changed
- * via intel_overlay_(un)map_regs_atomic */
+ * via intel_overlay_(un)map_regs
+ */
 static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
 {
+       struct drm_device *dev = overlay->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
-       struct drm_gem_object *obj;
 
-       /* only wait if there is actually an old frame to release to
-        * guarantee forward progress */
+       /* Only wait if there is actually an old frame to release to
+        * guarantee forward progress.
+        */
        if (!overlay->old_vid_bo)
                return 0;
 
-       ret = intel_overlay_wait_flip(overlay);
-       if (ret != 0)
-               return ret;
+       if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
+               struct drm_i915_gem_request *request;
 
-       obj = &overlay->old_vid_bo->base;
-       i915_gem_object_unpin(obj);
-       drm_gem_object_unreference(obj);
-       overlay->old_vid_bo = NULL;
+               /* synchronous slowpath */
+               request = kzalloc(sizeof(*request), GFP_KERNEL);
+               if (request == NULL)
+                       return -ENOMEM;
+
+               BEGIN_LP_RING(2);
+               OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+               OUT_RING(MI_NOOP);
+               ADVANCE_LP_RING();
 
+               ret = intel_overlay_do_wait_request(overlay, request, true,
+                                                   intel_overlay_release_old_vid_tail);
+               if (ret)
+                       return ret;
+       }
+
+       intel_overlay_release_old_vid_tail(overlay);
        return 0;
 }
 
@@ -506,65 +502,65 @@ struct put_image_params {
 static int packed_depth_bytes(u32 format)
 {
        switch (format & I915_OVERLAY_DEPTH_MASK) {
-               case I915_OVERLAY_YUV422:
-                       return 4;
-               case I915_OVERLAY_YUV411:
-                       /* return 6; not implemented */
-               default:
-                       return -EINVAL;
+       case I915_OVERLAY_YUV422:
+               return 4;
+       case I915_OVERLAY_YUV411:
+               /* return 6; not implemented */
+       default:
+               return -EINVAL;
        }
 }
 
 static int packed_width_bytes(u32 format, short width)
 {
        switch (format & I915_OVERLAY_DEPTH_MASK) {
-               case I915_OVERLAY_YUV422:
-                       return width << 1;
-               default:
-                       return -EINVAL;
+       case I915_OVERLAY_YUV422:
+               return width << 1;
+       default:
+               return -EINVAL;
        }
 }
 
 static int uv_hsubsampling(u32 format)
 {
        switch (format & I915_OVERLAY_DEPTH_MASK) {
-               case I915_OVERLAY_YUV422:
-               case I915_OVERLAY_YUV420:
-                       return 2;
-               case I915_OVERLAY_YUV411:
-               case I915_OVERLAY_YUV410:
-                       return 4;
-               default:
-                       return -EINVAL;
+       case I915_OVERLAY_YUV422:
+       case I915_OVERLAY_YUV420:
+               return 2;
+       case I915_OVERLAY_YUV411:
+       case I915_OVERLAY_YUV410:
+               return 4;
+       default:
+               return -EINVAL;
        }
 }
 
 static int uv_vsubsampling(u32 format)
 {
        switch (format & I915_OVERLAY_DEPTH_MASK) {
-               case I915_OVERLAY_YUV420:
-               case I915_OVERLAY_YUV410:
-                       return 2;
-               case I915_OVERLAY_YUV422:
-               case I915_OVERLAY_YUV411:
-                       return 1;
-               default:
-                       return -EINVAL;
+       case I915_OVERLAY_YUV420:
+       case I915_OVERLAY_YUV410:
+               return 2;
+       case I915_OVERLAY_YUV422:
+       case I915_OVERLAY_YUV411:
+               return 1;
+       default:
+               return -EINVAL;
        }
 }
 
 static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
 {
        u32 mask, shift, ret;
-       if (IS_I9XX(dev)) {
-               mask = 0x3f;
-               shift = 6;
-       } else {
+       if (IS_GEN2(dev)) {
                mask = 0x1f;
                shift = 5;
+       } else {
+               mask = 0x3f;
+               shift = 6;
        }
        ret = ((offset + width + mask) >> shift) - (offset >> shift);
-       if (IS_I9XX(dev))
+       if (!IS_GEN2(dev))
                ret <<= 1;
        ret -=1;
        return ret << 2;
@@ -587,7 +583,9 @@ static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
        0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
        0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
        0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
-       0xb000, 0x3000, 0x0800, 0x3000, 0xb000};
+       0xb000, 0x3000, 0x0800, 0x3000, 0xb000
+};
+
 static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
        0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
        0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
@@ -597,7 +595,8 @@ static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
        0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
        0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
        0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
-       0x3000, 0x0800, 0x3000};
+       0x3000, 0x0800, 0x3000
+};
 
 static void update_polyphase_filter(struct overlay_registers *regs)
 {
@@ -630,29 +629,31 @@ static bool update_scaling_factors(struct intel_overlay *overlay,
                yscale = 1 << FP_SHIFT;
 
        /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
-               xscale_UV = xscale/uv_hscale;
-               yscale_UV = yscale/uv_vscale;
-               /* make the Y scale to UV scale ratio an exact multiply */
-               xscale = xscale_UV * uv_hscale;
-               yscale = yscale_UV * uv_vscale;
+       xscale_UV = xscale/uv_hscale;
+       yscale_UV = yscale/uv_vscale;
+       /* make the Y scale to UV scale ratio an exact multiply */
+       xscale = xscale_UV * uv_hscale;
+       yscale = yscale_UV * uv_vscale;
        /*} else {
-               xscale_UV = 0;
-               yscale_UV = 0;
-       }*/
+         xscale_UV = 0;
+         yscale_UV = 0;
+         }*/
 
        if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
                scale_changed = true;
        overlay->old_xscale = xscale;
        overlay->old_yscale = yscale;
 
-       regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20)
-               | ((xscale >> FP_SHIFT) << 16)
-               | ((xscale & FRACT_MASK) << 3);
-       regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20)
-               | ((xscale_UV >> FP_SHIFT) << 16)
-               | ((xscale_UV & FRACT_MASK) << 3);
-       regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16)
-               | ((yscale_UV >> FP_SHIFT) << 0);
+       regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |
+                          ((xscale >> FP_SHIFT)  << 16) |
+                          ((xscale & FRACT_MASK) << 3));
+
+       regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |
+                        ((xscale_UV >> FP_SHIFT)  << 16) |
+                        ((xscale_UV & FRACT_MASK) << 3));
+
+       regs->UVSCALEV = ((((yscale    >> FP_SHIFT) << 16) |
+                          ((yscale_UV >> FP_SHIFT) << 0)));
 
        if (scale_changed)
                update_polyphase_filter(regs);
@@ -664,22 +665,28 @@ static void update_colorkey(struct intel_overlay *overlay,
                            struct overlay_registers *regs)
 {
        u32 key = overlay->color_key;
+
        switch (overlay->crtc->base.fb->bits_per_pixel) {
-               case 8:
-                       regs->DCLRKV = 0;
-                       regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
-               case 16:
-                       if (overlay->crtc->base.fb->depth == 15) {
-                               regs->DCLRKV = RGB15_TO_COLORKEY(key);
-                               regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
-                       } else {
-                               regs->DCLRKV = RGB16_TO_COLORKEY(key);
-                               regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
-                       }
-               case 24:
-               case 32:
-                       regs->DCLRKV = key;
-                       regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+       case 8:
+               regs->DCLRKV = 0;
+               regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
+               break;
+
+       case 16:
+               if (overlay->crtc->base.fb->depth == 15) {
+                       regs->DCLRKV = RGB15_TO_COLORKEY(key);
+                       regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
+               } else {
+                       regs->DCLRKV = RGB16_TO_COLORKEY(key);
+                       regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
+               }
+               break;
+
+       case 24:
+       case 32:
+               regs->DCLRKV = key;
+               regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+               break;
        }
 }
 
@@ -689,48 +696,48 @@ static u32 overlay_cmd_reg(struct put_image_params *params)
 
        if (params->format & I915_OVERLAY_YUV_PLANAR) {
                switch (params->format & I915_OVERLAY_DEPTH_MASK) {
-                       case I915_OVERLAY_YUV422:
-                               cmd |= OCMD_YUV_422_PLANAR;
-                               break;
-                       case I915_OVERLAY_YUV420:
-                               cmd |= OCMD_YUV_420_PLANAR;
-                               break;
-                       case I915_OVERLAY_YUV411:
-                       case I915_OVERLAY_YUV410:
-                               cmd |= OCMD_YUV_410_PLANAR;
-                               break;
+               case I915_OVERLAY_YUV422:
+                       cmd |= OCMD_YUV_422_PLANAR;
+                       break;
+               case I915_OVERLAY_YUV420:
+                       cmd |= OCMD_YUV_420_PLANAR;
+                       break;
+               case I915_OVERLAY_YUV411:
+               case I915_OVERLAY_YUV410:
+                       cmd |= OCMD_YUV_410_PLANAR;
+                       break;
                }
        } else { /* YUV packed */
                switch (params->format & I915_OVERLAY_DEPTH_MASK) {
-                       case I915_OVERLAY_YUV422:
-                               cmd |= OCMD_YUV_422_PACKED;
-                               break;
-                       case I915_OVERLAY_YUV411:
-                               cmd |= OCMD_YUV_411_PACKED;
-                               break;
+               case I915_OVERLAY_YUV422:
+                       cmd |= OCMD_YUV_422_PACKED;
+                       break;
+               case I915_OVERLAY_YUV411:
+                       cmd |= OCMD_YUV_411_PACKED;
+                       break;
                }
 
                switch (params->format & I915_OVERLAY_SWAP_MASK) {
-                       case I915_OVERLAY_NO_SWAP:
-                               break;
-                       case I915_OVERLAY_UV_SWAP:
-                               cmd |= OCMD_UV_SWAP;
-                               break;
-                       case I915_OVERLAY_Y_SWAP:
-                               cmd |= OCMD_Y_SWAP;
-                               break;
-                       case I915_OVERLAY_Y_AND_UV_SWAP:
-                               cmd |= OCMD_Y_AND_UV_SWAP;
-                               break;
+               case I915_OVERLAY_NO_SWAP:
+                       break;
+               case I915_OVERLAY_UV_SWAP:
+                       cmd |= OCMD_UV_SWAP;
+                       break;
+               case I915_OVERLAY_Y_SWAP:
+                       cmd |= OCMD_Y_SWAP;
+                       break;
+               case I915_OVERLAY_Y_AND_UV_SWAP:
+                       cmd |= OCMD_Y_AND_UV_SWAP;
+                       break;
                }
        }
 
        return cmd;
 }
 
-int intel_overlay_do_put_image(struct intel_overlay *overlay,
-                              struct drm_gem_object *new_bo,
-                              struct put_image_params *params)
+static int intel_overlay_do_put_image(struct intel_overlay *overlay,
+                                     struct drm_gem_object *new_bo,
+                                     struct put_image_params *params)
 {
        int ret, tmp_width;
        struct overlay_registers *regs;
@@ -755,24 +762,24 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
                goto out_unpin;
 
        if (!overlay->active) {
-               regs = intel_overlay_map_regs_atomic(overlay);
+               regs = intel_overlay_map_regs(overlay);
                if (!regs) {
                        ret = -ENOMEM;
                        goto out_unpin;
                }
                regs->OCONFIG = OCONF_CC_OUT_8BIT;
-               if (IS_I965GM(overlay->dev))
+               if (IS_GEN4(overlay->dev))
                        regs->OCONFIG |= OCONF_CSC_MODE_BT709;
                regs->OCONFIG |= overlay->crtc->pipe == 0 ?
                        OCONF_PIPE_A : OCONF_PIPE_B;
-               intel_overlay_unmap_regs_atomic(overlay);
+               intel_overlay_unmap_regs(overlay, regs);
 
                ret = intel_overlay_on(overlay);
                if (ret != 0)
                        goto out_unpin;
        }
 
-       regs = intel_overlay_map_regs_atomic(overlay);
+       regs = intel_overlay_map_regs(overlay);
        if (!regs) {
                ret = -ENOMEM;
                goto out_unpin;
@@ -788,7 +795,7 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
 
        regs->SWIDTH = params->src_w;
        regs->SWIDTHSW = calc_swidthsw(overlay->dev,
-                       params->offset_Y, tmp_width);
+                                      params->offset_Y, tmp_width);
        regs->SHEIGHT = params->src_h;
        regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
        regs->OSTRIDE = params->stride_Y;
@@ -799,9 +806,9 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
                u32 tmp_U, tmp_V;
                regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
                tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
-                               params->src_w/uv_hscale);
+                                     params->src_w/uv_hscale);
                tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
-                               params->src_w/uv_hscale);
+                                     params->src_w/uv_hscale);
                regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
                regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
                regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
@@ -815,9 +822,11 @@ int intel_overlay_do_put_image(struct intel_overlay *overlay,
 
        regs->OCMD = overlay_cmd_reg(params);
 
-       intel_overlay_unmap_regs_atomic(overlay);
+       intel_overlay_unmap_regs(overlay, regs);
 
-       intel_overlay_continue(overlay, scale_changed);
+       ret = intel_overlay_continue(overlay, scale_changed);
+       if (ret)
+               goto out_unpin;
 
        overlay->old_vid_bo = overlay->vid_bo;
        overlay->vid_bo = to_intel_bo(new_bo);
@@ -829,20 +838,19 @@ out_unpin:
        return ret;
 }
 
-int intel_overlay_switch_off(struct intel_overlay *overlay)
+int intel_overlay_switch_off(struct intel_overlay *overlay,
+                            bool interruptible)
 {
-       int ret;
        struct overlay_registers *regs;
        struct drm_device *dev = overlay->dev;
+       int ret;
 
        BUG_ON(!mutex_is_locked(&dev->struct_mutex));
        BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
 
-       if (overlay->hw_wedged) {
-               ret = intel_overlay_recover_from_interrupt(overlay, 1);
-               if (ret != 0)
-                       return ret;
-       }
+       ret = intel_overlay_recover_from_interrupt(overlay, interruptible);
+       if (ret != 0)
+               return ret;
 
        if (!overlay->active)
                return 0;
@@ -851,33 +859,29 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
        if (ret != 0)
                return ret;
 
-       regs = intel_overlay_map_regs_atomic(overlay);
+       regs = intel_overlay_map_regs(overlay);
        regs->OCMD = 0;
-       intel_overlay_unmap_regs_atomic(overlay);
+       intel_overlay_unmap_regs(overlay, regs);
 
-       ret = intel_overlay_off(overlay);
+       ret = intel_overlay_off(overlay, interruptible);
        if (ret != 0)
                return ret;
 
        intel_overlay_off_tail(overlay);
-
        return 0;
 }
 
 static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
                                          struct intel_crtc *crtc)
 {
-        drm_i915_private_t *dev_priv = overlay->dev->dev_private;
-       u32 pipeconf;
-       int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF;
+       drm_i915_private_t *dev_priv = overlay->dev->dev_private;
 
-       if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON)
+       if (!crtc->active)
                return -EINVAL;
 
-       pipeconf = I915_READ(pipeconf_reg);
-
        /* can't use the overlay with double wide pipe */
-       if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE)
+       if (INTEL_INFO(overlay->dev)->gen < 4 &&
+           (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE)
                return -EINVAL;
 
        return 0;
@@ -886,20 +890,22 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
 static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
 {
        struct drm_device *dev = overlay->dev;
-        drm_i915_private_t *dev_priv = dev->dev_private;
-       u32 ratio;
+       drm_i915_private_t *dev_priv = dev->dev_private;
        u32 pfit_control = I915_READ(PFIT_CONTROL);
+       u32 ratio;
 
        /* XXX: This is not the same logic as in the xorg driver, but more in
-        * line with the intel documentation for the i965 */
-       if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) {
-               ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT;
-       } else { /* on i965 use the PGM reg to read out the autoscaler values */
-               ratio = I915_READ(PFIT_PGM_RATIOS);
-               if (IS_I965G(dev))
-                       ratio >>= PFIT_VERT_SCALE_SHIFT_965;
+        * line with the intel documentation for the i965
+        */
+       if (INTEL_INFO(dev)->gen >= 4) {
+               /* on i965 use the PGM reg to read out the autoscaler values */
+               ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
+       } else {
+               if (pfit_control & VERT_AUTO_SCALE)
+                       ratio = I915_READ(PFIT_AUTO_RATIOS);
                else
-                       ratio >>= PFIT_VERT_SCALE_SHIFT;
+                       ratio = I915_READ(PFIT_PGM_RATIOS);
+               ratio >>= PFIT_VERT_SCALE_SHIFT;
        }
 
        overlay->pfit_vscale_ratio = ratio;
@@ -910,12 +916,10 @@ static int check_overlay_dst(struct intel_overlay *overlay,
 {
        struct drm_display_mode *mode = &overlay->crtc->base.mode;
 
-       if ((rec->dst_x < mode->crtc_hdisplay)
-           && (rec->dst_x + rec->dst_width
-                   <= mode->crtc_hdisplay)
-           && (rec->dst_y < mode->crtc_vdisplay)
-           && (rec->dst_y + rec->dst_height
-                   <= mode->crtc_vdisplay))
+       if (rec->dst_x < mode->crtc_hdisplay &&
+           rec->dst_x + rec->dst_width <= mode->crtc_hdisplay &&
+           rec->dst_y < mode->crtc_vdisplay &&
+           rec->dst_y + rec->dst_height <= mode->crtc_vdisplay)
                return 0;
        else
                return -EINVAL;
@@ -940,53 +944,57 @@ static int check_overlay_src(struct drm_device *dev,
                             struct drm_intel_overlay_put_image *rec,
                             struct drm_gem_object *new_bo)
 {
-       u32 stride_mask;
-       int depth;
        int uv_hscale = uv_hsubsampling(rec->flags);
        int uv_vscale = uv_vsubsampling(rec->flags);
-       size_t tmp;
+       u32 stride_mask, depth, tmp;
 
        /* check src dimensions */
        if (IS_845G(dev) || IS_I830(dev)) {
-               if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY
-                   || rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
+               if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
+                   rec->src_width  > IMAGE_MAX_WIDTH_LEGACY)
                        return -EINVAL;
        } else {
-               if (rec->src_height > IMAGE_MAX_HEIGHT
-                   || rec->src_width > IMAGE_MAX_WIDTH)
+               if (rec->src_height > IMAGE_MAX_HEIGHT ||
+                   rec->src_width  > IMAGE_MAX_WIDTH)
                        return -EINVAL;
        }
+
        /* better safe than sorry, use 4 as the maximal subsampling ratio */
-       if (rec->src_height < N_VERT_Y_TAPS*4
-           || rec->src_width < N_HORIZ_Y_TAPS*4)
+       if (rec->src_height < N_VERT_Y_TAPS*4 ||
+           rec->src_width  < N_HORIZ_Y_TAPS*4)
                return -EINVAL;
 
        /* check alignment constraints */
        switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
-               case I915_OVERLAY_RGB:
-                       /* not implemented */
+       case I915_OVERLAY_RGB:
+               /* not implemented */
+               return -EINVAL;
+
+       case I915_OVERLAY_YUV_PACKED:
+               if (uv_vscale != 1)
                        return -EINVAL;
-               case I915_OVERLAY_YUV_PACKED:
-                       depth = packed_depth_bytes(rec->flags);
-                       if (uv_vscale != 1)
-                               return -EINVAL;
-                       if (depth < 0)
-                               return depth;
-                       /* ignore UV planes */
-                       rec->stride_UV = 0;
-                       rec->offset_U = 0;
-                       rec->offset_V = 0;
-                       /* check pixel alignment */
-                       if (rec->offset_Y % depth)
-                               return -EINVAL;
-                       break;
-               case I915_OVERLAY_YUV_PLANAR:
-                       if (uv_vscale < 0 || uv_hscale < 0)
-                               return -EINVAL;
-                       /* no offset restrictions for planar formats */
-                       break;
-               default:
+
+               depth = packed_depth_bytes(rec->flags);
+               if (depth < 0)
+                       return depth;
+
+               /* ignore UV planes */
+               rec->stride_UV = 0;
+               rec->offset_U = 0;
+               rec->offset_V = 0;
+               /* check pixel alignment */
+               if (rec->offset_Y % depth)
+                       return -EINVAL;
+               break;
+
+       case I915_OVERLAY_YUV_PLANAR:
+               if (uv_vscale < 0 || uv_hscale < 0)
                        return -EINVAL;
+               /* no offset restrictions for planar formats */
+               break;
+
+       default:
+               return -EINVAL;
        }
 
        if (rec->src_width % uv_hscale)
@@ -1000,47 +1008,74 @@ static int check_overlay_src(struct drm_device *dev,
 
        if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
                return -EINVAL;
-       if (IS_I965G(dev) && rec->stride_Y < 512)
+       if (IS_GEN4(dev) && rec->stride_Y < 512)
                return -EINVAL;
 
        tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
-               4 : 8;
-       if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024)
+               4096 : 8192;
+       if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
                return -EINVAL;
 
        /* check buffer dimensions */
        switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
-               case I915_OVERLAY_RGB:
-               case I915_OVERLAY_YUV_PACKED:
-                       /* always 4 Y values per depth pixels */
-                       if (packed_width_bytes(rec->flags, rec->src_width)
-                                       > rec->stride_Y)
-                               return -EINVAL;
-
-                       tmp = rec->stride_Y*rec->src_height;
-                       if (rec->offset_Y + tmp > new_bo->size)
-                               return -EINVAL;
-                       break;
-               case I915_OVERLAY_YUV_PLANAR:
-                       if (rec->src_width > rec->stride_Y)
-                               return -EINVAL;
-                       if (rec->src_width/uv_hscale > rec->stride_UV)
-                               return -EINVAL;
-
-                       tmp = rec->stride_Y*rec->src_height;
-                       if (rec->offset_Y + tmp > new_bo->size)
-                               return -EINVAL;
-                       tmp = rec->stride_UV*rec->src_height;
-                       tmp /= uv_vscale;
-                       if (rec->offset_U + tmp > new_bo->size
-                           || rec->offset_V + tmp > new_bo->size)
-                               return -EINVAL;
-                       break;
+       case I915_OVERLAY_RGB:
+       case I915_OVERLAY_YUV_PACKED:
+               /* always 4 Y values per depth pixels */
+               if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
+                       return -EINVAL;
+
+               tmp = rec->stride_Y*rec->src_height;
+               if (rec->offset_Y + tmp > new_bo->size)
+                       return -EINVAL;
+               break;
+
+       case I915_OVERLAY_YUV_PLANAR:
+               if (rec->src_width > rec->stride_Y)
+                       return -EINVAL;
+               if (rec->src_width/uv_hscale > rec->stride_UV)
+                       return -EINVAL;
+
+               tmp = rec->stride_Y * rec->src_height;
+               if (rec->offset_Y + tmp > new_bo->size)
+                       return -EINVAL;
+
+               tmp = rec->stride_UV * (rec->src_height / uv_vscale);
+               if (rec->offset_U + tmp > new_bo->size ||
+                   rec->offset_V + tmp > new_bo->size)
+                       return -EINVAL;
+               break;
        }
 
        return 0;
 }
 
+/**
+ * Return the pipe currently connected to the panel fitter,
+ * or -1 if the panel fitter is not present or not in use
+ */
+static int intel_panel_fitter_pipe(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32  pfit_control;
+
+       /* i830 doesn't have a panel fitter */
+       if (IS_I830(dev))
+               return -1;
+
+       pfit_control = I915_READ(PFIT_CONTROL);
+
+       /* See if the panel fitter is in use */
+       if ((pfit_control & PFIT_ENABLE) == 0)
+               return -1;
+
+       /* 965 can place panel fitter on either pipe */
+       if (IS_GEN4(dev))
+               return (pfit_control >> 29) & 0x3;
+
+       /* older chips can only use pipe 1 */
+       return 1;
+}
+
 int intel_overlay_put_image(struct drm_device *dev, void *data,
                             struct drm_file *file_priv)
 {
@@ -1068,7 +1103,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
                mutex_lock(&dev->mode_config.mutex);
                mutex_lock(&dev->struct_mutex);
 
-               ret = intel_overlay_switch_off(overlay);
+               ret = intel_overlay_switch_off(overlay, true);
 
                mutex_unlock(&dev->struct_mutex);
                mutex_unlock(&dev->mode_config.mutex);
@@ -1081,7 +1116,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
                return -ENOMEM;
 
        drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
-                        DRM_MODE_OBJECT_CRTC);
+                                          DRM_MODE_OBJECT_CRTC);
        if (!drmmode_obj) {
                ret = -ENOENT;
                goto out_free;
@@ -1089,7 +1124,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
        crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
 
        new_bo = drm_gem_object_lookup(dev, file_priv,
-                       put_image_rec->bo_handle);
+                                      put_image_rec->bo_handle);
        if (!new_bo) {
                ret = -ENOENT;
                goto out_free;
@@ -1098,15 +1133,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
        mutex_lock(&dev->mode_config.mutex);
        mutex_lock(&dev->struct_mutex);
 
-       if (overlay->hw_wedged) {
-               ret = intel_overlay_recover_from_interrupt(overlay, 1);
-               if (ret != 0)
-                       goto out_unlock;
-       }
+       ret = intel_overlay_recover_from_interrupt(overlay, true);
+       if (ret != 0)
+               goto out_unlock;
 
        if (overlay->crtc != crtc) {
                struct drm_display_mode *mode = &crtc->base.mode;
-               ret = intel_overlay_switch_off(overlay);
+               ret = intel_overlay_switch_off(overlay, true);
                if (ret != 0)
                        goto out_unlock;
 
@@ -1117,9 +1150,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
                overlay->crtc = crtc;
                crtc->overlay = overlay;
 
-               if (intel_panel_fitter_pipe(dev) == crtc->pipe
-                   /* and line to wide, i.e. one-line-mode */
-                   && mode->hdisplay > 1024) {
+               /* line too wide, i.e. one-line-mode */
+               if (mode->hdisplay > 1024 &&
+                   intel_panel_fitter_pipe(dev) == crtc->pipe) {
                        overlay->pfit_active = 1;
                        update_pfit_vscale_ratio(overlay);
                } else
@@ -1132,10 +1165,10 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
 
        if (overlay->pfit_active) {
                params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
-                       overlay->pfit_vscale_ratio);
+                                overlay->pfit_vscale_ratio);
                /* shifting right rounds downwards, so add 1 */
                params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
-                       overlay->pfit_vscale_ratio) + 1;
+                                overlay->pfit_vscale_ratio) + 1;
        } else {
                params->dst_y = put_image_rec->dst_y;
                params->dst_h = put_image_rec->dst_height;
@@ -1147,8 +1180,8 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
        params->src_h = put_image_rec->src_height;
        params->src_scan_w = put_image_rec->src_scan_width;
        params->src_scan_h = put_image_rec->src_scan_height;
-       if (params->src_scan_h > params->src_h
-           || params->src_scan_w > params->src_w) {
+       if (params->src_scan_h > params->src_h ||
+           params->src_scan_w > params->src_w) {
                ret = -EINVAL;
                goto out_unlock;
        }
@@ -1204,7 +1237,7 @@ static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
                return false;
 
        for (i = 0; i < 3; i++) {
-               if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
+               if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
                        return false;
        }
 
@@ -1225,16 +1258,18 @@ static bool check_gamma5_errata(u32 gamma5)
 
 static int check_gamma(struct drm_intel_overlay_attrs *attrs)
 {
-       if (!check_gamma_bounds(0, attrs->gamma0)
-           || !check_gamma_bounds(attrs->gamma0, attrs->gamma1)
-           || !check_gamma_bounds(attrs->gamma1, attrs->gamma2)
-           || !check_gamma_bounds(attrs->gamma2, attrs->gamma3)
-           || !check_gamma_bounds(attrs->gamma3, attrs->gamma4)
-           || !check_gamma_bounds(attrs->gamma4, attrs->gamma5)
-           || !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
+       if (!check_gamma_bounds(0, attrs->gamma0) ||
+           !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
+           !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
+           !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
+           !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
+           !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
+           !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
                return -EINVAL;
+
        if (!check_gamma5_errata(attrs->gamma5))
                return -EINVAL;
+
        return 0;
 }
 
@@ -1261,13 +1296,14 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
        mutex_lock(&dev->mode_config.mutex);
        mutex_lock(&dev->struct_mutex);
 
+       ret = -EINVAL;
        if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
-               attrs->color_key = overlay->color_key;
+               attrs->color_key  = overlay->color_key;
                attrs->brightness = overlay->brightness;
-               attrs->contrast = overlay->contrast;
+               attrs->contrast   = overlay->contrast;
                attrs->saturation = overlay->saturation;
 
-               if (IS_I9XX(dev)) {
+               if (!IS_GEN2(dev)) {
                        attrs->gamma0 = I915_READ(OGAMC0);
                        attrs->gamma1 = I915_READ(OGAMC1);
                        attrs->gamma2 = I915_READ(OGAMC2);
@@ -1275,29 +1311,20 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
                        attrs->gamma4 = I915_READ(OGAMC4);
                        attrs->gamma5 = I915_READ(OGAMC5);
                }
-               ret = 0;
        } else {
-               overlay->color_key = attrs->color_key;
-               if (attrs->brightness >= -128 && attrs->brightness <= 127) {
-                       overlay->brightness = attrs->brightness;
-               } else {
-                       ret = -EINVAL;
+               if (attrs->brightness < -128 || attrs->brightness > 127)
                        goto out_unlock;
-               }
-               if (attrs->contrast <= 255) {
-                       overlay->contrast = attrs->contrast;
-               } else {
-                       ret = -EINVAL;
+               if (attrs->contrast > 255)
                        goto out_unlock;
-               }
-               if (attrs->saturation <= 1023) {
-                       overlay->saturation = attrs->saturation;
-               } else {
-                       ret = -EINVAL;
+               if (attrs->saturation > 1023)
                        goto out_unlock;
-               }
 
-               regs = intel_overlay_map_regs_atomic(overlay);
+               overlay->color_key  = attrs->color_key;
+               overlay->brightness = attrs->brightness;
+               overlay->contrast   = attrs->contrast;
+               overlay->saturation = attrs->saturation;
+
+               regs = intel_overlay_map_regs(overlay);
                if (!regs) {
                        ret = -ENOMEM;
                        goto out_unlock;
@@ -1305,13 +1332,11 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
 
                update_reg_attrs(overlay, regs);
 
-               intel_overlay_unmap_regs_atomic(overlay);
+               intel_overlay_unmap_regs(overlay, regs);
 
                if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
-                       if (!IS_I9XX(dev)) {
-                               ret = -EINVAL;
+                       if (IS_GEN2(dev))
                                goto out_unlock;
-                       }
 
                        if (overlay->active) {
                                ret = -EBUSY;
@@ -1319,7 +1344,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
                        }
 
                        ret = check_gamma(attrs);
-                       if (ret != 0)
+                       if (ret)
                                goto out_unlock;
 
                        I915_WRITE(OGAMC0, attrs->gamma0);
@@ -1329,9 +1354,9 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
                        I915_WRITE(OGAMC4, attrs->gamma4);
                        I915_WRITE(OGAMC5, attrs->gamma5);
                }
-               ret = 0;
        }
 
+       ret = 0;
 out_unlock:
        mutex_unlock(&dev->struct_mutex);
        mutex_unlock(&dev->mode_config.mutex);
@@ -1347,7 +1372,7 @@ void intel_setup_overlay(struct drm_device *dev)
        struct overlay_registers *regs;
        int ret;
 
-       if (!OVERLAY_EXISTS(dev))
+       if (!HAS_OVERLAY(dev))
                return;
 
        overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
@@ -1360,22 +1385,28 @@ void intel_setup_overlay(struct drm_device *dev)
                goto out_free;
        overlay->reg_bo = to_intel_bo(reg_bo);
 
-       if (OVERLAY_NONPHYSICAL(dev)) {
-               ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
-               if (ret) {
-                        DRM_ERROR("failed to pin overlay register bo\n");
-                        goto out_free_bo;
-                }
-               overlay->flip_addr = overlay->reg_bo->gtt_offset;
-       } else {
+       if (OVERLAY_NEEDS_PHYSICAL(dev)) {
                ret = i915_gem_attach_phys_object(dev, reg_bo,
                                                  I915_GEM_PHYS_OVERLAY_REGS,
-                                                 0);
+                                                 PAGE_SIZE);
                 if (ret) {
                         DRM_ERROR("failed to attach phys overlay regs\n");
                         goto out_free_bo;
                 }
                overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
+       } else {
+               ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
+               if (ret) {
+                        DRM_ERROR("failed to pin overlay register bo\n");
+                        goto out_free_bo;
+                }
+               overlay->flip_addr = overlay->reg_bo->gtt_offset;
+
+               ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
+               if (ret) {
+                        DRM_ERROR("failed to move overlay register bo into the GTT\n");
+                        goto out_unpin_bo;
+                }
        }
 
        /* init all values */
@@ -1384,21 +1415,22 @@ void intel_setup_overlay(struct drm_device *dev)
        overlay->contrast = 75;
        overlay->saturation = 146;
 
-       regs = intel_overlay_map_regs_atomic(overlay);
+       regs = intel_overlay_map_regs(overlay);
        if (!regs)
                goto out_free_bo;
 
        memset(regs, 0, sizeof(struct overlay_registers));
        update_polyphase_filter(regs);
-
        update_reg_attrs(overlay, regs);
 
-       intel_overlay_unmap_regs_atomic(overlay);
+       intel_overlay_unmap_regs(overlay, regs);
 
        dev_priv->overlay = overlay;
        DRM_INFO("initialized overlay support\n");
        return;
 
+out_unpin_bo:
+       i915_gem_object_unpin(reg_bo);
 out_free_bo:
        drm_gem_object_unreference(reg_bo);
 out_free:
@@ -1408,18 +1440,23 @@ out_free:
 
 void intel_cleanup_overlay(struct drm_device *dev)
 {
-        drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_private_t *dev_priv = dev->dev_private;
 
-       if (dev_priv->overlay) {
-               /* The bo's should be free'd by the generic code already.
-                * Furthermore modesetting teardown happens beforehand so the
-                * hardware should be off already */
-               BUG_ON(dev_priv->overlay->active);
+       if (!dev_priv->overlay)
+               return;
 
-               kfree(dev_priv->overlay);
-       }
+       /* The bo's should be free'd by the generic code already.
+        * Furthermore modesetting teardown happens beforehand so the
+        * hardware should be off already */
+       BUG_ON(dev_priv->overlay->active);
+
+       drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
+       kfree(dev_priv->overlay);
 }
 
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
 struct intel_overlay_error_state {
        struct overlay_registers regs;
        unsigned long base;
@@ -1427,6 +1464,32 @@ struct intel_overlay_error_state {
        u32 isr;
 };
 
+static struct overlay_registers *
+intel_overlay_map_regs_atomic(struct intel_overlay *overlay,
+                             int slot)
+{
+        drm_i915_private_t *dev_priv = overlay->dev->dev_private;
+       struct overlay_registers *regs;
+
+       if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+               regs = overlay->reg_bo->phys_obj->handle->vaddr;
+       else
+               regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+                                               overlay->reg_bo->gtt_offset,
+                                               slot);
+
+       return regs;
+}
+
+static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
+                                           int slot,
+                                           struct overlay_registers *regs)
+{
+       if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+               io_mapping_unmap_atomic(regs, slot);
+}
+
+
 struct intel_overlay_error_state *
 intel_overlay_capture_error_state(struct drm_device *dev)
 {
@@ -1444,17 +1507,17 @@ intel_overlay_capture_error_state(struct drm_device *dev)
 
        error->dovsta = I915_READ(DOVSTA);
        error->isr = I915_READ(ISR);
-       if (OVERLAY_NONPHYSICAL(overlay->dev))
-               error->base = (long) overlay->reg_bo->gtt_offset;
-       else
+       if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
                error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
+       else
+               error->base = (long) overlay->reg_bo->gtt_offset;
 
-       regs = intel_overlay_map_regs_atomic(overlay);
+       regs = intel_overlay_map_regs_atomic(overlay, KM_IRQ0);
        if (!regs)
                goto err;
 
        memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
-       intel_overlay_unmap_regs_atomic(overlay);
+       intel_overlay_unmap_regs_atomic(overlay, KM_IRQ0, regs);
 
        return error;
 
@@ -1515,3 +1578,4 @@ intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_s
        P(UVSCALEV);
 #undef P
 }
+#endif
index e7f5299d9d5740177ca8722db99892b2a7a856f5..92ff8f38527810657f94ad2f4439732e8dae8fa9 100644 (file)
@@ -30,6 +30,8 @@
 
 #include "intel_drv.h"
 
+#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
+
 void
 intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
                       struct drm_display_mode *adjusted_mode)
@@ -109,3 +111,110 @@ done:
        dev_priv->pch_pf_pos = (x << 16) | y;
        dev_priv->pch_pf_size = (width << 16) | height;
 }
+
+static int is_backlight_combination_mode(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (INTEL_INFO(dev)->gen >= 4)
+               return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+
+       if (IS_GEN2(dev))
+               return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+       return 0;
+}
+
+u32 intel_panel_get_max_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 max;
+
+       if (HAS_PCH_SPLIT(dev)) {
+               max = I915_READ(BLC_PWM_PCH_CTL2) >> 16;
+       } else {
+               max = I915_READ(BLC_PWM_CTL);
+               if (IS_PINEVIEW(dev)) {
+                       max >>= 17;
+               } else {
+                       max >>= 16;
+                       if (INTEL_INFO(dev)->gen < 4)
+                               max &= ~1;
+               }
+
+               if (is_backlight_combination_mode(dev))
+                       max *= 0xff;
+       }
+
+       if (max == 0) {
+               /* XXX add code here to query mode clock or hardware clock
+                * and program max PWM appropriately.
+                */
+               DRM_ERROR("fixme: max PWM is zero.\n");
+               max = 1;
+       }
+
+       DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
+       return max;
+}
+
+u32 intel_panel_get_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val;
+
+       if (HAS_PCH_SPLIT(dev)) {
+               val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+       } else {
+               val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+               if (IS_PINEVIEW(dev))
+                       val >>= 1;
+
+               if (is_backlight_combination_mode(dev)){
+                       u8 lbpc;
+
+                       val &= ~1;
+                       pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
+                       val *= lbpc;
+                       val >>= 1;
+               }
+       }
+
+       DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
+       return val;
+}
+
+static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(BLC_PWM_CPU_CTL, val | level);
+}
+
+void intel_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp;
+
+       DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
+
+       if (HAS_PCH_SPLIT(dev))
+               return intel_pch_panel_set_backlight(dev, level);
+
+       if (is_backlight_combination_mode(dev)){
+               u32 max = intel_panel_get_max_backlight(dev);
+               u8 lpbc;
+
+               lpbc = level * 0xfe / max + 1;
+               level /= lpbc;
+               pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc);
+       }
+
+       tmp = I915_READ(BLC_PWM_CTL);
+       if (IS_PINEVIEW(dev)) {
+               tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
+               level <<= 1;
+       } else
+               tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(BLC_PWM_CTL, tmp | level);
+}
index cb3508f78bc350735e16962f8283e598c53deca6..d89b88791aac7d763f1f72dbec10d750b78655c6 100644 (file)
@@ -32,6 +32,7 @@
 #include "i915_drv.h"
 #include "i915_drm.h"
 #include "i915_trace.h"
+#include "intel_drv.h"
 
 static u32 i915_gem_get_seqno(struct drm_device *dev)
 {
@@ -49,9 +50,9 @@ static u32 i915_gem_get_seqno(struct drm_device *dev)
 
 static void
 render_ring_flush(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               u32     invalidate_domains,
-               u32     flush_domains)
+                 struct intel_ring_buffer *ring,
+                 u32   invalidate_domains,
+                 u32   flush_domains)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 cmd;
@@ -97,7 +98,7 @@ render_ring_flush(struct drm_device *dev,
                if ((invalidate_domains|flush_domains) &
                    I915_GEM_DOMAIN_RENDER)
                        cmd &= ~MI_NO_WRITE_FLUSH;
-               if (!IS_I965G(dev)) {
+               if (INTEL_INFO(dev)->gen < 4) {
                        /*
                         * On the 965, the sampler cache always gets flushed
                         * and this bit is reserved.
@@ -118,38 +119,26 @@ render_ring_flush(struct drm_device *dev,
        }
 }
 
-static unsigned int render_ring_get_head(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       return I915_READ(PRB0_HEAD) & HEAD_ADDR;
-}
-
-static unsigned int render_ring_get_tail(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+static void ring_set_tail(struct drm_device *dev,
+                         struct intel_ring_buffer *ring,
+                         u32 value)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       return I915_READ(PRB0_TAIL) & TAIL_ADDR;
+       I915_WRITE_TAIL(ring, ring->tail);
 }
 
-static unsigned int render_ring_get_active_head(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+u32 intel_ring_get_active_head(struct drm_device *dev,
+                              struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
+       u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ?
+                       RING_ACTHD(ring->mmio_base) : ACTHD;
 
        return I915_READ(acthd_reg);
 }
 
-static void render_ring_advance_ring(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       I915_WRITE(PRB0_TAIL, ring->tail);
-}
-
 static int init_ring_common(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                           struct intel_ring_buffer *ring)
 {
        u32 head;
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -157,57 +146,57 @@ static int init_ring_common(struct drm_device *dev,
        obj_priv = to_intel_bo(ring->gem_object);
 
        /* Stop the ring if it's running. */
-       I915_WRITE(ring->regs.ctl, 0);
-       I915_WRITE(ring->regs.head, 0);
-       I915_WRITE(ring->regs.tail, 0);
+       I915_WRITE_CTL(ring, 0);
+       I915_WRITE_HEAD(ring, 0);
+       ring->set_tail(dev, ring, 0);
 
        /* Initialize the ring. */
-       I915_WRITE(ring->regs.start, obj_priv->gtt_offset);
-       head = ring->get_head(dev, ring);
+       I915_WRITE_START(ring, obj_priv->gtt_offset);
+       head = I915_READ_HEAD(ring) & HEAD_ADDR;
 
        /* G45 ring initialization fails to reset head to zero */
        if (head != 0) {
                DRM_ERROR("%s head not reset to zero "
                                "ctl %08x head %08x tail %08x start %08x\n",
                                ring->name,
-                               I915_READ(ring->regs.ctl),
-                               I915_READ(ring->regs.head),
-                               I915_READ(ring->regs.tail),
-                               I915_READ(ring->regs.start));
+                               I915_READ_CTL(ring),
+                               I915_READ_HEAD(ring),
+                               I915_READ_TAIL(ring),
+                               I915_READ_START(ring));
 
-               I915_WRITE(ring->regs.head, 0);
+               I915_WRITE_HEAD(ring, 0);
 
                DRM_ERROR("%s head forced to zero "
                                "ctl %08x head %08x tail %08x start %08x\n",
                                ring->name,
-                               I915_READ(ring->regs.ctl),
-                               I915_READ(ring->regs.head),
-                               I915_READ(ring->regs.tail),
-                               I915_READ(ring->regs.start));
+                               I915_READ_CTL(ring),
+                               I915_READ_HEAD(ring),
+                               I915_READ_TAIL(ring),
+                               I915_READ_START(ring));
        }
 
-       I915_WRITE(ring->regs.ctl,
+       I915_WRITE_CTL(ring,
                        ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES)
                        | RING_NO_REPORT | RING_VALID);
 
-       head = I915_READ(ring->regs.head) & HEAD_ADDR;
+       head = I915_READ_HEAD(ring) & HEAD_ADDR;
        /* If the head is still not zero, the ring is dead */
        if (head != 0) {
                DRM_ERROR("%s initialization failed "
                                "ctl %08x head %08x tail %08x start %08x\n",
                                ring->name,
-                               I915_READ(ring->regs.ctl),
-                               I915_READ(ring->regs.head),
-                               I915_READ(ring->regs.tail),
-                               I915_READ(ring->regs.start));
+                               I915_READ_CTL(ring),
+                               I915_READ_HEAD(ring),
+                               I915_READ_TAIL(ring),
+                               I915_READ_START(ring));
                return -EIO;
        }
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_kernel_lost_context(dev);
        else {
-               ring->head = ring->get_head(dev, ring);
-               ring->tail = ring->get_tail(dev, ring);
+               ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+               ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
                ring->space = ring->head - (ring->tail + 8);
                if (ring->space < 0)
                        ring->space += ring->size;
@@ -216,13 +205,13 @@ static int init_ring_common(struct drm_device *dev,
 }
 
 static int init_render_ring(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                           struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret = init_ring_common(dev, ring);
        int mode;
 
-       if (IS_I9XX(dev) && !IS_GEN3(dev)) {
+       if (INTEL_INFO(dev)->gen > 3) {
                mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
                if (IS_GEN6(dev))
                        mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
@@ -250,9 +239,8 @@ do {                                                                        \
  */
 static u32
 render_ring_add_request(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               struct drm_file *file_priv,
-               u32 flush_domains)
+                       struct intel_ring_buffer *ring,
+                       u32 flush_domains)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 seqno;
@@ -315,8 +303,8 @@ render_ring_add_request(struct drm_device *dev,
 }
 
 static u32
-render_ring_get_gem_seqno(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+render_ring_get_seqno(struct drm_device *dev,
+                     struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        if (HAS_PIPE_CONTROL(dev))
@@ -327,7 +315,7 @@ render_ring_get_gem_seqno(struct drm_device *dev,
 
 static void
 render_ring_get_user_irq(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                        struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
@@ -344,7 +332,7 @@ render_ring_get_user_irq(struct drm_device *dev,
 
 static void
 render_ring_put_user_irq(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                        struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
@@ -360,21 +348,23 @@ render_ring_put_user_irq(struct drm_device *dev,
        spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
-static void render_setup_status_page(struct drm_device *dev,
-       struct  intel_ring_buffer *ring)
+void intel_ring_setup_status_page(struct drm_device *dev,
+                                 struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        if (IS_GEN6(dev)) {
-               I915_WRITE(HWS_PGA_GEN6, ring->status_page.gfx_addr);
-               I915_READ(HWS_PGA_GEN6); /* posting read */
+               I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base),
+                          ring->status_page.gfx_addr);
+               I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); /* posting read */
        } else {
-               I915_WRITE(HWS_PGA, ring->status_page.gfx_addr);
-               I915_READ(HWS_PGA); /* posting read */
+               I915_WRITE(RING_HWS_PGA(ring->mmio_base),
+                          ring->status_page.gfx_addr);
+               I915_READ(RING_HWS_PGA(ring->mmio_base)); /* posting read */
        }
 
 }
 
-void
+static void
 bsd_ring_flush(struct drm_device *dev,
                struct intel_ring_buffer *ring,
                u32     invalidate_domains,
@@ -386,45 +376,16 @@ bsd_ring_flush(struct drm_device *dev,
        intel_ring_advance(dev, ring);
 }
 
-static inline unsigned int bsd_ring_get_head(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       return I915_READ(BSD_RING_HEAD) & HEAD_ADDR;
-}
-
-static inline unsigned int bsd_ring_get_tail(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       return I915_READ(BSD_RING_TAIL) & TAIL_ADDR;
-}
-
-static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       return I915_READ(BSD_RING_ACTHD);
-}
-
-static inline void bsd_ring_advance_ring(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       I915_WRITE(BSD_RING_TAIL, ring->tail);
-}
-
 static int init_bsd_ring(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                        struct intel_ring_buffer *ring)
 {
        return init_ring_common(dev, ring);
 }
 
 static u32
 bsd_ring_add_request(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               struct drm_file *file_priv,
-               u32 flush_domains)
+                    struct intel_ring_buffer *ring,
+                    u32 flush_domains)
 {
        u32 seqno;
 
@@ -443,40 +404,32 @@ bsd_ring_add_request(struct drm_device *dev,
        return seqno;
 }
 
-static void bsd_setup_status_page(struct drm_device *dev,
-               struct  intel_ring_buffer *ring)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       I915_WRITE(BSD_HWS_PGA, ring->status_page.gfx_addr);
-       I915_READ(BSD_HWS_PGA);
-}
-
 static void
 bsd_ring_get_user_irq(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                     struct intel_ring_buffer *ring)
 {
        /* do nothing */
 }
 static void
 bsd_ring_put_user_irq(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                     struct intel_ring_buffer *ring)
 {
        /* do nothing */
 }
 
 static u32
-bsd_ring_get_gem_seqno(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+bsd_ring_get_seqno(struct drm_device *dev,
+                  struct intel_ring_buffer *ring)
 {
        return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
 }
 
 static int
 bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               struct drm_i915_gem_execbuffer2 *exec,
-               struct drm_clip_rect *cliprects,
-               uint64_t exec_offset)
+                                struct intel_ring_buffer *ring,
+                                struct drm_i915_gem_execbuffer2 *exec,
+                                struct drm_clip_rect *cliprects,
+                                uint64_t exec_offset)
 {
        uint32_t exec_start;
        exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
@@ -491,10 +444,10 @@ bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
 
 static int
 render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               struct drm_i915_gem_execbuffer2 *exec,
-               struct drm_clip_rect *cliprects,
-               uint64_t exec_offset)
+                                   struct intel_ring_buffer *ring,
+                                   struct drm_i915_gem_execbuffer2 *exec,
+                                   struct drm_clip_rect *cliprects,
+                                   uint64_t exec_offset)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int nbox = exec->num_cliprects;
@@ -524,7 +477,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
                        intel_ring_emit(dev, ring, 0);
                } else {
                        intel_ring_begin(dev, ring, 4);
-                       if (IS_I965G(dev)) {
+                       if (INTEL_INFO(dev)->gen >= 4) {
                                intel_ring_emit(dev, ring,
                                                MI_BATCH_BUFFER_START | (2 << 6)
                                                | MI_BATCH_NON_SECURE_I965);
@@ -553,7 +506,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
 }
 
 static void cleanup_status_page(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                               struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_gem_object *obj;
@@ -573,7 +526,7 @@ static void cleanup_status_page(struct drm_device *dev,
 }
 
 static int init_status_page(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                           struct intel_ring_buffer *ring)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_gem_object *obj;
@@ -603,7 +556,7 @@ static int init_status_page(struct drm_device *dev,
        ring->status_page.obj = obj;
        memset(ring->status_page.page_addr, 0, PAGE_SIZE);
 
-       ring->setup_status_page(dev, ring);
+       intel_ring_setup_status_page(dev, ring);
        DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
                        ring->name, ring->status_page.gfx_addr);
 
@@ -617,15 +570,17 @@ err:
        return ret;
 }
 
-
 int intel_init_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                          struct intel_ring_buffer *ring)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj_priv;
        struct drm_gem_object *obj;
        int ret;
 
        ring->dev = dev;
+       INIT_LIST_HEAD(&ring->active_list);
+       INIT_LIST_HEAD(&ring->request_list);
 
        if (I915_NEED_GFX_HWS(dev)) {
                ret = init_status_page(dev, ring);
@@ -642,7 +597,7 @@ int intel_init_ring_buffer(struct drm_device *dev,
 
        ring->gem_object = obj;
 
-       ret = i915_gem_object_pin(obj, ring->alignment);
+       ret = i915_gem_object_pin(obj, PAGE_SIZE);
        if (ret)
                goto err_unref;
 
@@ -668,14 +623,12 @@ int intel_init_ring_buffer(struct drm_device *dev,
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_kernel_lost_context(dev);
        else {
-               ring->head = ring->get_head(dev, ring);
-               ring->tail = ring->get_tail(dev, ring);
+               ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+               ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
                ring->space = ring->head - (ring->tail + 8);
                if (ring->space < 0)
                        ring->space += ring->size;
        }
-       INIT_LIST_HEAD(&ring->active_list);
-       INIT_LIST_HEAD(&ring->request_list);
        return ret;
 
 err_unmap:
@@ -691,7 +644,7 @@ err_hws:
 }
 
 void intel_cleanup_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                              struct intel_ring_buffer *ring)
 {
        if (ring->gem_object == NULL)
                return;
@@ -704,8 +657,8 @@ void intel_cleanup_ring_buffer(struct drm_device *dev,
        cleanup_status_page(dev, ring);
 }
 
-int intel_wrap_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+static int intel_wrap_ring_buffer(struct drm_device *dev,
+                                 struct intel_ring_buffer *ring)
 {
        unsigned int *virt;
        int rem;
@@ -731,14 +684,15 @@ int intel_wrap_ring_buffer(struct drm_device *dev,
 }
 
 int intel_wait_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring, int n)
+                          struct intel_ring_buffer *ring, int n)
 {
        unsigned long end;
+       drm_i915_private_t *dev_priv = dev->dev_private;
 
        trace_i915_ring_wait_begin (dev);
        end = jiffies + 3 * HZ;
        do {
-               ring->head = ring->get_head(dev, ring);
+               ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
                ring->space = ring->head - (ring->tail + 8);
                if (ring->space < 0)
                        ring->space += ring->size;
@@ -760,7 +714,8 @@ int intel_wait_ring_buffer(struct drm_device *dev,
 }
 
 void intel_ring_begin(struct drm_device *dev,
-               struct intel_ring_buffer *ring, int num_dwords)
+                     struct intel_ring_buffer *ring,
+                     int num_dwords)
 {
        int n = 4*num_dwords;
        if (unlikely(ring->tail + n > ring->size))
@@ -772,16 +727,16 @@ void intel_ring_begin(struct drm_device *dev,
 }
 
 void intel_ring_advance(struct drm_device *dev,
-               struct intel_ring_buffer *ring)
+                       struct intel_ring_buffer *ring)
 {
        ring->tail &= ring->size - 1;
-       ring->advance_ring(dev, ring);
+       ring->set_tail(dev, ring, ring->tail);
 }
 
 void intel_fill_struct(struct drm_device *dev,
-               struct intel_ring_buffer *ring,
-               void *data,
-               unsigned int len)
+                      struct intel_ring_buffer *ring,
+                      void *data,
+                      unsigned int len)
 {
        unsigned int *virt = ring->virtual_start + ring->tail;
        BUG_ON((len&~(4-1)) != 0);
@@ -793,76 +748,136 @@ void intel_fill_struct(struct drm_device *dev,
        intel_ring_advance(dev, ring);
 }
 
-struct intel_ring_buffer render_ring = {
+static const struct intel_ring_buffer render_ring = {
        .name                   = "render ring",
-       .regs                   = {
-               .ctl = PRB0_CTL,
-               .head = PRB0_HEAD,
-               .tail = PRB0_TAIL,
-               .start = PRB0_START
-       },
-       .ring_flag              = I915_EXEC_RENDER,
+       .id                     = RING_RENDER,
+       .mmio_base              = RENDER_RING_BASE,
        .size                   = 32 * PAGE_SIZE,
-       .alignment              = PAGE_SIZE,
-       .virtual_start          = NULL,
-       .dev                    = NULL,
-       .gem_object             = NULL,
-       .head                   = 0,
-       .tail                   = 0,
-       .space                  = 0,
-       .user_irq_refcount      = 0,
-       .irq_gem_seqno          = 0,
-       .waiting_gem_seqno      = 0,
-       .setup_status_page      = render_setup_status_page,
        .init                   = init_render_ring,
-       .get_head               = render_ring_get_head,
-       .get_tail               = render_ring_get_tail,
-       .get_active_head        = render_ring_get_active_head,
-       .advance_ring           = render_ring_advance_ring,
+       .set_tail               = ring_set_tail,
        .flush                  = render_ring_flush,
        .add_request            = render_ring_add_request,
-       .get_gem_seqno          = render_ring_get_gem_seqno,
+       .get_seqno              = render_ring_get_seqno,
        .user_irq_get           = render_ring_get_user_irq,
        .user_irq_put           = render_ring_put_user_irq,
        .dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer,
-       .status_page            = {NULL, 0, NULL},
-       .map                    = {0,}
 };
 
 /* ring buffer for bit-stream decoder */
 
-struct intel_ring_buffer bsd_ring = {
+static const struct intel_ring_buffer bsd_ring = {
        .name                   = "bsd ring",
-       .regs                   = {
-               .ctl = BSD_RING_CTL,
-               .head = BSD_RING_HEAD,
-               .tail = BSD_RING_TAIL,
-               .start = BSD_RING_START
-       },
-       .ring_flag              = I915_EXEC_BSD,
+       .id                     = RING_BSD,
+       .mmio_base              = BSD_RING_BASE,
        .size                   = 32 * PAGE_SIZE,
-       .alignment              = PAGE_SIZE,
-       .virtual_start          = NULL,
-       .dev                    = NULL,
-       .gem_object             = NULL,
-       .head                   = 0,
-       .tail                   = 0,
-       .space                  = 0,
-       .user_irq_refcount      = 0,
-       .irq_gem_seqno          = 0,
-       .waiting_gem_seqno      = 0,
-       .setup_status_page      = bsd_setup_status_page,
        .init                   = init_bsd_ring,
-       .get_head               = bsd_ring_get_head,
-       .get_tail               = bsd_ring_get_tail,
-       .get_active_head        = bsd_ring_get_active_head,
-       .advance_ring           = bsd_ring_advance_ring,
+       .set_tail               = ring_set_tail,
        .flush                  = bsd_ring_flush,
        .add_request            = bsd_ring_add_request,
-       .get_gem_seqno          = bsd_ring_get_gem_seqno,
+       .get_seqno              = bsd_ring_get_seqno,
        .user_irq_get           = bsd_ring_get_user_irq,
        .user_irq_put           = bsd_ring_put_user_irq,
        .dispatch_gem_execbuffer = bsd_ring_dispatch_gem_execbuffer,
-       .status_page            = {NULL, 0, NULL},
-       .map                    = {0,}
 };
+
+
+static void gen6_bsd_ring_set_tail(struct drm_device *dev,
+                                  struct intel_ring_buffer *ring,
+                                  u32 value)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       /* Every tail move must follow the sequence below */
+       I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
+              GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
+              GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE);
+       I915_WRITE(GEN6_BSD_RNCID, 0x0);
+
+       if (wait_for((I915_READ(GEN6_BSD_SLEEP_PSMI_CONTROL) &
+                               GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR) == 0,
+                       50))
+               DRM_ERROR("timed out waiting for IDLE Indicator\n");
+
+       I915_WRITE_TAIL(ring, value);
+       I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
+              GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
+              GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE);
+}
+
+static void gen6_bsd_ring_flush(struct drm_device *dev,
+                               struct intel_ring_buffer *ring,
+                               u32 invalidate_domains,
+                               u32 flush_domains)
+{
+       intel_ring_begin(dev, ring, 4);
+       intel_ring_emit(dev, ring, MI_FLUSH_DW);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_advance(dev, ring);
+}
+
+static int
+gen6_bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
+                                     struct intel_ring_buffer *ring,
+                                     struct drm_i915_gem_execbuffer2 *exec,
+                                     struct drm_clip_rect *cliprects,
+                                     uint64_t exec_offset)
+{
+       uint32_t exec_start;
+
+       exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+
+       intel_ring_begin(dev, ring, 2);
+       intel_ring_emit(dev, ring,
+                      MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965);
+       /* bit0-7 is the length on GEN6+ */
+       intel_ring_emit(dev, ring, exec_start);
+       intel_ring_advance(dev, ring);
+
+       return 0;
+}
+
+/* ring buffer for Video Codec for Gen6+ */
+static const struct intel_ring_buffer gen6_bsd_ring = {
+       .name                   = "gen6 bsd ring",
+       .id                     = RING_BSD,
+       .mmio_base              = GEN6_BSD_RING_BASE,
+       .size                   = 32 * PAGE_SIZE,
+       .init                   = init_bsd_ring,
+       .set_tail               = gen6_bsd_ring_set_tail,
+       .flush                  = gen6_bsd_ring_flush,
+       .add_request            = bsd_ring_add_request,
+       .get_seqno              = bsd_ring_get_seqno,
+       .user_irq_get           = bsd_ring_get_user_irq,
+       .user_irq_put           = bsd_ring_put_user_irq,
+       .dispatch_gem_execbuffer        = gen6_bsd_ring_dispatch_gem_execbuffer,
+};
+
+int intel_init_render_ring_buffer(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       dev_priv->render_ring = render_ring;
+
+       if (!I915_NEED_GFX_HWS(dev)) {
+               dev_priv->render_ring.status_page.page_addr
+                       = dev_priv->status_page_dmah->vaddr;
+               memset(dev_priv->render_ring.status_page.page_addr,
+                               0, PAGE_SIZE);
+       }
+
+       return intel_init_ring_buffer(dev, &dev_priv->render_ring);
+}
+
+int intel_init_bsd_ring_buffer(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       if (IS_GEN6(dev))
+               dev_priv->bsd_ring = gen6_bsd_ring;
+       else
+               dev_priv->bsd_ring = bsd_ring;
+
+       return intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+}
index 525e7d3edda801582ac5a779de31a8fe43844ae0..9725f783db202f3a80d12a2b92c6bf5a279004bb 100644 (file)
@@ -7,25 +7,31 @@ struct  intel_hw_status_page {
        struct          drm_gem_object *obj;
 };
 
+#define I915_READ_TAIL(ring) I915_READ(RING_TAIL(ring->mmio_base))
+#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val)
+#define I915_READ_START(ring) I915_READ(RING_START(ring->mmio_base))
+#define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val)
+#define I915_READ_HEAD(ring) I915_READ(RING_HEAD(ring->mmio_base))
+#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val)
+#define I915_READ_CTL(ring) I915_READ(RING_CTL(ring->mmio_base))
+#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val)
+
 struct drm_i915_gem_execbuffer2;
 struct  intel_ring_buffer {
        const char      *name;
-       struct          ring_regs {
-                       u32 ctl;
-                       u32 head;
-                       u32 tail;
-                       u32 start;
-       } regs;
-       unsigned int    ring_flag;
+       enum intel_ring_id {
+               RING_RENDER = 0x1,
+               RING_BSD = 0x2,
+       } id;
+       u32             mmio_base;
        unsigned long   size;
-       unsigned int    alignment;
        void            *virtual_start;
        struct          drm_device *dev;
        struct          drm_gem_object *gem_object;
 
        unsigned int    head;
        unsigned int    tail;
-       unsigned int    space;
+       int             space;
        struct intel_hw_status_page status_page;
 
        u32             irq_gem_seqno;          /* last seq seem at irq time */
@@ -35,30 +41,22 @@ struct  intel_ring_buffer {
                        struct intel_ring_buffer *ring);
        void            (*user_irq_put)(struct drm_device *dev,
                        struct intel_ring_buffer *ring);
-       void            (*setup_status_page)(struct drm_device *dev,
-                       struct  intel_ring_buffer *ring);
 
        int             (*init)(struct drm_device *dev,
                        struct intel_ring_buffer *ring);
 
-       unsigned int    (*get_head)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
-       unsigned int    (*get_tail)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
-       unsigned int    (*get_active_head)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
-       void            (*advance_ring)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
+       void            (*set_tail)(struct drm_device *dev,
+                                   struct intel_ring_buffer *ring,
+                                   u32 value);
        void            (*flush)(struct drm_device *dev,
                        struct intel_ring_buffer *ring,
                        u32     invalidate_domains,
                        u32     flush_domains);
        u32             (*add_request)(struct drm_device *dev,
                        struct intel_ring_buffer *ring,
-                       struct drm_file *file_priv,
                        u32 flush_domains);
-       u32             (*get_gem_seqno)(struct drm_device *dev,
-                       struct intel_ring_buffer *ring);
+       u32             (*get_seqno)(struct drm_device *dev,
+                                    struct intel_ring_buffer *ring);
        int             (*dispatch_gem_execbuffer)(struct drm_device *dev,
                        struct intel_ring_buffer *ring,
                        struct drm_i915_gem_execbuffer2 *exec,
@@ -83,6 +81,11 @@ struct  intel_ring_buffer {
         */
        struct list_head request_list;
 
+       /**
+        * Do we have some not yet emitted requests outstanding?
+        */
+       bool outstanding_lazy_request;
+
        wait_queue_head_t irq_queue;
        drm_local_map_t map;
 };
@@ -96,15 +99,13 @@ intel_read_status_page(struct intel_ring_buffer *ring,
 }
 
 int intel_init_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring);
+                          struct intel_ring_buffer *ring);
 void intel_cleanup_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring);
+                              struct intel_ring_buffer *ring);
 int intel_wait_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring, int n);
-int intel_wrap_ring_buffer(struct drm_device *dev,
-               struct intel_ring_buffer *ring);
+                          struct intel_ring_buffer *ring, int n);
 void intel_ring_begin(struct drm_device *dev,
-               struct intel_ring_buffer *ring, int n);
+                     struct intel_ring_buffer *ring, int n);
 
 static inline void intel_ring_emit(struct drm_device *dev,
                                   struct intel_ring_buffer *ring,
@@ -125,7 +126,12 @@ void intel_ring_advance(struct drm_device *dev,
 u32 intel_ring_get_seqno(struct drm_device *dev,
                struct intel_ring_buffer *ring);
 
-extern struct intel_ring_buffer render_ring;
-extern struct intel_ring_buffer bsd_ring;
+int intel_init_render_ring_buffer(struct drm_device *dev);
+int intel_init_bsd_ring_buffer(struct drm_device *dev);
+
+u32 intel_ring_get_active_head(struct drm_device *dev,
+                              struct intel_ring_buffer *ring);
+void intel_ring_setup_status_page(struct drm_device *dev,
+                                 struct intel_ring_buffer *ring);
 
 #endif /* _INTEL_RINGBUFFER_H_ */
index e8e902d614edc8431cd4f17b5650a4682c7b0917..a84224f37605fc645f3781292ab308703f8dad42 100644 (file)
@@ -65,8 +65,11 @@ static const char *tv_format_names[] = {
 struct intel_sdvo {
        struct intel_encoder base;
 
+       struct i2c_adapter *i2c;
        u8 slave_addr;
 
+       struct i2c_adapter ddc;
+
        /* Register for the SDVO device: SDVOB or SDVOC */
        int sdvo_reg;
 
@@ -106,15 +109,11 @@ struct intel_sdvo {
        bool is_hdmi;
 
        /**
-        * This is set if we detect output of sdvo device as LVDS.
+        * This is set if we detect output of sdvo device as LVDS and
+        * have a valid fixed mode to use with the panel.
         */
        bool is_lvds;
 
-       /**
-        * This is sdvo flags for input timing.
-        */
-       uint8_t sdvo_flags;
-
        /**
         * This is sdvo fixed pannel mode pointer
         */
@@ -129,9 +128,8 @@ struct intel_sdvo {
        /* DDC bus used by this SDVO encoder */
        uint8_t ddc_bus;
 
-       /* Mac mini hack -- use the same DDC as the analog connector */
-       struct i2c_adapter *analog_ddc_bus;
-
+       /* Input timings for adjusted_mode */
+       struct intel_sdvo_dtd input_dtd;
 };
 
 struct intel_sdvo_connector {
@@ -186,9 +184,15 @@ struct intel_sdvo_connector {
        u32     cur_dot_crawl,  max_dot_crawl;
 };
 
-static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder)
+static struct intel_sdvo *to_intel_sdvo(struct drm_encoder *encoder)
+{
+       return container_of(encoder, struct intel_sdvo, base.base);
+}
+
+static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base);
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_sdvo, base);
 }
 
 static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector)
@@ -213,7 +217,7 @@ intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
  */
 static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
 {
-       struct drm_device *dev = intel_sdvo->base.enc.dev;
+       struct drm_device *dev = intel_sdvo->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 bval = val, cval = val;
        int i;
@@ -245,49 +249,29 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
 
 static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
 {
-       u8 out_buf[2] = { addr, 0 };
-       u8 buf[2];
        struct i2c_msg msgs[] = {
                {
-                       .addr = intel_sdvo->slave_addr >> 1,
+                       .addr = intel_sdvo->slave_addr,
                        .flags = 0,
                        .len = 1,
-                       .buf = out_buf,
+                       .buf = &addr,
                },
                {
-                       .addr = intel_sdvo->slave_addr >> 1,
+                       .addr = intel_sdvo->slave_addr,
                        .flags = I2C_M_RD,
                        .len = 1,
-                       .buf = buf,
+                       .buf = ch,
                }
        };
        int ret;
 
-       if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2)
-       {
-               *ch = buf[0];
+       if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)
                return true;
-       }
 
        DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
        return false;
 }
 
-static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch)
-{
-       u8 out_buf[2] = { addr, ch };
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = intel_sdvo->slave_addr >> 1,
-                       .flags = 0,
-                       .len = 2,
-                       .buf = out_buf,
-               }
-       };
-
-       return i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1;
-}
-
 #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
 /** Mapping of command numbers to names, for debug output */
 static const struct _sdvo_cmd_name {
@@ -432,22 +416,6 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
        DRM_LOG_KMS("\n");
 }
 
-static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
-                                const void *args, int args_len)
-{
-       int i;
-
-       intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
-
-       for (i = 0; i < args_len; i++) {
-               if (!intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i,
-                                          ((u8*)args)[i]))
-                       return false;
-       }
-
-       return intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd);
-}
-
 static const char *cmd_status_names[] = {
        "Power on",
        "Success",
@@ -458,54 +426,115 @@ static const char *cmd_status_names[] = {
        "Scaling not supported"
 };
 
-static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo,
-                                     void *response, int response_len,
-                                     u8 status)
+static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
+                                const void *args, int args_len)
 {
-       int i;
+       u8 buf[args_len*2 + 2], status;
+       struct i2c_msg msgs[args_len + 3];
+       int i, ret;
 
-       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
-       for (i = 0; i < response_len; i++)
-               DRM_LOG_KMS("%02X ", ((u8 *)response)[i]);
-       for (; i < 8; i++)
-               DRM_LOG_KMS("   ");
-       if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
-               DRM_LOG_KMS("(%s)", cmd_status_names[status]);
-       else
-               DRM_LOG_KMS("(??? %d)", status);
-       DRM_LOG_KMS("\n");
+       intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
+
+       for (i = 0; i < args_len; i++) {
+               msgs[i].addr = intel_sdvo->slave_addr;
+               msgs[i].flags = 0;
+               msgs[i].len = 2;
+               msgs[i].buf = buf + 2 *i;
+               buf[2*i + 0] = SDVO_I2C_ARG_0 - i;
+               buf[2*i + 1] = ((u8*)args)[i];
+       }
+       msgs[i].addr = intel_sdvo->slave_addr;
+       msgs[i].flags = 0;
+       msgs[i].len = 2;
+       msgs[i].buf = buf + 2*i;
+       buf[2*i + 0] = SDVO_I2C_OPCODE;
+       buf[2*i + 1] = cmd;
+
+       /* the following two are to read the response */
+       status = SDVO_I2C_CMD_STATUS;
+       msgs[i+1].addr = intel_sdvo->slave_addr;
+       msgs[i+1].flags = 0;
+       msgs[i+1].len = 1;
+       msgs[i+1].buf = &status;
+
+       msgs[i+2].addr = intel_sdvo->slave_addr;
+       msgs[i+2].flags = I2C_M_RD;
+       msgs[i+2].len = 1;
+       msgs[i+2].buf = &status;
+
+       ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);
+       if (ret < 0) {
+               DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
+               return false;
+       }
+       if (ret != i+3) {
+               /* failure in I2C transfer */
+               DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);
+               return false;
+       }
+
+       i = 3;
+       while (status == SDVO_CMD_STATUS_PENDING && i--) {
+               if (!intel_sdvo_read_byte(intel_sdvo,
+                                         SDVO_I2C_CMD_STATUS,
+                                         &status))
+                       return false;
+       }
+       if (status != SDVO_CMD_STATUS_SUCCESS) {
+               DRM_DEBUG_KMS("command returns response %s [%d]\n",
+                             status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP ? cmd_status_names[status] : "???",
+                             status);
+               return false;
+       }
+
+       return true;
 }
 
 static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
                                     void *response, int response_len)
 {
-       int i;
+       u8 retry = 5;
        u8 status;
-       u8 retry = 50;
-
-       while (retry--) {
-               /* Read the command response */
-               for (i = 0; i < response_len; i++) {
-                       if (!intel_sdvo_read_byte(intel_sdvo,
-                                                 SDVO_I2C_RETURN_0 + i,
-                                                 &((u8 *)response)[i]))
-                               return false;
-               }
+       int i;
 
-               /* read the return status */
-               if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS,
+       /*
+        * The documentation states that all commands will be
+        * processed within 15µs, and that we need only poll
+        * the status byte a maximum of 3 times in order for the
+        * command to be complete.
+        *
+        * Check 5 times in case the hardware failed to read the docs.
+        */
+       do {
+               if (!intel_sdvo_read_byte(intel_sdvo,
+                                         SDVO_I2C_CMD_STATUS,
                                          &status))
                        return false;
+       } while (status == SDVO_CMD_STATUS_PENDING && --retry);
 
-               intel_sdvo_debug_response(intel_sdvo, response, response_len,
-                                         status);
-               if (status != SDVO_CMD_STATUS_PENDING)
-                       break;
+       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
+       if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
+               DRM_LOG_KMS("(%s)", cmd_status_names[status]);
+       else
+               DRM_LOG_KMS("(??? %d)", status);
+
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               goto log_fail;
 
-               mdelay(50);
+       /* Read the command response */
+       for (i = 0; i < response_len; i++) {
+               if (!intel_sdvo_read_byte(intel_sdvo,
+                                         SDVO_I2C_RETURN_0 + i,
+                                         &((u8 *)response)[i]))
+                       goto log_fail;
+               DRM_LOG_KMS(" %02X", ((u8 *)response)[i]);
        }
+       DRM_LOG_KMS("\n");
+       return true;
 
-       return status == SDVO_CMD_STATUS_SUCCESS;
+log_fail:
+       DRM_LOG_KMS("\n");
+       return false;
 }
 
 static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
@@ -518,71 +547,17 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
                return 4;
 }
 
-/**
- * Try to read the response after issuie the DDC switch command. But it
- * is noted that we must do the action of reading response and issuing DDC
- * switch command in one I2C transaction. Otherwise when we try to start
- * another I2C transaction after issuing the DDC bus switch, it will be
- * switched to the internal SDVO register.
- */
-static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
-                                             u8 target)
+static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
+                                             u8 ddc_bus)
 {
-       u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = intel_sdvo->slave_addr >> 1,
-                       .flags = 0,
-                       .len = 2,
-                       .buf = out_buf,
-               },
-               /* the following two are to read the response */
-               {
-                       .addr = intel_sdvo->slave_addr >> 1,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = cmd_buf,
-               },
-               {
-                       .addr = intel_sdvo->slave_addr >> 1,
-                       .flags = I2C_M_RD,
-                       .len = 1,
-                       .buf = ret_value,
-               },
-       };
-
-       intel_sdvo_debug_write(intel_sdvo, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
-                                       &target, 1);
-       /* write the DDC switch command argument */
-       intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0, target);
-
-       out_buf[0] = SDVO_I2C_OPCODE;
-       out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
-       cmd_buf[0] = SDVO_I2C_CMD_STATUS;
-       cmd_buf[1] = 0;
-       ret_value[0] = 0;
-       ret_value[1] = 0;
-
-       ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 3);
-       if (ret != 3) {
-               /* failure in I2C transfer */
-               DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
-               return;
-       }
-       if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) {
-               DRM_DEBUG_KMS("DDC switch command returns response %d\n",
-                                       ret_value[0]);
-               return;
-       }
-       return;
+       return intel_sdvo_write_cmd(intel_sdvo,
+                                   SDVO_CMD_SET_CONTROL_BUS_SWITCH,
+                                   &ddc_bus, 1);
 }
 
 static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
 {
-       if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
-               return false;
-
-       return intel_sdvo_read_response(intel_sdvo, NULL, 0);
+       return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len);
 }
 
 static bool
@@ -1022,8 +997,6 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
                                        struct drm_display_mode *mode,
                                        struct drm_display_mode *adjusted_mode)
 {
-       struct intel_sdvo_dtd input_dtd;
-
        /* Reset the input timing to the screen. Assume always input 0. */
        if (!intel_sdvo_set_target_input(intel_sdvo))
                return false;
@@ -1035,14 +1008,12 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
                return false;
 
        if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
-                                                  &input_dtd))
+                                                  &intel_sdvo->input_dtd))
                return false;
 
-       intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
-       intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags;
+       intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);
 
        drm_mode_set_crtcinfo(adjusted_mode, 0);
-       mode->clock = adjusted_mode->clock;
        return true;
 }
 
@@ -1050,7 +1021,8 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode)
 {
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+       int multiplier;
 
        /* We need to construct preferred input timings based on our
         * output timings.  To do that, we have to set the output
@@ -1065,10 +1037,8 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
                                                             mode,
                                                             adjusted_mode);
        } else if (intel_sdvo->is_lvds) {
-               drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0);
-
                if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
-                                                           intel_sdvo->sdvo_lvds_fixed_mode))
+                                                            intel_sdvo->sdvo_lvds_fixed_mode))
                        return false;
 
                (void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,
@@ -1077,9 +1047,10 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
        }
 
        /* Make the CRTC code factor in the SDVO pixel multiplier.  The
-        * SDVO device will be told of the multiplier during mode_set.
+        * SDVO device will factor out the multiplier during mode_set.
         */
-       adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
+       multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);
+       intel_mode_set_pixel_multiplier(adjusted_mode, multiplier);
 
        return true;
 }
@@ -1092,11 +1063,12 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = encoder->crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-       u32 sdvox = 0;
-       int sdvo_pixel_multiply, rate;
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+       u32 sdvox;
        struct intel_sdvo_in_out_map in_out;
        struct intel_sdvo_dtd input_dtd;
+       int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+       int rate;
 
        if (!mode)
                return;
@@ -1114,28 +1086,23 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
                             SDVO_CMD_SET_IN_OUT_MAP,
                             &in_out, sizeof(in_out));
 
-       if (intel_sdvo->is_hdmi) {
-               if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
-                       return;
-
-               sdvox |= SDVO_AUDIO_ENABLE;
-       }
+       /* Set the output timings to the screen */
+       if (!intel_sdvo_set_target_output(intel_sdvo,
+                                         intel_sdvo->attached_output))
+               return;
 
        /* We have tried to get input timing in mode_fixup, and filled into
-          adjusted_mode */
-       intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-       if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
-               input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags;
-
-       /* If it's a TV, we already set the output timing in mode_fixup.
-        * Otherwise, the output timing is equal to the input timing.
+        * adjusted_mode.
         */
-       if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) {
+       if (intel_sdvo->is_tv || intel_sdvo->is_lvds) {
+               input_dtd = intel_sdvo->input_dtd;
+       } else {
                /* Set the output timing to the screen */
                if (!intel_sdvo_set_target_output(intel_sdvo,
                                                  intel_sdvo->attached_output))
                        return;
 
+               intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
                (void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd);
        }
 
@@ -1143,31 +1110,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
        if (!intel_sdvo_set_target_input(intel_sdvo))
                return;
 
-       if (intel_sdvo->is_tv) {
-               if (!intel_sdvo_set_tv_format(intel_sdvo))
-                       return;
-       }
+       if (intel_sdvo->is_hdmi &&
+           !intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
+               return;
 
-       /* We would like to use intel_sdvo_create_preferred_input_timing() to
-        * provide the device with a timing it can support, if it supports that
-        * feature.  However, presumably we would need to adjust the CRTC to
-        * output the preferred timing, and we don't support that currently.
-        */
-#if 0
-       success = intel_sdvo_create_preferred_input_timing(encoder, clock,
-                                                          width, height);
-       if (success) {
-               struct intel_sdvo_dtd *input_dtd;
+       if (intel_sdvo->is_tv &&
+           !intel_sdvo_set_tv_format(intel_sdvo))
+               return;
 
-               intel_sdvo_get_preferred_input_timing(encoder, &input_dtd);
-               intel_sdvo_set_input_timing(encoder, &input_dtd);
-       }
-#else
        (void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd);
-#endif
 
-       sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode);
-       switch (sdvo_pixel_multiply) {
+       switch (pixel_multiplier) {
+       default:
        case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
        case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
        case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -1176,14 +1130,14 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
                return;
 
        /* Set the SDVO control regs. */
-       if (IS_I965G(dev)) {
-               sdvox |= SDVO_BORDER_ENABLE;
+       if (INTEL_INFO(dev)->gen >= 4) {
+               sdvox = SDVO_BORDER_ENABLE;
                if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
                        sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
                if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
                        sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
        } else {
-               sdvox |= I915_READ(intel_sdvo->sdvo_reg);
+               sdvox = I915_READ(intel_sdvo->sdvo_reg);
                switch (intel_sdvo->sdvo_reg) {
                case SDVOB:
                        sdvox &= SDVOB_PRESERVE_MASK;
@@ -1196,16 +1150,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
        }
        if (intel_crtc->pipe == 1)
                sdvox |= SDVO_PIPE_B_SELECT;
+       if (intel_sdvo->is_hdmi)
+               sdvox |= SDVO_AUDIO_ENABLE;
 
-       if (IS_I965G(dev)) {
+       if (INTEL_INFO(dev)->gen >= 4) {
                /* done in crtc_mode_set as the dpll_md reg must be written early */
        } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
                /* done in crtc_mode_set as it lives inside the dpll register */
        } else {
-               sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
+               sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT;
        }
 
-       if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL)
+       if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL)
                sdvox |= SDVO_STALL_SELECT;
        intel_sdvo_write_sdvox(intel_sdvo, sdvox);
 }
@@ -1214,7 +1170,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
        u32 temp;
 
@@ -1260,8 +1216,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 static int intel_sdvo_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
@@ -1285,7 +1240,38 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector,
 
 static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
 {
-       return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps));
+       if (!intel_sdvo_get_value(intel_sdvo,
+                                 SDVO_CMD_GET_DEVICE_CAPS,
+                                 caps, sizeof(*caps)))
+               return false;
+
+       DRM_DEBUG_KMS("SDVO capabilities:\n"
+                     "  vendor_id: %d\n"
+                     "  device_id: %d\n"
+                     "  device_rev_id: %d\n"
+                     "  sdvo_version_major: %d\n"
+                     "  sdvo_version_minor: %d\n"
+                     "  sdvo_inputs_mask: %d\n"
+                     "  smooth_scaling: %d\n"
+                     "  sharp_scaling: %d\n"
+                     "  up_scaling: %d\n"
+                     "  down_scaling: %d\n"
+                     "  stall_support: %d\n"
+                     "  output_flags: %d\n",
+                     caps->vendor_id,
+                     caps->device_id,
+                     caps->device_rev_id,
+                     caps->sdvo_version_major,
+                     caps->sdvo_version_minor,
+                     caps->sdvo_inputs_mask,
+                     caps->smooth_scaling,
+                     caps->sharp_scaling,
+                     caps->up_scaling,
+                     caps->down_scaling,
+                     caps->stall_support,
+                     caps->output_flags);
+
+       return true;
 }
 
 /* No use! */
@@ -1389,22 +1375,33 @@ intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
        return (caps > 1);
 }
 
+static struct edid *
+intel_sdvo_get_edid(struct drm_connector *connector)
+{
+       struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
+       return drm_get_edid(connector, &sdvo->ddc);
+}
+
 static struct drm_connector *
 intel_find_analog_connector(struct drm_device *dev)
 {
        struct drm_connector *connector;
-       struct drm_encoder *encoder;
-       struct intel_sdvo *intel_sdvo;
-
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               intel_sdvo = enc_to_intel_sdvo(encoder);
-               if (intel_sdvo->base.type == INTEL_OUTPUT_ANALOG) {
-                       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-                               if (encoder == intel_attached_encoder(connector))
+       struct intel_sdvo *encoder;
+
+       list_for_each_entry(encoder,
+                           &dev->mode_config.encoder_list,
+                           base.base.head) {
+               if (encoder->base.type == INTEL_OUTPUT_ANALOG) {
+                       list_for_each_entry(connector,
+                                           &dev->mode_config.connector_list,
+                                           head) {
+                               if (&encoder->base ==
+                                   intel_attached_encoder(connector))
                                        return connector;
                        }
                }
        }
+
        return NULL;
 }
 
@@ -1424,65 +1421,66 @@ intel_analog_is_connected(struct drm_device *dev)
        return true;
 }
 
+/* Mac mini hack -- use the same DDC as the analog connector */
+static struct edid *
+intel_sdvo_get_analog_edid(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+
+       if (!intel_analog_is_connected(connector->dev))
+               return NULL;
+
+       return drm_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+}
+
 enum drm_connector_status
 intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-       struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
-       enum drm_connector_status status = connector_status_connected;
-       struct edid *edid = NULL;
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       enum drm_connector_status status;
+       struct edid *edid;
 
-       edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
+       edid = intel_sdvo_get_edid(connector);
 
-       /* This is only applied to SDVO cards with multiple outputs */
        if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) {
-               uint8_t saved_ddc, temp_ddc;
-               saved_ddc = intel_sdvo->ddc_bus;
-               temp_ddc = intel_sdvo->ddc_bus >> 1;
+               u8 ddc, saved_ddc = intel_sdvo->ddc_bus;
+
                /*
                 * Don't use the 1 as the argument of DDC bus switch to get
                 * the EDID. It is used for SDVO SPD ROM.
                 */
-               while(temp_ddc > 1) {
-                       intel_sdvo->ddc_bus = temp_ddc;
-                       edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
-                       if (edid) {
-                               /*
-                                * When we can get the EDID, maybe it is the
-                                * correct DDC bus. Update it.
-                                */
-                               intel_sdvo->ddc_bus = temp_ddc;
+               for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {
+                       intel_sdvo->ddc_bus = ddc;
+                       edid = intel_sdvo_get_edid(connector);
+                       if (edid)
                                break;
-                       }
-                       temp_ddc >>= 1;
                }
+               /*
+                * If we found the EDID on the other bus,
+                * assume that is the correct DDC bus.
+                */
                if (edid == NULL)
                        intel_sdvo->ddc_bus = saved_ddc;
        }
-       /* when there is no edid and no monitor is connected with VGA
-        * port, try to use the CRT ddc to read the EDID for DVI-connector
+
+       /*
+        * When there is no edid and no monitor is connected with VGA
+        * port, try to use the CRT ddc to read the EDID for DVI-connector.
         */
-       if (edid == NULL && intel_sdvo->analog_ddc_bus &&
-           !intel_analog_is_connected(connector->dev))
-               edid = drm_get_edid(connector, intel_sdvo->analog_ddc_bus);
+       if (edid == NULL)
+               edid = intel_sdvo_get_analog_edid(connector);
 
+       status = connector_status_unknown;
        if (edid != NULL) {
-               bool is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
-               bool need_digital = !!(intel_sdvo_connector->output_flag & SDVO_TMDS_MASK);
-
                /* DDC bus is shared, match EDID to connector type */
-               if (is_digital && need_digital)
+               if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+                       status = connector_status_connected;
                        intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid);
-               else if (is_digital != need_digital)
-                       status = connector_status_disconnected;
-
+               }
                connector->display_info.raw_edid = NULL;
-       } else
-               status = connector_status_disconnected;
+               kfree(edid);
+       }
        
-       kfree(edid);
-
        return status;
 }
 
@@ -1490,13 +1488,12 @@ static enum drm_connector_status
 intel_sdvo_detect(struct drm_connector *connector, bool force)
 {
        uint16_t response;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
        struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
        enum drm_connector_status ret;
 
        if (!intel_sdvo_write_cmd(intel_sdvo,
-                            SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
+                                 SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
                return connector_status_unknown;
        if (intel_sdvo->is_tv) {
                /* add 30ms delay when the output type is SDVO-TV */
@@ -1505,7 +1502,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
        if (!intel_sdvo_read_response(intel_sdvo, &response, 2))
                return connector_status_unknown;
 
-       DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8);
+       DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",
+                     response & 0xff, response >> 8,
+                     intel_sdvo_connector->output_flag);
 
        if (response == 0)
                return connector_status_disconnected;
@@ -1538,12 +1537,10 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
 
 static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-       int num_modes;
+       struct edid *edid;
 
        /* set the bus switch and get the modes */
-       num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
+       edid = intel_sdvo_get_edid(connector);
 
        /*
         * Mac mini hack.  On this device, the DVI-I connector shares one DDC
@@ -1551,12 +1548,14 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
         * DDC fails, check to see if the analog output is disconnected, in
         * which case we'll look there for the digital DDC data.
         */
-       if (num_modes == 0 &&
-           intel_sdvo->analog_ddc_bus &&
-           !intel_analog_is_connected(connector->dev)) {
-               /* Switch to the analog ddc bus and try that
-                */
-               (void) intel_ddc_get_modes(connector, intel_sdvo->analog_ddc_bus);
+       if (edid == NULL)
+               edid = intel_sdvo_get_analog_edid(connector);
+
+       if (edid != NULL) {
+               drm_mode_connector_update_edid_property(connector, edid);
+               drm_add_edid_modes(connector, edid);
+               connector->display_info.raw_edid = NULL;
+               kfree(edid);
        }
 }
 
@@ -1627,8 +1626,7 @@ struct drm_display_mode sdvo_tv_modes[] = {
 
 static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
        struct intel_sdvo_sdtv_resolution_request tv_res;
        uint32_t reply = 0, format_map = 0;
        int i;
@@ -1644,7 +1642,8 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
                return;
 
        BUILD_BUG_ON(sizeof(tv_res) != 3);
-       if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
+       if (!intel_sdvo_write_cmd(intel_sdvo,
+                                 SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
                                  &tv_res, sizeof(tv_res)))
                return;
        if (!intel_sdvo_read_response(intel_sdvo, &reply, 3))
@@ -1662,8 +1661,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 
 static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
        struct drm_display_mode *newmode;
 
@@ -1672,7 +1670,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
         * Assume that the preferred modes are
         * arranged in priority order.
         */
-       intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
+       intel_ddc_get_modes(connector, intel_sdvo->i2c);
        if (list_empty(&connector->probed_modes) == false)
                goto end;
 
@@ -1693,6 +1691,10 @@ end:
                if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
                        intel_sdvo->sdvo_lvds_fixed_mode =
                                drm_mode_duplicate(connector->dev, newmode);
+
+                       drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode,
+                                             0);
+
                        intel_sdvo->is_lvds = true;
                        break;
                }
@@ -1775,8 +1777,7 @@ intel_sdvo_set_property(struct drm_connector *connector,
                        struct drm_property *property,
                        uint64_t val)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
        struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
        uint16_t temp_value;
        uint8_t cmd;
@@ -1879,9 +1880,8 @@ set_value:
 
 
 done:
-       if (encoder->crtc) {
-               struct drm_crtc *crtc = encoder->crtc;
-
+       if (intel_sdvo->base.base.crtc) {
+               struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
                drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
                                         crtc->y, crtc->fb);
        }
@@ -1909,20 +1909,18 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
        .get_modes = intel_sdvo_get_modes,
        .mode_valid = intel_sdvo_mode_valid,
-       .best_encoder = intel_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
 {
-       struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-
-       if (intel_sdvo->analog_ddc_bus)
-               intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
 
        if (intel_sdvo->sdvo_lvds_fixed_mode != NULL)
                drm_mode_destroy(encoder->dev,
                                 intel_sdvo->sdvo_lvds_fixed_mode);
 
+       i2c_del_adapter(&intel_sdvo->ddc);
        intel_encoder_destroy(encoder);
 }
 
@@ -1990,54 +1988,39 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
                intel_sdvo_guess_ddc_bus(sdvo);
 }
 
-static bool
-intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device)
+static void
+intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
+                         struct intel_sdvo *sdvo, u32 reg)
 {
-       return intel_sdvo_set_target_output(intel_sdvo,
-                                           device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1) &&
-               intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE,
-                                    &intel_sdvo->is_hdmi, 1);
-}
+       struct sdvo_device_mapping *mapping;
+       u8 pin, speed;
 
-static struct intel_sdvo *
-intel_sdvo_chan_to_intel_sdvo(struct intel_i2c_chan *chan)
-{
-       struct drm_device *dev = chan->drm_dev;
-       struct drm_encoder *encoder;
+       if (IS_SDVOB(reg))
+               mapping = &dev_priv->sdvo_mappings[0];
+       else
+               mapping = &dev_priv->sdvo_mappings[1];
 
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-               if (intel_sdvo->base.ddc_bus == &chan->adapter)
-                       return intel_sdvo;
+       pin = GMBUS_PORT_DPB;
+       speed = GMBUS_RATE_1MHZ >> 8;
+       if (mapping->initialized) {
+               pin = mapping->i2c_pin;
+               speed = mapping->i2c_speed;
        }
 
-       return NULL;
+       sdvo->i2c = &dev_priv->gmbus[pin].adapter;
+       intel_gmbus_set_speed(sdvo->i2c, speed);
+       intel_gmbus_force_bit(sdvo->i2c, true);
 }
 
-static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
-                                 struct i2c_msg msgs[], int num)
+static bool
+intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device)
 {
-       struct intel_sdvo *intel_sdvo;
-       struct i2c_algo_bit_data *algo_data;
-       const struct i2c_algorithm *algo;
-
-       algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
-       intel_sdvo =
-               intel_sdvo_chan_to_intel_sdvo((struct intel_i2c_chan *)
-                                             (algo_data->data));
-       if (intel_sdvo == NULL)
-               return -EINVAL;
-
-       algo = intel_sdvo->base.i2c_bus->algo;
-
-       intel_sdvo_set_control_bus_switch(intel_sdvo, intel_sdvo->ddc_bus);
-       return algo->master_xfer(i2c_adap, msgs, num);
+       return intel_sdvo_set_target_output(intel_sdvo,
+                                           device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1) &&
+               intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE,
+                                    &intel_sdvo->is_hdmi, 1);
 }
 
-static struct i2c_algorithm intel_sdvo_i2c_bit_algo = {
-       .master_xfer    = intel_sdvo_master_xfer,
-};
-
 static u8
 intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
 {
@@ -2076,26 +2059,29 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
 }
 
 static void
-intel_sdvo_connector_init(struct drm_encoder *encoder,
-                         struct drm_connector *connector)
+intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
+                         struct intel_sdvo *encoder)
 {
-       drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs,
-                          connector->connector_type);
+       drm_connector_init(encoder->base.base.dev,
+                          &connector->base.base,
+                          &intel_sdvo_connector_funcs,
+                          connector->base.base.connector_type);
 
-       drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
+       drm_connector_helper_add(&connector->base.base,
+                                &intel_sdvo_connector_helper_funcs);
 
-       connector->interlace_allowed = 0;
-       connector->doublescan_allowed = 0;
-       connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+       connector->base.base.interlace_allowed = 0;
+       connector->base.base.doublescan_allowed = 0;
+       connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
 
-       drm_mode_connector_attach_encoder(connector, encoder);
-       drm_sysfs_connector_add(connector);
+       intel_connector_attach_encoder(&connector->base, &encoder->base);
+       drm_sysfs_connector_add(&connector->base.base);
 }
 
 static bool
 intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
 {
-       struct drm_encoder *encoder = &intel_sdvo->base.enc;
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
        struct drm_connector *connector;
        struct intel_connector *intel_connector;
        struct intel_sdvo_connector *intel_sdvo_connector;
@@ -2130,7 +2116,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
        intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
                                       (1 << INTEL_ANALOG_CLONE_BIT));
 
-       intel_sdvo_connector_init(encoder, connector);
+       intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
 
        return true;
 }
@@ -2138,83 +2124,83 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
 static bool
 intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
 {
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *intel_sdvo_connector;
 
        intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
        if (!intel_sdvo_connector)
                return false;
 
        intel_connector = &intel_sdvo_connector->base;
-        connector = &intel_connector->base;
-        encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
-        connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+       connector = &intel_connector->base;
+       encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
+       connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
 
-        intel_sdvo->controlled_output |= type;
-        intel_sdvo_connector->output_flag = type;
+       intel_sdvo->controlled_output |= type;
+       intel_sdvo_connector->output_flag = type;
 
-        intel_sdvo->is_tv = true;
-        intel_sdvo->base.needs_tv_clock = true;
-        intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
+       intel_sdvo->is_tv = true;
+       intel_sdvo->base.needs_tv_clock = true;
+       intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
 
-        intel_sdvo_connector_init(encoder, connector);
+       intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
 
-        if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
+       if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
                goto err;
 
-        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+       if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
                goto err;
 
-        return true;
+       return true;
 
 err:
-       intel_sdvo_destroy_enhance_property(connector);
-       kfree(intel_sdvo_connector);
+       intel_sdvo_destroy(connector);
        return false;
 }
 
 static bool
 intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
 {
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *intel_sdvo_connector;
 
        intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
        if (!intel_sdvo_connector)
                return false;
 
        intel_connector = &intel_sdvo_connector->base;
-        connector = &intel_connector->base;
+       connector = &intel_connector->base;
        connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-        encoder->encoder_type = DRM_MODE_ENCODER_DAC;
-        connector->connector_type = DRM_MODE_CONNECTOR_VGA;
-
-        if (device == 0) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
-        } else if (device == 1) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
-        }
-
-        intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+       encoder->encoder_type = DRM_MODE_ENCODER_DAC;
+       connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+
+       if (device == 0) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
+       } else if (device == 1) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
+       }
+
+       intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
                                       (1 << INTEL_ANALOG_CLONE_BIT));
 
-        intel_sdvo_connector_init(encoder, connector);
-        return true;
+       intel_sdvo_connector_init(intel_sdvo_connector,
+                                 intel_sdvo);
+       return true;
 }
 
 static bool
 intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
 {
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
+       struct drm_encoder *encoder = &intel_sdvo->base.base;
+       struct drm_connector *connector;
+       struct intel_connector *intel_connector;
+       struct intel_sdvo_connector *intel_sdvo_connector;
 
        intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
        if (!intel_sdvo_connector)
@@ -2222,29 +2208,28 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
 
        intel_connector = &intel_sdvo_connector->base;
        connector = &intel_connector->base;
-        encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
-        connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
-
-        if (device == 0) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
-        } else if (device == 1) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
-        }
-
-        intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
+       encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+       connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+
+       if (device == 0) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
+       } else if (device == 1) {
+               intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
+               intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
+       }
+
+       intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
                                       (1 << INTEL_SDVO_LVDS_CLONE_BIT));
 
-        intel_sdvo_connector_init(encoder, connector);
-        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+       intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+       if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
                goto err;
 
        return true;
 
 err:
-       intel_sdvo_destroy_enhance_property(connector);
-       kfree(intel_sdvo_connector);
+       intel_sdvo_destroy(connector);
        return false;
 }
 
@@ -2309,7 +2294,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
                                          struct intel_sdvo_connector *intel_sdvo_connector,
                                          int type)
 {
-       struct drm_device *dev = intel_sdvo->base.enc.dev;
+       struct drm_device *dev = intel_sdvo->base.base.dev;
        struct intel_sdvo_tv_format format;
        uint32_t format_map, i;
 
@@ -2375,7 +2360,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
                                      struct intel_sdvo_connector *intel_sdvo_connector,
                                      struct intel_sdvo_enhancements_reply enhancements)
 {
-       struct drm_device *dev = intel_sdvo->base.enc.dev;
+       struct drm_device *dev = intel_sdvo->base.base.dev;
        struct drm_connector *connector = &intel_sdvo_connector->base.base;
        uint16_t response, data_value[2];
 
@@ -2504,7 +2489,7 @@ intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo,
                                        struct intel_sdvo_connector *intel_sdvo_connector,
                                        struct intel_sdvo_enhancements_reply enhancements)
 {
-       struct drm_device *dev = intel_sdvo->base.enc.dev;
+       struct drm_device *dev = intel_sdvo->base.base.dev;
        struct drm_connector *connector = &intel_sdvo_connector->base.base;
        uint16_t response, data_value[2];
 
@@ -2522,11 +2507,10 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
                uint16_t response;
        } enhancements;
 
-       if (!intel_sdvo_get_value(intel_sdvo,
-                                 SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
-                                 &enhancements, sizeof(enhancements)))
-               return false;
-
+       enhancements.response = 0;
+       intel_sdvo_get_value(intel_sdvo,
+                            SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
+                            &enhancements, sizeof(enhancements));
        if (enhancements.response == 0) {
                DRM_DEBUG_KMS("No enhancement is supported\n");
                return true;
@@ -2538,7 +2522,43 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
                return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply);
        else
                return true;
+}
+
+static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter,
+                                    struct i2c_msg *msgs,
+                                    int num)
+{
+       struct intel_sdvo *sdvo = adapter->algo_data;
+
+       if (!intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
+               return -EIO;
+
+       return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num);
+}
 
+static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter)
+{
+       struct intel_sdvo *sdvo = adapter->algo_data;
+       return sdvo->i2c->algo->functionality(sdvo->i2c);
+}
+
+static const struct i2c_algorithm intel_sdvo_ddc_proxy = {
+       .master_xfer    = intel_sdvo_ddc_proxy_xfer,
+       .functionality  = intel_sdvo_ddc_proxy_func
+};
+
+static bool
+intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
+                         struct drm_device *dev)
+{
+       sdvo->ddc.owner = THIS_MODULE;
+       sdvo->ddc.class = I2C_CLASS_DDC;
+       snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");
+       sdvo->ddc.dev.parent = &dev->pdev->dev;
+       sdvo->ddc.algo_data = sdvo;
+       sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
+
+       return i2c_add_adapter(&sdvo->ddc) == 0;
 }
 
 bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
@@ -2546,95 +2566,66 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *intel_encoder;
        struct intel_sdvo *intel_sdvo;
-       u8 ch[0x40];
        int i;
-       u32 i2c_reg, ddc_reg, analog_ddc_reg;
 
        intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
        if (!intel_sdvo)
                return false;
 
+       if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {
+               kfree(intel_sdvo);
+               return false;
+       }
+
        intel_sdvo->sdvo_reg = sdvo_reg;
 
        intel_encoder = &intel_sdvo->base;
        intel_encoder->type = INTEL_OUTPUT_SDVO;
+       /* encoder type will be decided later */
+       drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
 
-       if (HAS_PCH_SPLIT(dev)) {
-               i2c_reg = PCH_GPIOE;
-               ddc_reg = PCH_GPIOE;
-               analog_ddc_reg = PCH_GPIOA;
-       } else {
-               i2c_reg = GPIOE;
-               ddc_reg = GPIOE;
-               analog_ddc_reg = GPIOA;
-       }
-
-       /* setup the DDC bus. */
-       if (IS_SDVOB(sdvo_reg))
-               intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOB");
-       else
-               intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOC");
-
-       if (!intel_encoder->i2c_bus)
-               goto err_inteloutput;
-
-       intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg);
-
-       /* Save the bit-banging i2c functionality for use by the DDC wrapper */
-       intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality;
+       intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
+       intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
 
        /* Read the regs to test if we can talk to the device */
        for (i = 0; i < 0x40; i++) {
-               if (!intel_sdvo_read_byte(intel_sdvo, i, &ch[i])) {
+               u8 byte;
+
+               if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {
                        DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
                                      IS_SDVOB(sdvo_reg) ? 'B' : 'C');
-                       goto err_i2c;
+                       goto err;
                }
        }
 
-       /* setup the DDC bus. */
-       if (IS_SDVOB(sdvo_reg)) {
-               intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOB DDC BUS");
-               intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
-                                               "SDVOB/VGA DDC BUS");
+       if (IS_SDVOB(sdvo_reg))
                dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
-       } else {
-               intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOC DDC BUS");
-               intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
-                                               "SDVOC/VGA DDC BUS");
+       else
                dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
-       }
-       if (intel_encoder->ddc_bus == NULL || intel_sdvo->analog_ddc_bus == NULL)
-               goto err_i2c;
-
-       /* Wrap with our custom algo which switches to DDC mode */
-       intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
 
-       /* encoder type will be decided later */
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_sdvo_enc_funcs, 0);
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs);
+       drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
 
        /* In default case sdvo lvds is false */
        if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
-               goto err_enc;
+               goto err;
 
        if (intel_sdvo_output_setup(intel_sdvo,
                                    intel_sdvo->caps.output_flags) != true) {
                DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
                              IS_SDVOB(sdvo_reg) ? 'B' : 'C');
-               goto err_enc;
+               goto err;
        }
 
        intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
 
        /* Set the input timing to the screen. Assume always input 0. */
        if (!intel_sdvo_set_target_input(intel_sdvo))
-               goto err_enc;
+               goto err;
 
        if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
                                                    &intel_sdvo->pixel_clock_min,
                                                    &intel_sdvo->pixel_clock_max))
-               goto err_enc;
+               goto err;
 
        DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
                        "clock range %dMHz - %dMHz, "
@@ -2654,16 +2645,9 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
                        (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
        return true;
 
-err_enc:
-       drm_encoder_cleanup(&intel_encoder->enc);
-err_i2c:
-       if (intel_sdvo->analog_ddc_bus != NULL)
-               intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
-       if (intel_encoder->ddc_bus != NULL)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
-       if (intel_encoder->i2c_bus != NULL)
-               intel_i2c_destroy(intel_encoder->i2c_bus);
-err_inteloutput:
+err:
+       drm_encoder_cleanup(&intel_encoder->base);
+       i2c_del_adapter(&intel_sdvo->ddc);
        kfree(intel_sdvo);
 
        return false;
index 4a117e318a73a0a44c7ae4cc0be3447d11a403da..2f7681989316643149f2c11de896eef6936d884a 100644 (file)
@@ -48,7 +48,7 @@ struct intel_tv {
        struct intel_encoder base;
 
        int type;
-       char *tv_format;
+       const char *tv_format;
        int margin[4];
        u32 save_TV_H_CTL_1;
        u32 save_TV_H_CTL_2;
@@ -350,7 +350,7 @@ static const struct video_levels component_levels = {
 
 
 struct tv_mode {
-       char *name;
+       const char *name;
        int clock;
        int refresh; /* in millihertz (for precision) */
        u32 oversample;
@@ -900,7 +900,14 @@ static const struct tv_mode tv_modes[] = {
 
 static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder)
 {
-       return container_of(enc_to_intel_encoder(encoder), struct intel_tv, base);
+       return container_of(encoder, struct intel_tv, base.base);
+}
+
+static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
+{
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_tv,
+                           base);
 }
 
 static void
@@ -922,7 +929,7 @@ intel_tv_dpms(struct drm_encoder *encoder, int mode)
 }
 
 static const struct tv_mode *
-intel_tv_mode_lookup (char *tv_format)
+intel_tv_mode_lookup(const char *tv_format)
 {
        int i;
 
@@ -936,22 +943,23 @@ intel_tv_mode_lookup (char *tv_format)
 }
 
 static const struct tv_mode *
-intel_tv_mode_find (struct intel_tv *intel_tv)
+intel_tv_mode_find(struct intel_tv *intel_tv)
 {
        return intel_tv_mode_lookup(intel_tv->tv_format);
 }
 
 static enum drm_mode_status
-intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
+intel_tv_mode_valid(struct drm_connector *connector,
+                   struct drm_display_mode *mode)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 
        /* Ensure TV refresh is close to desired refresh */
        if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
                                < 1000)
                return MODE_OK;
+
        return MODE_CLOCK_RANGE;
 }
 
@@ -1131,7 +1139,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                           color_conversion->av);
        }
 
-       if (IS_I965G(dev))
+       if (INTEL_INFO(dev)->gen >= 4)
                I915_WRITE(TV_CLR_KNOBS, 0x00404000);
        else
                I915_WRITE(TV_CLR_KNOBS, 0x00606000);
@@ -1157,12 +1165,12 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
 
                /* Wait for vblank for the disable to take effect */
-               if (!IS_I9XX(dev))
+               if (IS_GEN2(dev))
                        intel_wait_for_vblank(dev, intel_crtc->pipe);
 
-               I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
+               I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE);
                /* Wait for vblank for the disable to take effect. */
-               intel_wait_for_vblank(dev, intel_crtc->pipe);
+               intel_wait_for_pipe_off(dev, intel_crtc->pipe);
 
                /* Filter ctl must be set before TV_WIN_SIZE */
                I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
@@ -1196,7 +1204,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
        for (i = 0; i < 43; i++)
                I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
-       I915_WRITE(TV_DAC, 0);
+       I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
        I915_WRITE(TV_CTL, tv_ctl);
 }
 
@@ -1228,15 +1236,13 @@ static const struct drm_display_mode reported_modes[] = {
 static int
 intel_tv_detect_type (struct intel_tv *intel_tv)
 {
-       struct drm_encoder *encoder = &intel_tv->base.enc;
+       struct drm_encoder *encoder = &intel_tv->base.base;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
        u32 tv_ctl, save_tv_ctl;
        u32 tv_dac, save_tv_dac;
-       int type = DRM_MODE_CONNECTOR_Unknown;
-
-       tv_dac = I915_READ(TV_DAC);
+       int type;
 
        /* Disable TV interrupts around load detect or we'll recurse */
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
@@ -1244,19 +1250,14 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
                              PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
        spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 
-       /*
-        * Detect TV by polling)
-        */
-       save_tv_dac = tv_dac;
-       tv_ctl = I915_READ(TV_CTL);
-       save_tv_ctl = tv_ctl;
-       tv_ctl &= ~TV_ENC_ENABLE;
-       tv_ctl &= ~TV_TEST_MODE_MASK;
+       save_tv_dac = tv_dac = I915_READ(TV_DAC);
+       save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
+
+       /* Poll for TV detection */
+       tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
        tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
-       tv_dac &= ~TVDAC_SENSE_MASK;
-       tv_dac &= ~DAC_A_MASK;
-       tv_dac &= ~DAC_B_MASK;
-       tv_dac &= ~DAC_C_MASK;
+
+       tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
        tv_dac |= (TVDAC_STATE_CHG_EN |
                   TVDAC_A_SENSE_CTL |
                   TVDAC_B_SENSE_CTL |
@@ -1265,37 +1266,40 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
                   DAC_A_0_7_V |
                   DAC_B_0_7_V |
                   DAC_C_0_7_V);
+
        I915_WRITE(TV_CTL, tv_ctl);
        I915_WRITE(TV_DAC, tv_dac);
        POSTING_READ(TV_DAC);
-       msleep(20);
 
-       tv_dac = I915_READ(TV_DAC);
-       I915_WRITE(TV_DAC, save_tv_dac);
-       I915_WRITE(TV_CTL, save_tv_ctl);
-       POSTING_READ(TV_CTL);
-       msleep(20);
+       intel_wait_for_vblank(intel_tv->base.base.dev,
+                             to_intel_crtc(intel_tv->base.base.crtc)->pipe);
 
-       /*
-        *  A B C
-        *  0 1 1 Composite
-        *  1 0 X svideo
-        *  0 0 0 Component
-        */
-       if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
-               DRM_DEBUG_KMS("Detected Composite TV connection\n");
-               type = DRM_MODE_CONNECTOR_Composite;
-       } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
-               DRM_DEBUG_KMS("Detected S-Video TV connection\n");
-               type = DRM_MODE_CONNECTOR_SVIDEO;
-       } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
-               DRM_DEBUG_KMS("Detected Component TV connection\n");
-               type = DRM_MODE_CONNECTOR_Component;
-       } else {
-               DRM_DEBUG_KMS("No TV connection detected\n");
-               type = -1;
+       type = -1;
+       if (wait_for((tv_dac = I915_READ(TV_DAC)) & TVDAC_STATE_CHG, 20) == 0) {
+               DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
+               /*
+                *  A B C
+                *  0 1 1 Composite
+                *  1 0 X svideo
+                *  0 0 0 Component
+                */
+               if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
+                       DRM_DEBUG_KMS("Detected Composite TV connection\n");
+                       type = DRM_MODE_CONNECTOR_Composite;
+               } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
+                       DRM_DEBUG_KMS("Detected S-Video TV connection\n");
+                       type = DRM_MODE_CONNECTOR_SVIDEO;
+               } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
+                       DRM_DEBUG_KMS("Detected Component TV connection\n");
+                       type = DRM_MODE_CONNECTOR_Component;
+               } else {
+                       DRM_DEBUG_KMS("Unrecognised TV connection\n");
+               }
        }
 
+       I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
+       I915_WRITE(TV_CTL, save_tv_ctl);
+
        /* Restore interrupt config */
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
        i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
@@ -1311,8 +1315,7 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
  */
 static void intel_tv_find_better_format(struct drm_connector *connector)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
        int i;
 
@@ -1344,14 +1347,13 @@ static enum drm_connector_status
 intel_tv_detect(struct drm_connector *connector, bool force)
 {
        struct drm_display_mode mode;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
        int type;
 
        mode = reported_modes[0];
        drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
 
-       if (encoder->crtc && encoder->crtc->enabled) {
+       if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
                type = intel_tv_detect_type(intel_tv);
        } else if (force) {
                struct drm_crtc *crtc;
@@ -1375,11 +1377,10 @@ intel_tv_detect(struct drm_connector *connector, bool force)
        return connector_status_connected;
 }
 
-static struct input_res {
-       char *name;
+static const struct input_res {
+       const char *name;
        int w, h;
-} input_res_table[] =
-{
+} input_res_table[] = {
        {"640x480", 640, 480},
        {"800x600", 800, 600},
        {"1024x768", 1024, 768},
@@ -1396,8 +1397,7 @@ static void
 intel_tv_chose_preferred_modes(struct drm_connector *connector,
                               struct drm_display_mode *mode_ptr)
 {
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 
        if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
@@ -1422,15 +1422,14 @@ static int
 intel_tv_get_modes(struct drm_connector *connector)
 {
        struct drm_display_mode *mode_ptr;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
        int j, count = 0;
        u64 tmp;
 
        for (j = 0; j < ARRAY_SIZE(input_res_table);
             j++) {
-               struct input_res *input = &input_res_table[j];
+               const struct input_res *input = &input_res_table[j];
                unsigned int hactive_s = input->w;
                unsigned int vactive_s = input->h;
 
@@ -1488,9 +1487,8 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
                      uint64_t val)
 {
        struct drm_device *dev = connector->dev;
-       struct drm_encoder *encoder = intel_attached_encoder(connector);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
-       struct drm_crtc *crtc = encoder->crtc;
+       struct intel_tv *intel_tv = intel_attached_tv(connector);
+       struct drm_crtc *crtc = intel_tv->base.base.crtc;
        int ret = 0;
        bool changed = false;
 
@@ -1555,7 +1553,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
        .mode_valid = intel_tv_mode_valid,
        .get_modes = intel_tv_get_modes,
-       .best_encoder = intel_attached_encoder,
+       .best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_tv_enc_funcs = {
@@ -1607,7 +1605,7 @@ intel_tv_init(struct drm_device *dev)
        struct intel_encoder *intel_encoder;
        struct intel_connector *intel_connector;
        u32 tv_dac_on, tv_dac_off, save_tv_dac;
-       char **tv_format_names;
+       char *tv_format_names[ARRAY_SIZE(tv_modes)];
        int i, initial_mode = 0;
 
        if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
@@ -1661,15 +1659,15 @@ intel_tv_init(struct drm_device *dev)
        drm_connector_init(dev, connector, &intel_tv_connector_funcs,
                           DRM_MODE_CONNECTOR_SVIDEO);
 
-       drm_encoder_init(dev, &intel_encoder->enc, &intel_tv_enc_funcs,
+       drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
                         DRM_MODE_ENCODER_TVDAC);
 
-       drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
+       intel_connector_attach_encoder(intel_connector, intel_encoder);
        intel_encoder->type = INTEL_OUTPUT_TVOUT;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
        intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
-       intel_encoder->enc.possible_crtcs = ((1 << 0) | (1 << 1));
-       intel_encoder->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
+       intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
+       intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
        intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
 
        /* BIOS margin values */
@@ -1678,21 +1676,19 @@ intel_tv_init(struct drm_device *dev)
        intel_tv->margin[TV_MARGIN_RIGHT] = 46;
        intel_tv->margin[TV_MARGIN_BOTTOM] = 37;
 
-       intel_tv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);
+       intel_tv->tv_format = tv_modes[initial_mode].name;
 
-       drm_encoder_helper_add(&intel_encoder->enc, &intel_tv_helper_funcs);
+       drm_encoder_helper_add(&intel_encoder->base, &intel_tv_helper_funcs);
        drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
        connector->interlace_allowed = false;
        connector->doublescan_allowed = false;
 
        /* Create TV properties then attach current values */
-       tv_format_names = kmalloc(sizeof(char *) * ARRAY_SIZE(tv_modes),
-                                 GFP_KERNEL);
-       if (!tv_format_names)
-               goto out;
        for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
-               tv_format_names[i] = tv_modes[i].name;
-       drm_mode_create_tv_properties(dev, ARRAY_SIZE(tv_modes), tv_format_names);
+               tv_format_names[i] = (char *)tv_modes[i].name;
+       drm_mode_create_tv_properties(dev,
+                                     ARRAY_SIZE(tv_modes),
+                                     tv_format_names);
 
        drm_connector_attach_property(connector, dev->mode_config.tv_mode_property,
                                   initial_mode);
@@ -1708,6 +1704,5 @@ intel_tv_init(struct drm_device *dev)
        drm_connector_attach_property(connector,
                                   dev->mode_config.tv_bottom_margin_property,
                                   intel_tv->margin[TV_MARGIN_BOTTOM]);
-out:
        drm_sysfs_connector_add(connector);
 }
index dbd30b2e43fd13b39aaa59eb0abc4fb0332bd1ee..d2047713dc59318fe94aff82eccf98bd28dd6841 100644 (file)
@@ -352,6 +352,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
 
        if (nouveau_fb->nvbo) {
                nouveau_bo_unmap(nouveau_fb->nvbo);
+               drm_gem_object_handle_unreference_unlocked(nouveau_fb->nvbo->gem);
                drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
                nouveau_fb->nvbo = NULL;
        }
index 1e630987543e93709f827eb181c3373366044483..5c4c929d7f744d6911c1a16b67924ab770b6de5c 100644 (file)
@@ -167,11 +167,9 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
                goto out;
 
        ret = drm_gem_handle_create(file_priv, nvbo->gem, &req->info.handle);
+       /* drop reference from allocate - handle holds it now */
+       drm_gem_object_unreference_unlocked(nvbo->gem);
 out:
-       drm_gem_object_handle_unreference_unlocked(nvbo->gem);
-
-       if (ret)
-               drm_gem_object_unreference_unlocked(nvbo->gem);
        return ret;
 }
 
index 2cc59f8c658bd63b840fbf35c7871d090a587d95..d670839cb34dffafa7d3275b31a08dc743bb716c 100644 (file)
@@ -80,6 +80,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
        mutex_lock(&dev->struct_mutex);
        nouveau_bo_unpin(chan->notifier_bo);
        mutex_unlock(&dev->struct_mutex);
+       drm_gem_object_handle_unreference_unlocked(chan->notifier_bo->gem);
        drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
        drm_mm_takedown(&chan->notifier_heap);
 }
index 1bc72c3190a9dcfe9b8f70f16087a231560d9b08..fe359a239df343437cce0b0c79d2692c559ffb9e 100644 (file)
@@ -4999,7 +4999,7 @@ typedef struct _SW_I2C_IO_DATA_PARAMETERS
 #define SW_I2C_CNTL_WRITE1BIT 6
 
 //==============================VESA definition Portion===============================
-#define VESA_OEM_PRODUCT_REV                               '01.00'
+#define VESA_OEM_PRODUCT_REV                               "01.00"
 #define VESA_MODE_ATTRIBUTE_MODE_SUPPORT            0xBB       //refer to VBE spec p.32, no TTY support
 #define VESA_MODE_WIN_ATTRIBUTE                                                     7
 #define VESA_WIN_SIZE                                                                                       64
index afc18d87fdca7409e4c7462fe3a1b03eeaa6d3ca..7a04959ba0eefacad6ab9894cb1d5732bbf4677e 100644 (file)
@@ -2729,7 +2729,7 @@ int r600_ib_test(struct radeon_device *rdev)
        if (i < rdev->usec_timeout) {
                DRM_INFO("ib test succeeded in %u usecs\n", i);
        } else {
-               DRM_ERROR("radeon: ib test failed (sracth(0x%04X)=0x%08X)\n",
+               DRM_ERROR("radeon: ib test failed (scratch(0x%04X)=0x%08X)\n",
                          scratch, tmp);
                r = -EINVAL;
        }
@@ -3528,7 +3528,8 @@ void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo)
        /* r7xx hw bug.  write to HDP_DEBUG1 followed by fb read
         * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
         */
-       if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) {
+       if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) &&
+           rdev->vram_scratch.ptr) {
                void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
                u32 tmp;
 
index ebae14c4b768b4413990e84c1055782a72590009..68932ba7b8a47d0e7a360be37fb38f16075e4d3b 100644 (file)
@@ -317,6 +317,15 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
                        *connector_type = DRM_MODE_CONNECTOR_DVID;
        }
 
+       /* MSI K9A2GM V2/V3 board has no HDMI or DVI */
+       if ((dev->pdev->device == 0x796e) &&
+           (dev->pdev->subsystem_vendor == 0x1462) &&
+           (dev->pdev->subsystem_device == 0x7302)) {
+               if ((supported_device == ATOM_DEVICE_DFP2_SUPPORT) ||
+                   (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
+                       return false;
+       }
+
        /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
        if ((dev->pdev->device == 0x7941) &&
            (dev->pdev->subsystem_vendor == 0x147b) &&
index 127a395f70fb304d6f4d0df613de1fdfc8ca1223..b92d2f2fcbed6a8bd472ce9f4b936aa82f309278 100644 (file)
@@ -349,6 +349,8 @@ static void radeon_print_display_setup(struct drm_device *dev)
                                        DRM_INFO("    DFP4: %s\n", encoder_names[radeon_encoder->encoder_id]);
                                if (devices & ATOM_DEVICE_DFP5_SUPPORT)
                                        DRM_INFO("    DFP5: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                               if (devices & ATOM_DEVICE_DFP6_SUPPORT)
+                                       DRM_INFO("    DFP6: %s\n", encoder_names[radeon_encoder->encoder_id]);
                                if (devices & ATOM_DEVICE_TV1_SUPPORT)
                                        DRM_INFO("    TV1: %s\n", encoder_names[radeon_encoder->encoder_id]);
                                if (devices & ATOM_DEVICE_CV_SUPPORT)
@@ -841,8 +843,9 @@ static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
        struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
 
-       if (radeon_fb->obj)
+       if (radeon_fb->obj) {
                drm_gem_object_unreference_unlocked(radeon_fb->obj);
+       }
        drm_framebuffer_cleanup(fb);
        kfree(radeon_fb);
 }
index c74a8b20d9413e921bc6a03cd92578146a9ee8ef..9cdf6a35bc2c3f4efbd5daab2a9506078308aa31 100644 (file)
@@ -94,8 +94,10 @@ static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj)
        ret = radeon_bo_reserve(rbo, false);
        if (likely(ret == 0)) {
                radeon_bo_kunmap(rbo);
+               radeon_bo_unpin(rbo);
                radeon_bo_unreserve(rbo);
        }
+       drm_gem_object_handle_unreference(gobj);
        drm_gem_object_unreference_unlocked(gobj);
 }
 
@@ -325,8 +327,6 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb
 {
        struct fb_info *info;
        struct radeon_framebuffer *rfb = &rfbdev->rfb;
-       struct radeon_bo *rbo;
-       int r;
 
        if (rfbdev->helper.fbdev) {
                info = rfbdev->helper.fbdev;
@@ -338,14 +338,8 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb
        }
 
        if (rfb->obj) {
-               rbo = rfb->obj->driver_private;
-               r = radeon_bo_reserve(rbo, false);
-               if (likely(r == 0)) {
-                       radeon_bo_kunmap(rbo);
-                       radeon_bo_unpin(rbo);
-                       radeon_bo_unreserve(rbo);
-               }
-               drm_gem_object_unreference_unlocked(rfb->obj);
+               radeonfb_destroy_pinned_object(rfb->obj);
+               rfb->obj = NULL;
        }
        drm_fb_helper_fini(&rfbdev->helper);
        drm_framebuffer_cleanup(&rfb->base);
index c578f265b24cefc6dce21734783b01c1aed1ce27..d1e595d9172396b8104d19c7a1d0a87d3b14b772 100644 (file)
@@ -201,11 +201,11 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
                return r;
        }
        r = drm_gem_handle_create(filp, gobj, &handle);
+       /* drop reference from allocate - handle holds it now */
+       drm_gem_object_unreference_unlocked(gobj);
        if (r) {
-               drm_gem_object_unreference_unlocked(gobj);
                return r;
        }
-       drm_gem_object_handle_unreference_unlocked(gobj);
        args->handle = handle;
        return 0;
 }
index 5eee3c41d124bf49fbd5dfbc7264fb062699e961..8fbbe1c6ebbda854f7bf9dc9f76ae1c4eefdafc5 100644 (file)
@@ -203,6 +203,10 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
  */
 int radeon_driver_firstopen_kms(struct drm_device *dev)
 {
+       struct radeon_device *rdev = dev->dev_private;
+
+       if (rdev->powered_down)
+               return -EINVAL;
        return 0;
 }
 
index c9d2d4d8d066bc54606f85d10b208ac1333519dd..ff358ad45aa3e8a022739bbbcaa96d3b8ea1ccfa 100644 (file)
@@ -343,6 +343,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
        INIT_LIST_HEAD(&fbo->lru);
        INIT_LIST_HEAD(&fbo->swap);
        fbo->vm_node = NULL;
+       atomic_set(&fbo->cpu_writers, 0);
 
        fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj);
        kref_init(&fbo->list_kref);
index ca904799f018a6e3ae23c80933bd1e007aec8f7f..b1e02fffd3ccdebf256d38bb55bed9a37ea1c8d7 100644 (file)
@@ -69,7 +69,7 @@ struct ttm_page_pool {
        spinlock_t              lock;
        bool                    fill_lock;
        struct list_head        list;
-       int                     gfp_flags;
+       gfp_t                   gfp_flags;
        unsigned                npages;
        char                    *name;
        unsigned long           nfrees;
@@ -475,7 +475,7 @@ static void ttm_handle_caching_state_failure(struct list_head *pages,
  * This function is reentrant if caller updates count depending on number of
  * pages returned in pages array.
  */
-static int ttm_alloc_new_pages(struct list_head *pages, int gfp_flags,
+static int ttm_alloc_new_pages(struct list_head *pages, gfp_t gfp_flags,
                int ttm_flags, enum ttm_caching_state cstate, unsigned count)
 {
        struct page **caching_array;
@@ -666,7 +666,7 @@ int ttm_get_pages(struct list_head *pages, int flags,
 {
        struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
        struct page *p = NULL;
-       int gfp_flags = GFP_USER;
+       gfp_t gfp_flags = GFP_USER;
        int r;
 
        /* set zero flag for page allocation if required */
@@ -818,7 +818,7 @@ int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages)
        return 0;
 }
 
-void ttm_page_alloc_fini()
+void ttm_page_alloc_fini(void)
 {
        int i;
 
index e645f44e43020c45984e576bf64b4f767ada9a9b..f2942b3c59c0f501605b7759708c21fcff464e9d 100644 (file)
@@ -148,13 +148,16 @@ static struct pci_device_id vmw_pci_id_list[] = {
        {0, 0, 0}
 };
 
-static char *vmw_devname = "vmwgfx";
+static int enable_fbdev;
 
 static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
 static void vmw_master_init(struct vmw_master *);
 static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
                              void *ptr);
 
+MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev");
+module_param_named(enable_fbdev, enable_fbdev, int, 0600);
+
 static void vmw_print_capabilities(uint32_t capabilities)
 {
        DRM_INFO("Capabilities:\n");
@@ -192,8 +195,6 @@ static int vmw_request_device(struct vmw_private *dev_priv)
 {
        int ret;
 
-       vmw_kms_save_vga(dev_priv);
-
        ret = vmw_fifo_init(dev_priv, &dev_priv->fifo);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Unable to initialize FIFO.\n");
@@ -206,10 +207,36 @@ static int vmw_request_device(struct vmw_private *dev_priv)
 static void vmw_release_device(struct vmw_private *dev_priv)
 {
        vmw_fifo_release(dev_priv, &dev_priv->fifo);
-       vmw_kms_restore_vga(dev_priv);
+}
+
+int vmw_3d_resource_inc(struct vmw_private *dev_priv)
+{
+       int ret = 0;
+
+       mutex_lock(&dev_priv->release_mutex);
+       if (unlikely(dev_priv->num_3d_resources++ == 0)) {
+               ret = vmw_request_device(dev_priv);
+               if (unlikely(ret != 0))
+                       --dev_priv->num_3d_resources;
+       }
+       mutex_unlock(&dev_priv->release_mutex);
+       return ret;
 }
 
 
+void vmw_3d_resource_dec(struct vmw_private *dev_priv)
+{
+       int32_t n3d;
+
+       mutex_lock(&dev_priv->release_mutex);
+       if (unlikely(--dev_priv->num_3d_resources == 0))
+               vmw_release_device(dev_priv);
+       n3d = (int32_t) dev_priv->num_3d_resources;
+       mutex_unlock(&dev_priv->release_mutex);
+
+       BUG_ON(n3d < 0);
+}
+
 static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 {
        struct vmw_private *dev_priv;
@@ -228,6 +255,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        dev_priv->last_read_sequence = (uint32_t) -100;
        mutex_init(&dev_priv->hw_mutex);
        mutex_init(&dev_priv->cmdbuf_mutex);
+       mutex_init(&dev_priv->release_mutex);
        rwlock_init(&dev_priv->resource_lock);
        idr_init(&dev_priv->context_idr);
        idr_init(&dev_priv->surface_idr);
@@ -244,6 +272,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
        dev_priv->mmio_start = pci_resource_start(dev->pdev, 2);
 
+       dev_priv->enable_fb = enable_fbdev;
+
        mutex_lock(&dev_priv->hw_mutex);
 
        vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
@@ -343,17 +373,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 
        dev->dev_private = dev_priv;
 
-       if (!dev->devname)
-               dev->devname = vmw_devname;
-
-       if (dev_priv->capabilities & SVGA_CAP_IRQMASK) {
-               ret = drm_irq_install(dev);
-               if (unlikely(ret != 0)) {
-                       DRM_ERROR("Failed installing irq: %d\n", ret);
-                       goto out_no_irq;
-               }
-       }
-
        ret = pci_request_regions(dev->pdev, "vmwgfx probe");
        dev_priv->stealth = (ret != 0);
        if (dev_priv->stealth) {
@@ -369,26 +388,52 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                        goto out_no_device;
                }
        }
-       ret = vmw_request_device(dev_priv);
+       ret = vmw_kms_init(dev_priv);
        if (unlikely(ret != 0))
-               goto out_no_device;
-       vmw_kms_init(dev_priv);
+               goto out_no_kms;
        vmw_overlay_init(dev_priv);
-       vmw_fb_init(dev_priv);
+       if (dev_priv->enable_fb) {
+               ret = vmw_3d_resource_inc(dev_priv);
+               if (unlikely(ret != 0))
+                       goto out_no_fifo;
+               vmw_kms_save_vga(dev_priv);
+               vmw_fb_init(dev_priv);
+               DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ?
+                        "Detected device 3D availability.\n" :
+                        "Detected no device 3D availability.\n");
+       } else {
+               DRM_INFO("Delayed 3D detection since we're not "
+                        "running the device in SVGA mode yet.\n");
+       }
+
+       if (dev_priv->capabilities & SVGA_CAP_IRQMASK) {
+               ret = drm_irq_install(dev);
+               if (unlikely(ret != 0)) {
+                       DRM_ERROR("Failed installing irq: %d\n", ret);
+                       goto out_no_irq;
+               }
+       }
 
        dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier;
        register_pm_notifier(&dev_priv->pm_nb);
 
-       DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ? "Have 3D\n" : "No 3D\n");
-
        return 0;
 
-out_no_device:
-       if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
-               drm_irq_uninstall(dev_priv->dev);
-       if (dev->devname == vmw_devname)
-               dev->devname = NULL;
 out_no_irq:
+       if (dev_priv->enable_fb) {
+               vmw_fb_close(dev_priv);
+               vmw_kms_restore_vga(dev_priv);
+               vmw_3d_resource_dec(dev_priv);
+       }
+out_no_fifo:
+       vmw_overlay_close(dev_priv);
+       vmw_kms_close(dev_priv);
+out_no_kms:
+       if (dev_priv->stealth)
+               pci_release_region(dev->pdev, 2);
+       else
+               pci_release_regions(dev->pdev);
+out_no_device:
        ttm_object_device_release(&dev_priv->tdev);
 out_err4:
        iounmap(dev_priv->mmio_virt);
@@ -415,19 +460,20 @@ static int vmw_driver_unload(struct drm_device *dev)
 
        unregister_pm_notifier(&dev_priv->pm_nb);
 
-       vmw_fb_close(dev_priv);
+       if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
+               drm_irq_uninstall(dev_priv->dev);
+       if (dev_priv->enable_fb) {
+               vmw_fb_close(dev_priv);
+               vmw_kms_restore_vga(dev_priv);
+               vmw_3d_resource_dec(dev_priv);
+       }
        vmw_kms_close(dev_priv);
        vmw_overlay_close(dev_priv);
-       vmw_release_device(dev_priv);
        if (dev_priv->stealth)
                pci_release_region(dev->pdev, 2);
        else
                pci_release_regions(dev->pdev);
 
-       if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
-               drm_irq_uninstall(dev_priv->dev);
-       if (dev->devname == vmw_devname)
-               dev->devname = NULL;
        ttm_object_device_release(&dev_priv->tdev);
        iounmap(dev_priv->mmio_virt);
        drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
@@ -500,7 +546,7 @@ static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
                struct drm_ioctl_desc *ioctl =
                    &vmw_ioctls[nr - DRM_COMMAND_BASE];
 
-               if (unlikely(ioctl->cmd != cmd)) {
+               if (unlikely(ioctl->cmd_drv != cmd)) {
                        DRM_ERROR("Invalid command format, ioctl %d\n",
                                  nr - DRM_COMMAND_BASE);
                        return -EINVAL;
@@ -551,6 +597,8 @@ static void vmw_lastclose(struct drm_device *dev)
 static void vmw_master_init(struct vmw_master *vmaster)
 {
        ttm_lock_init(&vmaster->lock);
+       INIT_LIST_HEAD(&vmaster->fb_surf);
+       mutex_init(&vmaster->fb_surf_mutex);
 }
 
 static int vmw_master_create(struct drm_device *dev,
@@ -562,7 +610,7 @@ static int vmw_master_create(struct drm_device *dev,
        if (unlikely(vmaster == NULL))
                return -ENOMEM;
 
-       ttm_lock_init(&vmaster->lock);
+       vmw_master_init(vmaster);
        ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
        master->driver_priv = vmaster;
 
@@ -589,6 +637,16 @@ static int vmw_master_set(struct drm_device *dev,
        struct vmw_master *vmaster = vmw_master(file_priv->master);
        int ret = 0;
 
+       if (!dev_priv->enable_fb) {
+               ret = vmw_3d_resource_inc(dev_priv);
+               if (unlikely(ret != 0))
+                       return ret;
+               vmw_kms_save_vga(dev_priv);
+               mutex_lock(&dev_priv->hw_mutex);
+               vmw_write(dev_priv, SVGA_REG_TRACES, 0);
+               mutex_unlock(&dev_priv->hw_mutex);
+       }
+
        if (active) {
                BUG_ON(active != &dev_priv->fbdev_master);
                ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile);
@@ -617,7 +675,13 @@ static int vmw_master_set(struct drm_device *dev,
        return 0;
 
 out_no_active_lock:
-       vmw_release_device(dev_priv);
+       if (!dev_priv->enable_fb) {
+               mutex_lock(&dev_priv->hw_mutex);
+               vmw_write(dev_priv, SVGA_REG_TRACES, 1);
+               mutex_unlock(&dev_priv->hw_mutex);
+               vmw_kms_restore_vga(dev_priv);
+               vmw_3d_resource_dec(dev_priv);
+       }
        return ret;
 }
 
@@ -637,6 +701,7 @@ static void vmw_master_drop(struct drm_device *dev,
 
        vmw_fp->locked_master = drm_master_get(file_priv->master);
        ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
+       vmw_kms_idle_workqueues(vmaster);
 
        if (unlikely((ret != 0))) {
                DRM_ERROR("Unable to lock TTM at VT switch.\n");
@@ -645,11 +710,23 @@ static void vmw_master_drop(struct drm_device *dev,
 
        ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
 
+       if (!dev_priv->enable_fb) {
+               ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM);
+               if (unlikely(ret != 0))
+                       DRM_ERROR("Unable to clean VRAM on master drop.\n");
+               mutex_lock(&dev_priv->hw_mutex);
+               vmw_write(dev_priv, SVGA_REG_TRACES, 1);
+               mutex_unlock(&dev_priv->hw_mutex);
+               vmw_kms_restore_vga(dev_priv);
+               vmw_3d_resource_dec(dev_priv);
+       }
+
        dev_priv->active_master = &dev_priv->fbdev_master;
        ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
        ttm_vt_unlock(&dev_priv->fbdev_master.lock);
 
-       vmw_fb_on(dev_priv);
+       if (dev_priv->enable_fb)
+               vmw_fb_on(dev_priv);
 }
 
 
@@ -677,15 +754,16 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
                 * Buffer contents is moved to swappable memory.
                 */
                ttm_bo_swapout_all(&dev_priv->bdev);
+
                break;
        case PM_POST_HIBERNATION:
        case PM_POST_SUSPEND:
+       case PM_POST_RESTORE:
                ttm_suspend_unlock(&vmaster->lock);
+
                break;
        case PM_RESTORE_PREPARE:
                break;
-       case PM_POST_RESTORE:
-               break;
        default:
                break;
        }
@@ -696,21 +774,98 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
  * These might not be needed with the virtual SVGA device.
  */
 
-int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct vmw_private *dev_priv = vmw_priv(dev);
+
+       if (dev_priv->num_3d_resources != 0) {
+               DRM_INFO("Can't suspend or hibernate "
+                        "while 3D resources are active.\n");
+               return -EBUSY;
+       }
+
        pci_save_state(pdev);
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
        return 0;
 }
 
-int vmw_pci_resume(struct pci_dev *pdev)
+static int vmw_pci_resume(struct pci_dev *pdev)
 {
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        return pci_enable_device(pdev);
 }
 
+static int vmw_pm_suspend(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct pm_message dummy;
+
+       dummy.event = 0;
+
+       return vmw_pci_suspend(pdev, dummy);
+}
+
+static int vmw_pm_resume(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+
+       return vmw_pci_resume(pdev);
+}
+
+static int vmw_pm_prepare(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct vmw_private *dev_priv = vmw_priv(dev);
+
+       /**
+        * Release 3d reference held by fbdev and potentially
+        * stop fifo.
+        */
+       dev_priv->suspended = true;
+       if (dev_priv->enable_fb)
+               vmw_3d_resource_dec(dev_priv);
+
+       if (dev_priv->num_3d_resources != 0) {
+
+               DRM_INFO("Can't suspend or hibernate "
+                        "while 3D resources are active.\n");
+
+               if (dev_priv->enable_fb)
+                       vmw_3d_resource_inc(dev_priv);
+               dev_priv->suspended = false;
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static void vmw_pm_complete(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct vmw_private *dev_priv = vmw_priv(dev);
+
+       /**
+        * Reclaim 3d reference held by fbdev and potentially
+        * start fifo.
+        */
+       if (dev_priv->enable_fb)
+               vmw_3d_resource_inc(dev_priv);
+
+       dev_priv->suspended = false;
+}
+
+static const struct dev_pm_ops vmw_pm_ops = {
+       .prepare = vmw_pm_prepare,
+       .complete = vmw_pm_complete,
+       .suspend = vmw_pm_suspend,
+       .resume = vmw_pm_resume,
+};
+
 static struct drm_driver driver = {
        .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
        DRIVER_MODESET,
@@ -722,6 +877,7 @@ static struct drm_driver driver = {
        .irq_postinstall = vmw_irq_postinstall,
        .irq_uninstall = vmw_irq_uninstall,
        .irq_handler = vmw_irq_handler,
+       .get_vblank_counter = vmw_get_vblank_counter,
        .reclaim_buffers_locked = NULL,
        .ioctls = vmw_ioctls,
        .num_ioctls = DRM_ARRAY_SIZE(vmw_ioctls),
@@ -743,15 +899,16 @@ static struct drm_driver driver = {
 #if defined(CONFIG_COMPAT)
                 .compat_ioctl = drm_compat_ioctl,
 #endif
-                },
+       },
        .pci_driver = {
-                      .name = VMWGFX_DRIVER_NAME,
-                      .id_table = vmw_pci_id_list,
-                      .probe = vmw_probe,
-                      .remove = vmw_remove,
-                      .suspend = vmw_pci_suspend,
-                      .resume = vmw_pci_resume
-                      },
+                .name = VMWGFX_DRIVER_NAME,
+                .id_table = vmw_pci_id_list,
+                .probe = vmw_probe,
+                .remove = vmw_remove,
+                .driver = {
+                        .pm = &vmw_pm_ops
+                }
+        },
        .name = VMWGFX_DRIVER_NAME,
        .desc = VMWGFX_DRIVER_DESC,
        .date = VMWGFX_DRIVER_DATE,
@@ -785,3 +942,7 @@ module_exit(vmwgfx_exit);
 MODULE_AUTHOR("VMware Inc. and others");
 MODULE_DESCRIPTION("Standalone drm driver for the VMware SVGA device");
 MODULE_LICENSE("GPL and additional rights");
+MODULE_VERSION(__stringify(VMWGFX_DRIVER_MAJOR) "."
+              __stringify(VMWGFX_DRIVER_MINOR) "."
+              __stringify(VMWGFX_DRIVER_PATCHLEVEL) "."
+              "0");
index 429f917b60bf4b30ecdfd0946f9f1f0978bd5c58..9d55fa8cd0fe52c83f7d9c46d9432160a2bc1820 100644 (file)
@@ -39,9 +39,9 @@
 #include "ttm/ttm_execbuf_util.h"
 #include "ttm/ttm_module.h"
 
-#define VMWGFX_DRIVER_DATE "20100209"
+#define VMWGFX_DRIVER_DATE "20100927"
 #define VMWGFX_DRIVER_MAJOR 1
-#define VMWGFX_DRIVER_MINOR 2
+#define VMWGFX_DRIVER_MINOR 4
 #define VMWGFX_DRIVER_PATCHLEVEL 0
 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000
 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
@@ -151,6 +151,8 @@ struct vmw_overlay;
 
 struct vmw_master {
        struct ttm_lock lock;
+       struct mutex fb_surf_mutex;
+       struct list_head fb_surf;
 };
 
 struct vmw_vga_topology_state {
@@ -277,6 +279,7 @@ struct vmw_private {
 
        bool stealth;
        bool is_opened;
+       bool enable_fb;
 
        /**
         * Master management.
@@ -285,6 +288,10 @@ struct vmw_private {
        struct vmw_master *active_master;
        struct vmw_master fbdev_master;
        struct notifier_block pm_nb;
+       bool suspended;
+
+       struct mutex release_mutex;
+       uint32_t num_3d_resources;
 };
 
 static inline struct vmw_private *vmw_priv(struct drm_device *dev)
@@ -319,6 +326,9 @@ static inline uint32_t vmw_read(struct vmw_private *dev_priv,
        return val;
 }
 
+int vmw_3d_resource_inc(struct vmw_private *dev_priv);
+void vmw_3d_resource_dec(struct vmw_private *dev_priv);
+
 /**
  * GMR utilities - vmwgfx_gmr.c
  */
@@ -511,6 +521,11 @@ void vmw_kms_write_svga(struct vmw_private *vmw_priv,
                        unsigned bbp, unsigned depth);
 int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
+void vmw_kms_idle_workqueues(struct vmw_master *vmaster);
+bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
+                               uint32_t pitch,
+                               uint32_t height);
+u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc);
 
 /**
  * Overlay control - vmwgfx_overlay.c
index 870967a97c15d52eb3f380323e6038d32ed6e76f..e7304188a784da8d8b1e850c1e4b3a06978c0995 100644 (file)
@@ -144,6 +144,13 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var,
                return -EINVAL;
        }
 
+       if (!vmw_kms_validate_mode_vram(vmw_priv,
+                                       info->fix.line_length,
+                                       var->yoffset + var->yres)) {
+               DRM_ERROR("Requested geom can not fit in framebuffer\n");
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -205,6 +212,9 @@ static void vmw_fb_dirty_flush(struct vmw_fb_par *par)
                SVGAFifoCmdUpdate body;
        } *cmd;
 
+       if (vmw_priv->suspended)
+               return;
+
        spin_lock_irqsave(&par->dirty.lock, flags);
        if (!par->dirty.active) {
                spin_unlock_irqrestore(&par->dirty.lock, flags);
@@ -602,6 +612,7 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
 {
        struct ttm_buffer_object *bo = &vmw_bo->base;
        struct ttm_placement ne_placement = vmw_vram_ne_placement;
+       struct drm_mm_node *mm_node;
        int ret = 0;
 
        ne_placement.lpfn = bo->num_pages;
@@ -615,6 +626,12 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
        if (unlikely(ret != 0))
                goto err_unlock;
 
+       mm_node = bo->mem.mm_node;
+       if (bo->mem.mem_type == TTM_PL_VRAM &&
+           mm_node->start < bo->num_pages)
+               (void) ttm_bo_validate(bo, &vmw_sys_placement, false,
+                                      false, false);
+
        ret = ttm_bo_validate(bo, &ne_placement, false, false, false);
 
        /* Could probably bug on */
index e6a1eb7ea95498f00e65d123adeae79160af8fa8..0fe31766e4cf5f11e6025e5a85f96baa5936408f 100644 (file)
@@ -106,6 +106,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
        mutex_lock(&dev_priv->hw_mutex);
        dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE);
        dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE);
+       dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES);
        vmw_write(dev_priv, SVGA_REG_ENABLE, 1);
 
        min = 4;
@@ -175,6 +176,8 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
                  dev_priv->config_done_state);
        vmw_write(dev_priv, SVGA_REG_ENABLE,
                  dev_priv->enable_state);
+       vmw_write(dev_priv, SVGA_REG_TRACES,
+                 dev_priv->traces_state);
 
        mutex_unlock(&dev_priv->hw_mutex);
        vmw_fence_queue_takedown(&fifo->fence_queue);
index 1c7a316454d80ceb9aaeb6c83d6ac6a82f1cae1f..570d57775a58de0eebf9574f5ce3782fafcae508 100644 (file)
@@ -54,6 +54,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
        case DRM_VMW_PARAM_FIFO_CAPS:
                param->value = dev_priv->fifo.capabilities;
                break;
+       case DRM_VMW_PARAM_MAX_FB_SIZE:
+               param->value = dev_priv->vram_size;
+               break;
        default:
                DRM_ERROR("Illegal vmwgfx get param request: %d\n",
                          param->param);
index 64d7f47df8683ef49cfbb3c83eb449026949af03..87c6e6156d7de8bc809a62bab06dbf64a7da512b 100644 (file)
@@ -332,18 +332,55 @@ struct vmw_framebuffer_surface {
        struct delayed_work d_work;
        struct mutex work_lock;
        bool present_fs;
+       struct list_head head;
+       struct drm_master *master;
 };
 
+/**
+ * vmw_kms_idle_workqueues - Flush workqueues on this master
+ *
+ * @vmaster - Pointer identifying the master, for the surfaces of which
+ * we idle the dirty work queues.
+ *
+ * This function should be called with the ttm lock held in exclusive mode
+ * to idle all dirty work queues before the fifo is taken down.
+ *
+ * The work task may actually requeue itself, but after the flush returns we're
+ * sure that there's nothing to present, since the ttm lock is held in
+ * exclusive mode, so the fifo will never get used.
+ */
+
+void vmw_kms_idle_workqueues(struct vmw_master *vmaster)
+{
+       struct vmw_framebuffer_surface *entry;
+
+       mutex_lock(&vmaster->fb_surf_mutex);
+       list_for_each_entry(entry, &vmaster->fb_surf, head) {
+               if (cancel_delayed_work_sync(&entry->d_work))
+                       (void) entry->d_work.work.func(&entry->d_work.work);
+
+               (void) cancel_delayed_work_sync(&entry->d_work);
+       }
+       mutex_unlock(&vmaster->fb_surf_mutex);
+}
+
 void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
 {
-       struct vmw_framebuffer_surface *vfb =
+       struct vmw_framebuffer_surface *vfbs =
                vmw_framebuffer_to_vfbs(framebuffer);
+       struct vmw_master *vmaster = vmw_master(vfbs->master);
+
 
-       cancel_delayed_work_sync(&vfb->d_work);
+       mutex_lock(&vmaster->fb_surf_mutex);
+       list_del(&vfbs->head);
+       mutex_unlock(&vmaster->fb_surf_mutex);
+
+       cancel_delayed_work_sync(&vfbs->d_work);
+       drm_master_put(&vfbs->master);
        drm_framebuffer_cleanup(framebuffer);
-       vmw_surface_unreference(&vfb->surface);
+       vmw_surface_unreference(&vfbs->surface);
 
-       kfree(framebuffer);
+       kfree(vfbs);
 }
 
 static void vmw_framebuffer_present_fs_callback(struct work_struct *work)
@@ -362,6 +399,12 @@ static void vmw_framebuffer_present_fs_callback(struct work_struct *work)
                SVGA3dCopyRect cr;
        } *cmd;
 
+       /**
+        * Strictly we should take the ttm_lock in read mode before accessing
+        * the fifo, to make sure the fifo is present and up. However,
+        * instead we flush all workqueues under the ttm lock in exclusive mode
+        * before taking down the fifo.
+        */
        mutex_lock(&vfbs->work_lock);
        if (!vfbs->present_fs)
                goto out_unlock;
@@ -392,17 +435,20 @@ out_unlock:
 
 
 int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
+                                 struct drm_file *file_priv,
                                  unsigned flags, unsigned color,
                                  struct drm_clip_rect *clips,
                                  unsigned num_clips)
 {
        struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct vmw_framebuffer_surface *vfbs =
                vmw_framebuffer_to_vfbs(framebuffer);
        struct vmw_surface *surf = vfbs->surface;
        struct drm_clip_rect norect;
        SVGA3dCopyRect *cr;
        int i, inc = 1;
+       int ret;
 
        struct {
                SVGA3dCmdHeader header;
@@ -410,6 +456,13 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
                SVGA3dCopyRect cr;
        } *cmd;
 
+       if (unlikely(vfbs->master != file_priv->master))
+               return -EINVAL;
+
+       ret = ttm_read_lock(&vmaster->lock, true);
+       if (unlikely(ret != 0))
+               return ret;
+
        if (!num_clips ||
            !(dev_priv->fifo.capabilities &
              SVGA_FIFO_CAP_SCREEN_OBJECT)) {
@@ -425,6 +478,7 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
                         */
                        vmw_framebuffer_present_fs_callback(&vfbs->d_work.work);
                }
+               ttm_read_unlock(&vmaster->lock);
                return 0;
        }
 
@@ -442,6 +496,7 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr));
        if (unlikely(cmd == NULL)) {
                DRM_ERROR("Fifo reserve failed.\n");
+               ttm_read_unlock(&vmaster->lock);
                return -ENOMEM;
        }
 
@@ -461,7 +516,7 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
        }
 
        vmw_fifo_commit(dev_priv, sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr));
-
+       ttm_read_unlock(&vmaster->lock);
        return 0;
 }
 
@@ -471,16 +526,57 @@ static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
        .create_handle = vmw_framebuffer_create_handle,
 };
 
-int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
-                                   struct vmw_surface *surface,
-                                   struct vmw_framebuffer **out,
-                                   unsigned width, unsigned height)
+static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
+                                          struct drm_file *file_priv,
+                                          struct vmw_surface *surface,
+                                          struct vmw_framebuffer **out,
+                                          const struct drm_mode_fb_cmd
+                                          *mode_cmd)
 
 {
        struct drm_device *dev = dev_priv->dev;
        struct vmw_framebuffer_surface *vfbs;
+       enum SVGA3dSurfaceFormat format;
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
        int ret;
 
+       /*
+        * Sanity checks.
+        */
+
+       if (unlikely(surface->mip_levels[0] != 1 ||
+                    surface->num_sizes != 1 ||
+                    surface->sizes[0].width < mode_cmd->width ||
+                    surface->sizes[0].height < mode_cmd->height ||
+                    surface->sizes[0].depth != 1)) {
+               DRM_ERROR("Incompatible surface dimensions "
+                         "for requested mode.\n");
+               return -EINVAL;
+       }
+
+       switch (mode_cmd->depth) {
+       case 32:
+               format = SVGA3D_A8R8G8B8;
+               break;
+       case 24:
+               format = SVGA3D_X8R8G8B8;
+               break;
+       case 16:
+               format = SVGA3D_R5G6B5;
+               break;
+       case 15:
+               format = SVGA3D_A1R5G5B5;
+               break;
+       default:
+               DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth);
+               return -EINVAL;
+       }
+
+       if (unlikely(format != surface->format)) {
+               DRM_ERROR("Invalid surface format for requested mode.\n");
+               return -EINVAL;
+       }
+
        vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL);
        if (!vfbs) {
                ret = -ENOMEM;
@@ -498,16 +594,22 @@ int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
        }
 
        /* XXX get the first 3 from the surface info */
-       vfbs->base.base.bits_per_pixel = 32;
-       vfbs->base.base.pitch = width * 32 / 4;
-       vfbs->base.base.depth = 24;
-       vfbs->base.base.width = width;
-       vfbs->base.base.height = height;
+       vfbs->base.base.bits_per_pixel = mode_cmd->bpp;
+       vfbs->base.base.pitch = mode_cmd->pitch;
+       vfbs->base.base.depth = mode_cmd->depth;
+       vfbs->base.base.width = mode_cmd->width;
+       vfbs->base.base.height = mode_cmd->height;
        vfbs->base.pin = &vmw_surface_dmabuf_pin;
        vfbs->base.unpin = &vmw_surface_dmabuf_unpin;
        vfbs->surface = surface;
+       vfbs->master = drm_master_get(file_priv->master);
        mutex_init(&vfbs->work_lock);
+
+       mutex_lock(&vmaster->fb_surf_mutex);
        INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback);
+       list_add_tail(&vfbs->head, &vmaster->fb_surf);
+       mutex_unlock(&vmaster->fb_surf_mutex);
+
        *out = &vfbs->base;
 
        return 0;
@@ -544,18 +646,25 @@ void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer)
 }
 
 int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
+                                struct drm_file *file_priv,
                                 unsigned flags, unsigned color,
                                 struct drm_clip_rect *clips,
                                 unsigned num_clips)
 {
        struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct drm_clip_rect norect;
+       int ret;
        struct {
                uint32_t header;
                SVGAFifoCmdUpdate body;
        } *cmd;
        int i, increment = 1;
 
+       ret = ttm_read_lock(&vmaster->lock, true);
+       if (unlikely(ret != 0))
+               return ret;
+
        if (!num_clips) {
                num_clips = 1;
                clips = &norect;
@@ -570,6 +679,7 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) * num_clips);
        if (unlikely(cmd == NULL)) {
                DRM_ERROR("Fifo reserve failed.\n");
+               ttm_read_unlock(&vmaster->lock);
                return -ENOMEM;
        }
 
@@ -582,6 +692,7 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
        }
 
        vmw_fifo_commit(dev_priv, sizeof(*cmd) * num_clips);
+       ttm_read_unlock(&vmaster->lock);
 
        return 0;
 }
@@ -659,16 +770,25 @@ static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb)
        return vmw_dmabuf_from_vram(dev_priv, vfbd->buffer);
 }
 
-int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
-                                  struct vmw_dma_buffer *dmabuf,
-                                  struct vmw_framebuffer **out,
-                                  unsigned width, unsigned height)
+static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
+                                         struct vmw_dma_buffer *dmabuf,
+                                         struct vmw_framebuffer **out,
+                                         const struct drm_mode_fb_cmd
+                                         *mode_cmd)
 
 {
        struct drm_device *dev = dev_priv->dev;
        struct vmw_framebuffer_dmabuf *vfbd;
+       unsigned int requested_size;
        int ret;
 
+       requested_size = mode_cmd->height * mode_cmd->pitch;
+       if (unlikely(requested_size > dmabuf->base.num_pages * PAGE_SIZE)) {
+               DRM_ERROR("Screen buffer object size is too small "
+                         "for requested mode.\n");
+               return -EINVAL;
+       }
+
        vfbd = kzalloc(sizeof(*vfbd), GFP_KERNEL);
        if (!vfbd) {
                ret = -ENOMEM;
@@ -685,12 +805,11 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
                goto out_err3;
        }
 
-       /* XXX get the first 3 from the surface info */
-       vfbd->base.base.bits_per_pixel = 32;
-       vfbd->base.base.pitch = width * vfbd->base.base.bits_per_pixel / 8;
-       vfbd->base.base.depth = 24;
-       vfbd->base.base.width = width;
-       vfbd->base.base.height = height;
+       vfbd->base.base.bits_per_pixel = mode_cmd->bpp;
+       vfbd->base.base.pitch = mode_cmd->pitch;
+       vfbd->base.base.depth = mode_cmd->depth;
+       vfbd->base.base.width = mode_cmd->width;
+       vfbd->base.base.height = mode_cmd->height;
        vfbd->base.pin = vmw_framebuffer_dmabuf_pin;
        vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin;
        vfbd->buffer = dmabuf;
@@ -719,8 +838,25 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
        struct vmw_framebuffer *vfb = NULL;
        struct vmw_surface *surface = NULL;
        struct vmw_dma_buffer *bo = NULL;
+       u64 required_size;
        int ret;
 
+       /**
+        * This code should be conditioned on Screen Objects not being used.
+        * If screen objects are used, we can allocate a GMR to hold the
+        * requested framebuffer.
+        */
+
+       required_size = mode_cmd->pitch * mode_cmd->height;
+       if (unlikely(required_size > (u64) dev_priv->vram_size)) {
+               DRM_ERROR("VRAM size is too small for requested mode.\n");
+               return NULL;
+       }
+
+       /**
+        * End conditioned code.
+        */
+
        ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
                                             mode_cmd->handle, &surface);
        if (ret)
@@ -729,8 +865,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
        if (!surface->scanout)
                goto err_not_scanout;
 
-       ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
-                                             mode_cmd->width, mode_cmd->height);
+       ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, surface,
+                                             &vfb, mode_cmd);
 
        /* vmw_user_surface_lookup takes one ref so does new_fb */
        vmw_surface_unreference(&surface);
@@ -751,7 +887,7 @@ try_dmabuf:
        }
 
        ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
-                                            mode_cmd->width, mode_cmd->height);
+                                            mode_cmd);
 
        /* vmw_user_dmabuf_lookup takes one ref so does new_fb */
        vmw_dmabuf_unreference(&bo);
@@ -889,6 +1025,9 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv)
        vmw_priv->num_displays = vmw_read(vmw_priv,
                                          SVGA_REG_NUM_GUEST_DISPLAYS);
 
+       if (vmw_priv->num_displays == 0)
+               vmw_priv->num_displays = 1;
+
        for (i = 0; i < vmw_priv->num_displays; ++i) {
                save = &vmw_priv->vga_save[i];
                vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i);
@@ -898,7 +1037,19 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv)
                save->width = vmw_read(vmw_priv, SVGA_REG_DISPLAY_WIDTH);
                save->height = vmw_read(vmw_priv, SVGA_REG_DISPLAY_HEIGHT);
                vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+               if (i == 0 && vmw_priv->num_displays == 1 &&
+                   save->width == 0 && save->height == 0) {
+
+                       /*
+                        * It should be fairly safe to assume that these
+                        * values are uninitialized.
+                        */
+
+                       save->width = vmw_priv->vga_width - save->pos_x;
+                       save->height = vmw_priv->vga_height - save->pos_y;
+               }
        }
+
        return 0;
 }
 
@@ -984,3 +1135,15 @@ out_unlock:
        ttm_read_unlock(&vmaster->lock);
        return ret;
 }
+
+bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
+                               uint32_t pitch,
+                               uint32_t height)
+{
+       return ((u64) pitch * (u64) height) < (u64) dev_priv->vram_size;
+}
+
+u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc)
+{
+       return 0;
+}
index 7083b1a24df35b99fe8792040ef234d6536d69a2..a01c47ddb5bc724617b74c15ad3bffc2ed63067f 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "vmwgfx_kms.h"
 
+#define VMWGFX_LDU_NUM_DU 8
+
 #define vmw_crtc_to_ldu(x) \
        container_of(x, struct vmw_legacy_display_unit, base.crtc)
 #define vmw_encoder_to_ldu(x) \
@@ -425,7 +427,9 @@ static int vmw_ldu_connector_fill_modes(struct drm_connector *connector,
 {
        struct vmw_legacy_display_unit *ldu = vmw_connector_to_ldu(connector);
        struct drm_device *dev = connector->dev;
+       struct vmw_private *dev_priv = vmw_priv(dev);
        struct drm_display_mode *mode = NULL;
+       struct drm_display_mode *bmode;
        struct drm_display_mode prefmode = { DRM_MODE("preferred",
                DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -441,22 +445,30 @@ static int vmw_ldu_connector_fill_modes(struct drm_connector *connector,
                mode->hdisplay = ldu->pref_width;
                mode->vdisplay = ldu->pref_height;
                mode->vrefresh = drm_mode_vrefresh(mode);
-               drm_mode_probed_add(connector, mode);
+               if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2,
+                                              mode->vdisplay)) {
+                       drm_mode_probed_add(connector, mode);
 
-               if (ldu->pref_mode) {
-                       list_del_init(&ldu->pref_mode->head);
-                       drm_mode_destroy(dev, ldu->pref_mode);
-               }
+                       if (ldu->pref_mode) {
+                               list_del_init(&ldu->pref_mode->head);
+                               drm_mode_destroy(dev, ldu->pref_mode);
+                       }
 
-               ldu->pref_mode = mode;
+                       ldu->pref_mode = mode;
+               }
        }
 
        for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) {
-               if (vmw_ldu_connector_builtin[i].hdisplay > max_width ||
-                   vmw_ldu_connector_builtin[i].vdisplay > max_height)
+               bmode = &vmw_ldu_connector_builtin[i];
+               if (bmode->hdisplay > max_width ||
+                   bmode->vdisplay > max_height)
+                       continue;
+
+               if (!vmw_kms_validate_mode_vram(dev_priv, bmode->hdisplay * 2,
+                                               bmode->vdisplay))
                        continue;
 
-               mode = drm_mode_duplicate(dev, &vmw_ldu_connector_builtin[i]);
+               mode = drm_mode_duplicate(dev, bmode);
                if (!mode)
                        return 0;
                mode->vrefresh = drm_mode_vrefresh(mode);
@@ -536,6 +548,10 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
 
 int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
 {
+       struct drm_device *dev = dev_priv->dev;
+       int i;
+       int ret;
+
        if (dev_priv->ldu_priv) {
                DRM_INFO("ldu system already on\n");
                return -EINVAL;
@@ -553,23 +569,24 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
 
        drm_mode_create_dirty_info_property(dev_priv->dev);
 
-       vmw_ldu_init(dev_priv, 0);
-       /* for old hardware without multimon only enable one display */
        if (dev_priv->capabilities & SVGA_CAP_MULTIMON) {
-               vmw_ldu_init(dev_priv, 1);
-               vmw_ldu_init(dev_priv, 2);
-               vmw_ldu_init(dev_priv, 3);
-               vmw_ldu_init(dev_priv, 4);
-               vmw_ldu_init(dev_priv, 5);
-               vmw_ldu_init(dev_priv, 6);
-               vmw_ldu_init(dev_priv, 7);
+               for (i = 0; i < VMWGFX_LDU_NUM_DU; ++i)
+                       vmw_ldu_init(dev_priv, i);
+               ret = drm_vblank_init(dev, VMWGFX_LDU_NUM_DU);
+       } else {
+               /* for old hardware without multimon only enable one display */
+               vmw_ldu_init(dev_priv, 0);
+               ret = drm_vblank_init(dev, 1);
        }
 
-       return 0;
+       return ret;
 }
 
 int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv)
 {
+       struct drm_device *dev = dev_priv->dev;
+
+       drm_vblank_cleanup(dev);
        if (!dev_priv->ldu_priv)
                return -ENOSYS;
 
index 5f2d5df01e5c370acbc1be99772701626419daf5..c8c40e9979dbd21442a5d87cf6ac4cdcad08cfad 100644 (file)
@@ -211,6 +211,7 @@ static void vmw_hw_context_destroy(struct vmw_resource *res)
        cmd->body.cid = cpu_to_le32(res->id);
 
        vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       vmw_3d_resource_dec(dev_priv);
 }
 
 static int vmw_context_init(struct vmw_private *dev_priv,
@@ -247,6 +248,7 @@ static int vmw_context_init(struct vmw_private *dev_priv,
        cmd->body.cid = cpu_to_le32(res->id);
 
        vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       (void) vmw_3d_resource_inc(dev_priv);
        vmw_resource_activate(res, vmw_hw_context_destroy);
        return 0;
 }
@@ -406,6 +408,7 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res)
        cmd->body.sid = cpu_to_le32(res->id);
 
        vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       vmw_3d_resource_dec(dev_priv);
 }
 
 void vmw_surface_res_free(struct vmw_resource *res)
@@ -473,6 +476,7 @@ int vmw_surface_init(struct vmw_private *dev_priv,
        }
 
        vmw_fifo_commit(dev_priv, submit_size);
+       (void) vmw_3d_resource_inc(dev_priv);
        vmw_resource_activate(res, vmw_hw_surface_destroy);
        return 0;
 }
index b87569e96b163c04fb35790ef8c457999480e3f3..f366f968155a3ed913ce770a60ca30cbf2f97981 100644 (file)
@@ -598,7 +598,7 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev,
        pr_debug("vgaarb: decoding count now is: %d\n", vga_decode_count);
 }
 
-void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace)
+static void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace)
 {
        struct vga_device *vgadev;
        unsigned long flags;
index 4d4d09bdec0a7a7cb043725b2fb94dc1fff23dc7..97499d00615aacbddcf5963bcfa08b5f4733a1bb 100644 (file)
@@ -409,7 +409,7 @@ config SENSORS_CORETEMP
 
 config SENSORS_PKGTEMP
        tristate "Intel processor package temperature sensor"
-       depends on X86 && PCI && EXPERIMENTAL
+       depends on X86 && EXPERIMENTAL
        help
          If you say yes here you get support for the package level temperature
          sensor inside your CPU. Check documentation/driver for details.
index de8111114f469ec21567a5781349bb0d7f7cbc98..baa842a80b4bdec0088231a5a6466b12a4812131 100644 (file)
@@ -423,9 +423,18 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
        int err;
        struct platform_device *pdev;
        struct pdev_entry *pdev_entry;
-#ifdef CONFIG_SMP
        struct cpuinfo_x86 *c = &cpu_data(cpu);
-#endif
+
+       /*
+        * CPUID.06H.EAX[0] indicates whether the CPU has thermal
+        * sensors. We check this bit only, all the early CPUs
+        * without thermal sensors will be filtered out.
+        */
+       if (!cpu_has(c, X86_FEATURE_DTS)) {
+               printk(KERN_INFO DRVNAME ": CPU (model=0x%x)"
+                      " has no thermal sensor.\n", c->x86_model);
+               return 0;
+       }
 
        mutex_lock(&pdev_list_mutex);
 
@@ -482,14 +491,22 @@ exit:
 
 static void coretemp_device_remove(unsigned int cpu)
 {
-       struct pdev_entry *p, *n;
+       struct pdev_entry *p;
+       unsigned int i;
+
        mutex_lock(&pdev_list_mutex);
-       list_for_each_entry_safe(p, n, &pdev_list, list) {
-               if (p->cpu == cpu) {
-                       platform_device_unregister(p->pdev);
-                       list_del(&p->list);
-                       kfree(p);
-               }
+       list_for_each_entry(p, &pdev_list, list) {
+               if (p->cpu != cpu)
+                       continue;
+
+               platform_device_unregister(p->pdev);
+               list_del(&p->list);
+               mutex_unlock(&pdev_list_mutex);
+               kfree(p);
+               for_each_cpu(i, cpu_sibling_mask(cpu))
+                       if (i != cpu && !coretemp_device_add(i))
+                               break;
+               return;
        }
        mutex_unlock(&pdev_list_mutex);
 }
@@ -527,30 +544,21 @@ static int __init coretemp_init(void)
        if (err)
                goto exit;
 
-       for_each_online_cpu(i) {
-               struct cpuinfo_x86 *c = &cpu_data(i);
-               /*
-                * CPUID.06H.EAX[0] indicates whether the CPU has thermal
-                * sensors. We check this bit only, all the early CPUs
-                * without thermal sensors will be filtered out.
-                */
-               if (c->cpuid_level >= 6 && (cpuid_eax(0x06) & 0x01))
-                       coretemp_device_add(i);
-               else {
-                       printk(KERN_INFO DRVNAME ": CPU (model=0x%x)"
-                               " has no thermal sensor.\n", c->x86_model);
-               }
-       }
+       for_each_online_cpu(i)
+               coretemp_device_add(i);
+
+#ifndef CONFIG_HOTPLUG_CPU
        if (list_empty(&pdev_list)) {
                err = -ENODEV;
                goto exit_driver_unreg;
        }
+#endif
 
        register_hotcpu_notifier(&coretemp_cpu_notifier);
        return 0;
 
-exit_driver_unreg:
 #ifndef CONFIG_HOTPLUG_CPU
+exit_driver_unreg:
        platform_driver_unregister(&coretemp_driver);
 #endif
 exit:
index 6138f036b159956dbc4eec8282636db794485527..fc591ae53107da8481a2ab5e02f53117ac6e2471 100644 (file)
@@ -277,7 +277,7 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
        wake_up_interruptible(&lis3_dev.misc_wait);
        kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
 out:
-       if (lis3_dev.whoami == WAI_8B && lis3_dev.idev &&
+       if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev &&
            lis3_dev.idev->input->users)
                return IRQ_WAKE_THREAD;
        return IRQ_HANDLED;
@@ -718,7 +718,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
         * io-apic is not configurable (and generates a warning) but I keep it
         * in case of support for other hardware.
         */
-       if (dev->whoami == WAI_8B)
+       if (dev->pdata && dev->whoami == WAI_8B)
                thread_fn = lis302dl_interrupt_thread1_8b;
        else
                thread_fn = NULL;
index 74157fcda6edf4bc569469db4ae1de9efa5b882d..f11903936c8b3a51c3f8dddcb20318185952fa79 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/list.h>
 #include <linux/platform_device.h>
 #include <linux/cpu.h>
-#include <linux/pci.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
 
@@ -224,7 +223,7 @@ static int __devinit pkgtemp_probe(struct platform_device *pdev)
 
        err = sysfs_create_group(&pdev->dev.kobj, &pkgtemp_group);
        if (err)
-               goto exit_free;
+               goto exit_dev;
 
        data->hwmon_dev = hwmon_device_register(&pdev->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -238,6 +237,8 @@ static int __devinit pkgtemp_probe(struct platform_device *pdev)
 
 exit_class:
        sysfs_remove_group(&pdev->dev.kobj, &pkgtemp_group);
+exit_dev:
+       device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
 exit_free:
        kfree(data);
 exit:
@@ -250,6 +251,7 @@ static int __devexit pkgtemp_remove(struct platform_device *pdev)
 
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &pkgtemp_group);
+       device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
        platform_set_drvdata(pdev, NULL);
        kfree(data);
        return 0;
@@ -281,9 +283,10 @@ static int __cpuinit pkgtemp_device_add(unsigned int cpu)
        int err;
        struct platform_device *pdev;
        struct pdev_entry *pdev_entry;
-#ifdef CONFIG_SMP
        struct cpuinfo_x86 *c = &cpu_data(cpu);
-#endif
+
+       if (!cpu_has(c, X86_FEATURE_PTS))
+               return 0;
 
        mutex_lock(&pdev_list_mutex);
 
@@ -339,17 +342,18 @@ exit:
 #ifdef CONFIG_HOTPLUG_CPU
 static void pkgtemp_device_remove(unsigned int cpu)
 {
-       struct pdev_entry *p, *n;
+       struct pdev_entry *p;
        unsigned int i;
        int err;
 
        mutex_lock(&pdev_list_mutex);
-       list_for_each_entry_safe(p, n, &pdev_list, list) {
+       list_for_each_entry(p, &pdev_list, list) {
                if (p->cpu != cpu)
                        continue;
 
                platform_device_unregister(p->pdev);
                list_del(&p->list);
+               mutex_unlock(&pdev_list_mutex);
                kfree(p);
                for_each_cpu(i, cpu_core_mask(cpu)) {
                        if (i != cpu) {
@@ -358,7 +362,7 @@ static void pkgtemp_device_remove(unsigned int cpu)
                                        break;
                        }
                }
-               break;
+               return;
        }
        mutex_unlock(&pdev_list_mutex);
 }
@@ -399,11 +403,6 @@ static int __init pkgtemp_init(void)
                goto exit;
 
        for_each_online_cpu(i) {
-               struct cpuinfo_x86 *c = &cpu_data(i);
-
-               if (!cpu_has(c, X86_FEATURE_PTS))
-                       continue;
-
                err = pkgtemp_device_add(i);
                if (err)
                        goto exit_devices_unreg;
index 9952579425b99a477c29e488243337e9372b2200..1b3060eb2921c9da66fb2f0844de4a2d1afa4ce0 100644 (file)
@@ -80,5 +80,4 @@ struct st_proto_s {
 extern long st_register(struct st_proto_s *);
 extern long st_unregister(enum proto_type);
 
-extern struct platform_device *st_get_plat_device(void);
 #endif /* ST_H */
index 063c9b1db1ab655504f5908e7c4598418dafd0fd..b85d8bfdf600ad22cd4d62636b521bfb3ac38fa5 100644 (file)
@@ -38,7 +38,6 @@
 #include "st_ll.h"
 #include "st.h"
 
-#define VERBOSE
 /* strings to be used for rfkill entries and by
  * ST Core to be used for sysfs debug entry
  */
@@ -581,7 +580,7 @@ long st_register(struct st_proto_s *new_proto)
        long err = 0;
        unsigned long flags = 0;
 
-       st_kim_ref(&st_gdata);
+       st_kim_ref(&st_gdata, 0);
        pr_info("%s(%d) ", __func__, new_proto->type);
        if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL
            || new_proto->reg_complete_cb == NULL) {
@@ -713,7 +712,7 @@ long st_unregister(enum proto_type type)
 
        pr_debug("%s: %d ", __func__, type);
 
-       st_kim_ref(&st_gdata);
+       st_kim_ref(&st_gdata, 0);
        if (type < ST_BT || type >= ST_MAX) {
                pr_err(" protocol %d not supported", type);
                return -EPROTONOSUPPORT;
@@ -767,7 +766,7 @@ long st_write(struct sk_buff *skb)
 #endif
        long len;
 
-       st_kim_ref(&st_gdata);
+       st_kim_ref(&st_gdata, 0);
        if (unlikely(skb == NULL || st_gdata == NULL
                || st_gdata->tty == NULL)) {
                pr_err("data/tty unavailable to perform write");
@@ -818,7 +817,7 @@ static int st_tty_open(struct tty_struct *tty)
        struct st_data_s *st_gdata;
        pr_info("%s ", __func__);
 
-       st_kim_ref(&st_gdata);
+       st_kim_ref(&st_gdata, 0);
        st_gdata->tty = tty;
        tty->disc_data = st_gdata;
 
index e0c32d149f5f294878d22597bec9c1bfc05660a4..8601320a679ee8ce5dda5ea9d36f8c85798dd23e 100644 (file)
@@ -117,7 +117,7 @@ int st_core_init(struct st_data_s **);
 void st_core_exit(struct st_data_s *);
 
 /* ask for reference from KIM */
-void st_kim_ref(struct st_data_s **);
+void st_kim_ref(struct st_data_s **, int);
 
 #define GPS_STUB_TEST
 #ifdef GPS_STUB_TEST
index b4a6c7fdc4e6ca59283dd3e64736c0efdfd97407..9e99463f76e8a0d048f7ec8667a455125d88cb0b 100644 (file)
@@ -72,10 +72,25 @@ const unsigned char *protocol_names[] = {
        PROTO_ENTRY(ST_GPS, "GPS"),
 };
 
+#define MAX_ST_DEVICES 3       /* Imagine 1 on each UART for now */
+struct platform_device *st_kim_devices[MAX_ST_DEVICES];
 
 /**********************************************************************/
 /* internal functions */
 
+/**
+ * st_get_plat_device -
+ *     function which returns the reference to the platform device
+ *     requested by id. As of now only 1 such device exists (id=0)
+ *     the context requesting for reference can get the id to be
+ *     requested by a. The protocol driver which is registering or
+ *     b. the tty device which is opened.
+ */
+static struct platform_device *st_get_plat_device(int id)
+{
+       return st_kim_devices[id];
+}
+
 /**
  * validate_firmware_response -
  *     function to return whether the firmware response was proper
@@ -353,7 +368,7 @@ void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state)
        struct kim_data_s       *kim_gdata;
        pr_info(" %s ", __func__);
 
-       kim_pdev = st_get_plat_device();
+       kim_pdev = st_get_plat_device(0);
        kim_gdata = dev_get_drvdata(&kim_pdev->dev);
 
        if (kim_gdata->gpios[type] == -1) {
@@ -574,12 +589,12 @@ static int kim_toggle_radio(void *data, bool blocked)
  *     This would enable multiple such platform devices to exist
  *     on a given platform
  */
-void st_kim_ref(struct st_data_s **core_data)
+void st_kim_ref(struct st_data_s **core_data, int id)
 {
        struct platform_device  *pdev;
        struct kim_data_s       *kim_gdata;
        /* get kim_gdata reference from platform device */
-       pdev = st_get_plat_device();
+       pdev = st_get_plat_device(id);
        kim_gdata = dev_get_drvdata(&pdev->dev);
        *core_data = kim_gdata->core_data;
 }
@@ -623,6 +638,7 @@ static int kim_probe(struct platform_device *pdev)
        long *gpios = pdev->dev.platform_data;
        struct kim_data_s       *kim_gdata;
 
+       st_kim_devices[pdev->id] = pdev;
        kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC);
        if (!kim_gdata) {
                pr_err("no mem to allocate");
index 7e594449600e004c7f6ba14fa2dce39ebee25d20..9eed5b52d9de22647f6ca7e94791cd97f6e60122 100644 (file)
@@ -91,12 +91,12 @@ config USB_DYNAMIC_MINORS
          If you are unsure about this, say N here.
 
 config USB_SUSPEND
-       bool "USB runtime power management (suspend/resume and wakeup)"
+       bool "USB runtime power management (autosuspend) and wakeup"
        depends on USB && PM_RUNTIME
        help
          If you say Y here, you can use driver calls or the sysfs
-         "power/level" file to suspend or resume individual USB
-         peripherals and to enable or disable autosuspend (see
+         "power/control" file to enable or disable autosuspend for
+         individual USB peripherals (see
          Documentation/usb/power-management.txt for more details).
 
          Also, USB "remote wakeup" signaling is supported, whereby some
index f06f5dbc8cdc22fbedfa463c05b18672cbb99516..1e6ccef2cf0cbd9e817e7045dccfb03918efa9d7 100644 (file)
@@ -159,9 +159,9 @@ void usb_major_cleanup(void)
 int usb_register_dev(struct usb_interface *intf,
                     struct usb_class_driver *class_driver)
 {
-       int retval = -EINVAL;
+       int retval;
        int minor_base = class_driver->minor_base;
-       int minor = 0;
+       int minor;
        char name[20];
        char *temp;
 
@@ -173,12 +173,17 @@ int usb_register_dev(struct usb_interface *intf,
         */
        minor_base = 0;
 #endif
-       intf->minor = -1;
-
-       dbg ("looking for a minor, starting at %d", minor_base);
 
        if (class_driver->fops == NULL)
-               goto exit;
+               return -EINVAL;
+       if (intf->minor >= 0)
+               return -EADDRINUSE;
+
+       retval = init_usb_class();
+       if (retval)
+               return retval;
+
+       dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base);
 
        down_write(&minor_rwsem);
        for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
@@ -186,20 +191,12 @@ int usb_register_dev(struct usb_interface *intf,
                        continue;
 
                usb_minors[minor] = class_driver->fops;
-
-               retval = 0;
+               intf->minor = minor;
                break;
        }
        up_write(&minor_rwsem);
-
-       if (retval)
-               goto exit;
-
-       retval = init_usb_class();
-       if (retval)
-               goto exit;
-
-       intf->minor = minor;
+       if (intf->minor < 0)
+               return -EXFULL;
 
        /* create a usb class device for this usb interface */
        snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
@@ -213,11 +210,11 @@ int usb_register_dev(struct usb_interface *intf,
                                      "%s", temp);
        if (IS_ERR(intf->usb_dev)) {
                down_write(&minor_rwsem);
-               usb_minors[intf->minor] = NULL;
+               usb_minors[minor] = NULL;
+               intf->minor = -1;
                up_write(&minor_rwsem);
                retval = PTR_ERR(intf->usb_dev);
        }
-exit:
        return retval;
 }
 EXPORT_SYMBOL_GPL(usb_register_dev);
index 844683e503830485147910ff16ca035a90194d27..9f0ce7de0e366fb0066dfb92d6a6403aa5f4a2b3 100644 (file)
@@ -1802,6 +1802,7 @@ free_interfaces:
                intf->dev.groups = usb_interface_groups;
                intf->dev.dma_mask = dev->dev.dma_mask;
                INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
+               intf->minor = -1;
                device_initialize(&intf->dev);
                dev_set_name(&intf->dev, "%d-%s:%d.%d",
                        dev->bus->busnum, dev->devpath,
index 59dc3d351b60269f3c3872b859c0b39d7fcbe449..5ab5bb89bae3558cfe6f296e37931680afa0e323 100644 (file)
@@ -322,6 +322,7 @@ cppi_channel_allocate(struct dma_controller *c,
                                index, transmit ? 'T' : 'R', cppi_ch);
        cppi_ch->hw_ep = ep;
        cppi_ch->channel.status = MUSB_DMA_STATUS_FREE;
+       cppi_ch->channel.max_len = 0x7fffffff;
 
        DBG(4, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R');
        return &cppi_ch->channel;
index 6fca870e957ed3b5061f19deec76a9472d6d5211..d065e23f123ee755f9e6fe0e661823f48d917727 100644 (file)
@@ -300,6 +300,11 @@ static void txstate(struct musb *musb, struct musb_request *req)
 #ifndef        CONFIG_MUSB_PIO_ONLY
        if (is_dma_capable() && musb_ep->dma) {
                struct dma_controller   *c = musb->dma_controller;
+               size_t request_size;
+
+               /* setup DMA, then program endpoint CSR */
+               request_size = min_t(size_t, request->length - request->actual,
+                                       musb_ep->dma->max_len);
 
                use_dma = (request->dma != DMA_ADDR_INVALID);
 
@@ -307,11 +312,6 @@ static void txstate(struct musb *musb, struct musb_request *req)
 
 #ifdef CONFIG_USB_INVENTRA_DMA
                {
-                       size_t request_size;
-
-                       /* setup DMA, then program endpoint CSR */
-                       request_size = min_t(size_t, request->length,
-                                               musb_ep->dma->max_len);
                        if (request_size < musb_ep->packet_sz)
                                musb_ep->dma->desired_mode = 0;
                        else
@@ -373,8 +373,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
                use_dma = use_dma && c->channel_program(
                                musb_ep->dma, musb_ep->packet_sz,
                                0,
-                               request->dma,
-                               request->length);
+                               request->dma + request->actual,
+                               request_size);
                if (!use_dma) {
                        c->channel_release(musb_ep->dma);
                        musb_ep->dma = NULL;
@@ -386,8 +386,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
                use_dma = use_dma && c->channel_program(
                                musb_ep->dma, musb_ep->packet_sz,
                                request->zero,
-                               request->dma,
-                               request->length);
+                               request->dma + request->actual,
+                               request_size);
 #endif
        }
 #endif
@@ -501,26 +501,14 @@ void musb_g_tx(struct musb *musb, u8 epnum)
                                request->zero = 0;
                        }
 
-                       /* ... or if not, then complete it. */
-                       musb_g_giveback(musb_ep, request, 0);
-
-                       /*
-                        * Kickstart next transfer if appropriate;
-                        * the packet that just completed might not
-                        * be transmitted for hours or days.
-                        * REVISIT for double buffering...
-                        * FIXME revisit for stalls too...
-                        */
-                       musb_ep_select(mbase, epnum);
-                       csr = musb_readw(epio, MUSB_TXCSR);
-                       if (csr & MUSB_TXCSR_FIFONOTEMPTY)
-                               return;
-
-                       request = musb_ep->desc ? next_request(musb_ep) : NULL;
-                       if (!request) {
-                               DBG(4, "%s idle now\n",
-                                       musb_ep->end_point.name);
-                               return;
+                       if (request->actual == request->length) {
+                               musb_g_giveback(musb_ep, request, 0);
+                               request = musb_ep->desc ? next_request(musb_ep) : NULL;
+                               if (!request) {
+                                       DBG(4, "%s idle now\n",
+                                               musb_ep->end_point.name);
+                                       return;
+                               }
                        }
                }
 
@@ -568,11 +556,19 @@ static void rxstate(struct musb *musb, struct musb_request *req)
 {
        const u8                epnum = req->epnum;
        struct usb_request      *request = &req->request;
-       struct musb_ep          *musb_ep = &musb->endpoints[epnum].ep_out;
+       struct musb_ep          *musb_ep;
        void __iomem            *epio = musb->endpoints[epnum].regs;
        unsigned                fifo_count = 0;
-       u16                     len = musb_ep->packet_sz;
+       u16                     len;
        u16                     csr = musb_readw(epio, MUSB_RXCSR);
+       struct musb_hw_ep       *hw_ep = &musb->endpoints[epnum];
+
+       if (hw_ep->is_shared_fifo)
+               musb_ep = &hw_ep->ep_in;
+       else
+               musb_ep = &hw_ep->ep_out;
+
+       len = musb_ep->packet_sz;
 
        /* We shouldn't get here while DMA is active, but we do... */
        if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
@@ -647,8 +643,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
         */
 
                                csr |= MUSB_RXCSR_DMAENAB;
-#ifdef USE_MODE1
                                csr |= MUSB_RXCSR_AUTOCLEAR;
+#ifdef USE_MODE1
                                /* csr |= MUSB_RXCSR_DMAMODE; */
 
                                /* this special sequence (enabling and then
@@ -663,10 +659,11 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                if (request->actual < request->length) {
                                        int transfer_size = 0;
 #ifdef USE_MODE1
-                                       transfer_size = min(request->length,
+                                       transfer_size = min(request->length - request->actual,
                                                        channel->max_len);
 #else
-                                       transfer_size = len;
+                                       transfer_size = min(request->length - request->actual,
+                                                       (unsigned)len);
 #endif
                                        if (transfer_size <= musb_ep->packet_sz)
                                                musb_ep->dma->desired_mode = 0;
@@ -740,9 +737,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
        u16                     csr;
        struct usb_request      *request;
        void __iomem            *mbase = musb->mregs;
-       struct musb_ep          *musb_ep = &musb->endpoints[epnum].ep_out;
+       struct musb_ep          *musb_ep;
        void __iomem            *epio = musb->endpoints[epnum].regs;
        struct dma_channel      *dma;
+       struct musb_hw_ep       *hw_ep = &musb->endpoints[epnum];
+
+       if (hw_ep->is_shared_fifo)
+               musb_ep = &hw_ep->ep_in;
+       else
+               musb_ep = &hw_ep->ep_out;
 
        musb_ep_select(mbase, epnum);
 
@@ -1081,7 +1084,7 @@ struct free_record {
 /*
  * Context: controller locked, IRQs blocked.
  */
-static void musb_ep_restart(struct musb *musb, struct musb_request *req)
+void musb_ep_restart(struct musb *musb, struct musb_request *req)
 {
        DBG(3, "<== %s request %p len %u on hw_ep%d\n",
                req->tx ? "TX/IN" : "RX/OUT",
index c8b140325d82bf4bb6cd3ad85216fa24ec308ce7..572b1da7f2dc45ea1fd3d9bb67d3ea273d56cfae 100644 (file)
@@ -105,4 +105,6 @@ extern void musb_gadget_cleanup(struct musb *);
 
 extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
 
+extern void musb_ep_restart(struct musb *, struct musb_request *);
+
 #endif         /* __MUSB_GADGET_H */
index 59bef8f3a3585100310bbb43848ea56603a82c28..6dd03f4c5f4956983c2d1bf2552c248f6a1702a0 100644 (file)
@@ -261,6 +261,7 @@ __acquires(musb->lock)
                                        ctrlrequest->wIndex & 0x0f;
                                struct musb_ep          *musb_ep;
                                struct musb_hw_ep       *ep;
+                               struct musb_request     *request;
                                void __iomem            *regs;
                                int                     is_in;
                                u16                     csr;
@@ -302,6 +303,14 @@ __acquires(musb->lock)
                                        musb_writew(regs, MUSB_RXCSR, csr);
                                }
 
+                               /* Maybe start the first request in the queue */
+                               request = to_musb_request(
+                                               next_request(musb_ep));
+                               if (!musb_ep->busy && request) {
+                                       DBG(3, "restarting the request\n");
+                                       musb_ep_restart(musb, request);
+                               }
+
                                /* select ep0 again */
                                musb_ep_select(mbase, 0);
                                } break;
index 877d20b1dff973fd6975f258bb0b18267df1f5f5..9e65c47cc98b95761daba7186dd180550b954def 100644 (file)
@@ -660,6 +660,12 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
 
        qh->segsize = length;
 
+       /*
+        * Ensure the data reaches to main memory before starting
+        * DMA transfer
+        */
+       wmb();
+
        if (!dma->channel_program(channel, pkt_size, mode,
                        urb->transfer_dma + offset, length)) {
                dma->channel_release(channel);
index a76e0aa5cd3fc5188a392639618858a7e7e34092..391915093fe1c494a58ec8feae54cd576fd2464a 100644 (file)
@@ -209,7 +209,10 @@ static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh,
        }
 
        inode->i_mode = new_mode;
+       inode->i_ctime = CURRENT_TIME;
        di->i_mode = cpu_to_le16(inode->i_mode);
+       di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
+       di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
 
        ocfs2_journal_dirty(handle, di_bh);
 
index 1361997cf205d132a04ddeb87760aa233c3e707d..cbe2f057cc2826cb6af4ed833319fe27c4bd565f 100644 (file)
@@ -977,7 +977,7 @@ static int o2net_tx_can_proceed(struct o2net_node *nn,
 int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
                           size_t caller_veclen, u8 target_node, int *status)
 {
-       int ret;
+       int ret = 0;
        struct o2net_msg *msg = NULL;
        size_t veclen, caller_bytes = 0;
        struct kvec *vec = NULL;
index f04ebcfffc4a5e1516c2a7307ffa8032db8e19d7..c49f6de0e7abb6e096ddc56e795957e0194bb8dd 100644 (file)
@@ -3931,6 +3931,15 @@ static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir,
                goto out_commit;
        }
 
+       cpos = split_hash;
+       ret = ocfs2_dx_dir_new_cluster(dir, &et, cpos, handle,
+                                      data_ac, meta_ac, new_dx_leaves,
+                                      num_dx_leaves);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
        for (i = 0; i < num_dx_leaves; i++) {
                ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir),
                                              orig_dx_leaves[i],
@@ -3939,15 +3948,14 @@ static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir,
                        mlog_errno(ret);
                        goto out_commit;
                }
-       }
 
-       cpos = split_hash;
-       ret = ocfs2_dx_dir_new_cluster(dir, &et, cpos, handle,
-                                      data_ac, meta_ac, new_dx_leaves,
-                                      num_dx_leaves);
-       if (ret) {
-               mlog_errno(ret);
-               goto out_commit;
+               ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir),
+                                             new_dx_leaves[i],
+                                             OCFS2_JOURNAL_ACCESS_WRITE);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+               }
        }
 
        ocfs2_dx_dir_transfer_leaf(dir, split_hash, handle, tmp_dx_leaf,
index 4b6ae2c13b47a85c6a31f6f7d2a1072099354935..765298908f1d3905bbabf3c5e597a8bf72ebd4a9 100644 (file)
@@ -1030,6 +1030,7 @@ int dlm_drop_lockres_ref(struct dlm_ctxt *dlm,
                         struct dlm_lock_resource *res);
 void dlm_clean_master_list(struct dlm_ctxt *dlm,
                           u8 dead_node);
+void dlm_force_free_mles(struct dlm_ctxt *dlm);
 int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock);
 int __dlm_lockres_has_locks(struct dlm_lock_resource *res);
 int __dlm_lockres_unused(struct dlm_lock_resource *res);
index 5efdd37dfe484f2f6207ac2c7c6927fda0cc1ea0..901ca52bf86b293639ea39c8e1f460b66bc1f265 100644 (file)
@@ -636,8 +636,14 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos)
        spin_lock(&dlm->track_lock);
        if (oldres)
                track_list = &oldres->tracking;
-       else
+       else {
                track_list = &dlm->tracking_list;
+               if (list_empty(track_list)) {
+                       dl = NULL;
+                       spin_unlock(&dlm->track_lock);
+                       goto bail;
+               }
+       }
 
        list_for_each_entry(res, track_list, tracking) {
                if (&res->tracking == &dlm->tracking_list)
@@ -660,6 +666,7 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos)
        } else
                dl = NULL;
 
+bail:
        /* passed to seq_show */
        return dl;
 }
index 153abb5abef024d2ca63f6d4a23ee1c126b89f13..11a5c87fd7f7c00de41c61c00fae625e46675973 100644 (file)
@@ -693,6 +693,7 @@ void dlm_unregister_domain(struct dlm_ctxt *dlm)
 
                dlm_mark_domain_leaving(dlm);
                dlm_leave_domain(dlm);
+               dlm_force_free_mles(dlm);
                dlm_complete_dlm_shutdown(dlm);
        }
        dlm_put(dlm);
index ffb4c68dafa495bc739165eb30f718f1eb0865ec..f564b0e5f80d8c89e08eeba4a5e133b24cb67373 100644 (file)
@@ -3433,3 +3433,43 @@ void dlm_lockres_release_ast(struct dlm_ctxt *dlm,
        wake_up(&res->wq);
        wake_up(&dlm->migration_wq);
 }
+
+void dlm_force_free_mles(struct dlm_ctxt *dlm)
+{
+       int i;
+       struct hlist_head *bucket;
+       struct dlm_master_list_entry *mle;
+       struct hlist_node *tmp, *list;
+
+       /*
+        * We notified all other nodes that we are exiting the domain and
+        * marked the dlm state to DLM_CTXT_LEAVING. If any mles are still
+        * around we force free them and wake any processes that are waiting
+        * on the mles
+        */
+       spin_lock(&dlm->spinlock);
+       spin_lock(&dlm->master_lock);
+
+       BUG_ON(dlm->dlm_state != DLM_CTXT_LEAVING);
+       BUG_ON((find_next_bit(dlm->domain_map, O2NM_MAX_NODES, 0) < O2NM_MAX_NODES));
+
+       for (i = 0; i < DLM_HASH_BUCKETS; i++) {
+               bucket = dlm_master_hash(dlm, i);
+               hlist_for_each_safe(list, tmp, bucket) {
+                       mle = hlist_entry(list, struct dlm_master_list_entry,
+                                         master_hash_node);
+                       if (mle->type != DLM_MLE_BLOCK) {
+                               mlog(ML_ERROR, "bad mle: %p\n", mle);
+                               dlm_print_one_mle(mle);
+                       }
+                       atomic_set(&mle->woken, 1);
+                       wake_up(&mle->wq);
+
+                       __dlm_unlink_mle(dlm, mle);
+                       __dlm_mle_detach_hb_events(dlm, mle);
+                       __dlm_put_mle(mle);
+               }
+       }
+       spin_unlock(&dlm->master_lock);
+       spin_unlock(&dlm->spinlock);
+}
index d1ce48e1b3d6029e5861cf2863cbb0a544511b40..1d596d8c4a4a55dfd185ecaff4d7d9900bf10b24 100644 (file)
@@ -84,6 +84,7 @@ enum {
        OI_LS_PARENT,
        OI_LS_RENAME1,
        OI_LS_RENAME2,
+       OI_LS_REFLINK_TARGET,
 };
 
 int ocfs2_dlm_init(struct ocfs2_super *osb);
index 33f1c9a8258d1d4de5a17fe1ebf1d0d39c4098c3..fa31d05e41b7e558fa24df43682dbd107b568c76 100644 (file)
 #define OCFS2_HAS_REFCOUNT_FL   (0x0010)
 
 /* Inode attributes, keep in sync with EXT2 */
-#define OCFS2_SECRM_FL         (0x00000001)    /* Secure deletion */
-#define OCFS2_UNRM_FL          (0x00000002)    /* Undelete */
-#define OCFS2_COMPR_FL         (0x00000004)    /* Compress file */
-#define OCFS2_SYNC_FL          (0x00000008)    /* Synchronous updates */
-#define OCFS2_IMMUTABLE_FL     (0x00000010)    /* Immutable file */
-#define OCFS2_APPEND_FL                (0x00000020)    /* writes to file may only append */
-#define OCFS2_NODUMP_FL                (0x00000040)    /* do not dump file */
-#define OCFS2_NOATIME_FL       (0x00000080)    /* do not update atime */
-#define OCFS2_DIRSYNC_FL       (0x00010000)    /* dirsync behaviour (directories only) */
-
-#define OCFS2_FL_VISIBLE       (0x000100FF)    /* User visible flags */
-#define OCFS2_FL_MODIFIABLE    (0x000100FF)    /* User modifiable flags */
+#define OCFS2_SECRM_FL                 FS_SECRM_FL     /* Secure deletion */
+#define OCFS2_UNRM_FL                  FS_UNRM_FL      /* Undelete */
+#define OCFS2_COMPR_FL                 FS_COMPR_FL     /* Compress file */
+#define OCFS2_SYNC_FL                  FS_SYNC_FL      /* Synchronous updates */
+#define OCFS2_IMMUTABLE_FL             FS_IMMUTABLE_FL /* Immutable file */
+#define OCFS2_APPEND_FL                        FS_APPEND_FL    /* writes to file may only append */
+#define OCFS2_NODUMP_FL                        FS_NODUMP_FL    /* do not dump file */
+#define OCFS2_NOATIME_FL               FS_NOATIME_FL   /* do not update atime */
+/* Reserved for compression usage... */
+#define OCFS2_DIRTY_FL                 FS_DIRTY_FL
+#define OCFS2_COMPRBLK_FL              FS_COMPRBLK_FL  /* One or more compressed clusters */
+#define OCFS2_NOCOMP_FL                        FS_NOCOMP_FL    /* Don't compress */
+#define OCFS2_ECOMPR_FL                        FS_ECOMPR_FL    /* Compression error */
+/* End compression flags --- maybe not all used */
+#define OCFS2_BTREE_FL                 FS_BTREE_FL     /* btree format dir */
+#define OCFS2_INDEX_FL                 FS_INDEX_FL     /* hash-indexed directory */
+#define OCFS2_IMAGIC_FL                        FS_IMAGIC_FL    /* AFS directory */
+#define OCFS2_JOURNAL_DATA_FL          FS_JOURNAL_DATA_FL /* Reserved for ext3 */
+#define OCFS2_NOTAIL_FL                        FS_NOTAIL_FL    /* file tail should not be merged */
+#define OCFS2_DIRSYNC_FL               FS_DIRSYNC_FL   /* dirsync behaviour (directories only) */
+#define OCFS2_TOPDIR_FL                        FS_TOPDIR_FL    /* Top of directory hierarchies*/
+#define OCFS2_RESERVED_FL              FS_RESERVED_FL  /* reserved for ext2 lib */
+
+#define OCFS2_FL_VISIBLE               FS_FL_USER_VISIBLE      /* User visible flags */
+#define OCFS2_FL_MODIFIABLE            FS_FL_USER_MODIFIABLE   /* User modifiable flags */
 
 /*
  * Extent record flags (e_node.leaf.flags)
index 2d3420af1a839e0e13626a34c289cd2227bf095a..5d241505690b71e2ec0b259cbc39f1ed46d683d5 100644 (file)
 /*
  * ioctl commands
  */
-#define OCFS2_IOC_GETFLAGS     _IOR('f', 1, long)
-#define OCFS2_IOC_SETFLAGS     _IOW('f', 2, long)
-#define OCFS2_IOC32_GETFLAGS   _IOR('f', 1, int)
-#define OCFS2_IOC32_SETFLAGS   _IOW('f', 2, int)
+#define OCFS2_IOC_GETFLAGS     FS_IOC_GETFLAGS
+#define OCFS2_IOC_SETFLAGS     FS_IOC_SETFLAGS
+#define OCFS2_IOC32_GETFLAGS   FS_IOC32_GETFLAGS
+#define OCFS2_IOC32_SETFLAGS   FS_IOC32_SETFLAGS
 
 /*
  * Space reservation / allocation / free ioctls and argument structure
index 0afeda83120fa0e54bd2c9cc7e1f4f08c6e836bf..efdd7560740655beba6f53dccef235b5ce89cdbf 100644 (file)
@@ -4201,8 +4201,9 @@ static int __ocfs2_reflink(struct dentry *old_dentry,
                goto out;
        }
 
-       mutex_lock(&new_inode->i_mutex);
-       ret = ocfs2_inode_lock(new_inode, &new_bh, 1);
+       mutex_lock_nested(&new_inode->i_mutex, I_MUTEX_CHILD);
+       ret = ocfs2_inode_lock_nested(new_inode, &new_bh, 1,
+                                     OI_LS_REFLINK_TARGET);
        if (ret) {
                mlog_errno(ret);
                goto out_unlock;
index d8b6e4259b80022cb824326f4ce2c665089b5818..3e78db361bc70b3ffc327a6f21b6d4580305d0eb 100644 (file)
@@ -732,25 +732,23 @@ int ocfs2_resmap_resv_bits(struct ocfs2_reservation_map *resmap,
                           struct ocfs2_alloc_reservation *resv,
                           int *cstart, int *clen)
 {
-       unsigned int wanted = *clen;
-
        if (resv == NULL || ocfs2_resmap_disabled(resmap))
                return -ENOSPC;
 
        spin_lock(&resv_lock);
 
-       /*
-        * We don't want to over-allocate for temporary
-        * windows. Otherwise, we run the risk of fragmenting the
-        * allocation space.
-        */
-       wanted = ocfs2_resv_window_bits(resmap, resv);
-       if ((resv->r_flags & OCFS2_RESV_FLAG_TMP) || wanted < *clen)
-               wanted = *clen;
-
        if (ocfs2_resv_empty(resv)) {
-               mlog(0, "empty reservation, find new window\n");
+               /*
+                * We don't want to over-allocate for temporary
+                * windows. Otherwise, we run the risk of fragmenting the
+                * allocation space.
+                */
+               unsigned int wanted = ocfs2_resv_window_bits(resmap, resv);
 
+               if ((resv->r_flags & OCFS2_RESV_FLAG_TMP) || wanted < *clen)
+                       wanted = *clen;
+
+               mlog(0, "empty reservation, find new window\n");
                /*
                 * Try to get a window here. If it works, we must fall
                 * through and test the bitmap . This avoids some
index 8a286f54dca1f30a1d65b0d6cbb5baa0fa8c063c..849c2f0e0a0e664e983adf61f620abedf87fcb72 100644 (file)
@@ -357,7 +357,7 @@ out:
 static void ocfs2_bg_discontig_add_extent(struct ocfs2_super *osb,
                                          struct ocfs2_group_desc *bg,
                                          struct ocfs2_chain_list *cl,
-                                         u64 p_blkno, u32 clusters)
+                                         u64 p_blkno, unsigned int clusters)
 {
        struct ocfs2_extent_list *el = &bg->bg_list;
        struct ocfs2_extent_rec *rec;
@@ -369,7 +369,7 @@ static void ocfs2_bg_discontig_add_extent(struct ocfs2_super *osb,
        rec->e_blkno = cpu_to_le64(p_blkno);
        rec->e_cpos = cpu_to_le32(le16_to_cpu(bg->bg_bits) /
                                  le16_to_cpu(cl->cl_bpc));
-       rec->e_leaf_clusters = cpu_to_le32(clusters);
+       rec->e_leaf_clusters = cpu_to_le16(clusters);
        le16_add_cpu(&bg->bg_bits, clusters * le16_to_cpu(cl->cl_bpc));
        le16_add_cpu(&bg->bg_free_bits_count,
                     clusters * le16_to_cpu(cl->cl_bpc));
index d03469f618012ea4aff64b62f1f77e3e8b8ec47d..06fa5e77c40ef7aa0a3c0483ddbf3b9dd59f9dcf 100644 (file)
@@ -1286,13 +1286,11 @@ int ocfs2_xattr_get_nolock(struct inode *inode,
        xis.inode_bh = xbs.inode_bh = di_bh;
        di = (struct ocfs2_dinode *)di_bh->b_data;
 
-       down_read(&oi->ip_xattr_sem);
        ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer,
                                    buffer_size, &xis);
        if (ret == -ENODATA && di->i_xattr_loc)
                ret = ocfs2_xattr_block_get(inode, name_index, name, buffer,
                                            buffer_size, &xbs);
-       up_read(&oi->ip_xattr_sem);
 
        return ret;
 }
@@ -1316,8 +1314,10 @@ static int ocfs2_xattr_get(struct inode *inode,
                mlog_errno(ret);
                return ret;
        }
+       down_read(&OCFS2_I(inode)->ip_xattr_sem);
        ret = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
                                     name, buffer, buffer_size);
+       up_read(&OCFS2_I(inode)->ip_xattr_sem);
 
        ocfs2_inode_unlock(inode, 0);
 
index 30e827aeba02af2c2bbe278953181ae0fe74fb7b..274eaaa15c36a86ee48a6b743f6c9d7cfb36b010 100644 (file)
@@ -612,7 +612,7 @@ struct drm_gem_object {
        struct kref refcount;
 
        /** Handle count of this object. Each handle also holds a reference */
-       struct kref handlecount;
+       atomic_t handle_count; /* number of handles on this object */
 
        /** Related drm device */
        struct drm_device *dev;
@@ -1041,13 +1041,6 @@ struct drm_device {
        /*@{ */
        spinlock_t object_name_lock;
        struct idr object_name_idr;
-       atomic_t object_count;
-       atomic_t object_memory;
-       atomic_t pin_count;
-       atomic_t pin_memory;
-       atomic_t gtt_count;
-       atomic_t gtt_memory;
-       uint32_t gtt_total;
        uint32_t invalidate_domains;    /* domains pending invalidation */
        uint32_t flush_domains;         /* domains pending flush */
        /*@} */
@@ -1158,6 +1151,7 @@ extern int drm_release(struct inode *inode, struct file *filp);
 extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
 extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma);
 extern void drm_vm_open_locked(struct vm_area_struct *vma);
+extern void drm_vm_close_locked(struct vm_area_struct *vma);
 extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
 
                                /* Memory management support (drm_memory.h) */
@@ -1378,7 +1372,6 @@ extern int drm_bufs_info(struct seq_file *m, void *data);
 extern int drm_vblank_info(struct seq_file *m, void *data);
 extern int drm_clients_info(struct seq_file *m, void* data);
 extern int drm_gem_name_info(struct seq_file *m, void *data);
-extern int drm_gem_object_info(struct seq_file *m, void* data);
 
 #if DRM_DEBUG_CODE
 extern int drm_vma_info(struct seq_file *m, void *data);
@@ -1419,12 +1412,11 @@ int drm_gem_init(struct drm_device *dev);
 void drm_gem_destroy(struct drm_device *dev);
 void drm_gem_object_release(struct drm_gem_object *obj);
 void drm_gem_object_free(struct kref *kref);
-void drm_gem_object_free_unlocked(struct kref *kref);
 struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
                                            size_t size);
 int drm_gem_object_init(struct drm_device *dev,
                        struct drm_gem_object *obj, size_t size);
-void drm_gem_object_handle_free(struct kref *kref);
+void drm_gem_object_handle_free(struct drm_gem_object *obj);
 void drm_gem_vm_open(struct vm_area_struct *vma);
 void drm_gem_vm_close(struct vm_area_struct *vma);
 int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
@@ -1447,8 +1439,12 @@ drm_gem_object_unreference(struct drm_gem_object *obj)
 static inline void
 drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
 {
-       if (obj != NULL)
-               kref_put(&obj->refcount, drm_gem_object_free_unlocked);
+       if (obj != NULL) {
+               struct drm_device *dev = obj->dev;
+               mutex_lock(&dev->struct_mutex);
+               kref_put(&obj->refcount, drm_gem_object_free);
+               mutex_unlock(&dev->struct_mutex);
+       }
 }
 
 int drm_gem_handle_create(struct drm_file *file_priv,
@@ -1459,7 +1455,7 @@ static inline void
 drm_gem_object_handle_reference(struct drm_gem_object *obj)
 {
        drm_gem_object_reference(obj);
-       kref_get(&obj->handlecount);
+       atomic_inc(&obj->handle_count);
 }
 
 static inline void
@@ -1468,12 +1464,15 @@ drm_gem_object_handle_unreference(struct drm_gem_object *obj)
        if (obj == NULL)
                return;
 
+       if (atomic_read(&obj->handle_count) == 0)
+               return;
        /*
         * Must bump handle count first as this may be the last
         * ref, in which case the object would disappear before we
         * checked for a name
         */
-       kref_put(&obj->handlecount, drm_gem_object_handle_free);
+       if (atomic_dec_and_test(&obj->handle_count))
+               drm_gem_object_handle_free(obj);
        drm_gem_object_unreference(obj);
 }
 
@@ -1483,12 +1482,17 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
        if (obj == NULL)
                return;
 
+       if (atomic_read(&obj->handle_count) == 0)
+               return;
+
        /*
        * Must bump handle count first as this may be the last
        * ref, in which case the object would disappear before we
        * checked for a name
        */
-       kref_put(&obj->handlecount, drm_gem_object_handle_free);
+
+       if (atomic_dec_and_test(&obj->handle_count))
+               drm_gem_object_handle_free(obj);
        drm_gem_object_unreference_unlocked(obj);
 }
 
index 3e5a51af757c76ba07f514d00265a5e7300b6627..15c4796fd467f2d145516b78b949b5f80e042823 100644 (file)
@@ -221,7 +221,8 @@ struct drm_framebuffer_funcs {
         * the semantics and arguments have a one to one mapping
         * on this function.
         */
-       int (*dirty)(struct drm_framebuffer *framebuffer, unsigned flags,
+       int (*dirty)(struct drm_framebuffer *framebuffer,
+                    struct drm_file *file_priv, unsigned flags,
                     unsigned color, struct drm_clip_rect *clips,
                     unsigned num_clips);
 };
index 3a9940ef728bb5d2412c4cb54d84ed746e15d870..883c1d4398996d8ba807ca5d54940cec28c7809e 100644 (file)
@@ -85,7 +85,6 @@
        {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
        {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
        {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
-       {0x1002, 0x5657, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x5657, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
        {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
        {0x1002, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h
new file mode 100644 (file)
index 0000000..d3c8194
--- /dev/null
@@ -0,0 +1,18 @@
+/* Common header for intel-gtt.ko and i915.ko */
+
+#ifndef _DRM_INTEL_GTT_H
+#define        _DRM_INTEL_GTT_H
+struct intel_gtt {
+       /* Number of stolen gtt entries at the beginning. */
+       unsigned int gtt_stolen_entries;
+       /* Total number of gtt entries. */
+       unsigned int gtt_total_entries;
+       /* Part of the gtt that is mappable by the cpu, for those chips where
+        * this is not the full gtt. */
+       unsigned int gtt_mappable_entries;
+};
+
+struct intel_gtt *intel_gtt_get(void);
+
+#endif
+
index 4d0842391edc666f8985329fed245b989e3a0c2d..650e6bf6f69f101999d0294497458c3d5100e55f 100644 (file)
@@ -72,6 +72,7 @@
 #define DRM_VMW_PARAM_FIFO_OFFSET      3
 #define DRM_VMW_PARAM_HW_CAPS          4
 #define DRM_VMW_PARAM_FIFO_CAPS        5
+#define DRM_VMW_PARAM_MAX_FB_SIZE      6
 
 /**
  * struct drm_vmw_getparam_arg
index 46f5dacf90a2cd62427fdf89b67fa01ef8af68e0..ec520c7b28dffedb5027de6b27834831938671cd 100644 (file)
@@ -125,7 +125,6 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
 {
        struct mm_struct *mm = current->mm;
        struct address_space *mapping;
-       unsigned long end = start + size;
        struct vm_area_struct *vma;
        int err = -EINVAL;
        int has_write_lock = 0;
@@ -142,6 +141,10 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
        if (start + size <= start)
                return err;
 
+       /* Does pgoff wrap? */
+       if (pgoff + (size >> PAGE_SHIFT) < pgoff)
+               return err;
+
        /* Can we represent this offset inside this architecture's pte's? */
 #if PTE_FILE_MAX_BITS < BITS_PER_LONG
        if (pgoff + (size >> PAGE_SHIFT) >= (1UL << PTE_FILE_MAX_BITS))
@@ -168,7 +171,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
        if (!(vma->vm_flags & VM_CAN_NONLINEAR))
                goto out;
 
-       if (end <= start || start < vma->vm_start || end > vma->vm_end)
+       if (start < vma->vm_start || start + size > vma->vm_end)
                goto out;
 
        /* Must set VM_NONLINEAR before any pages are populated. */
index b697fd2a6f8b8cd19a84840fd8e05369226981db..10bbbaf6ebc3d2b0531ba2fb1ab7e3f2be1f8994 100644 (file)
@@ -3641,6 +3641,7 @@ static struct snd_pci_quirk ad1984_cfg_tbl[] = {
        /* Lenovo Thinkpad T61/X61 */
        SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
        SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
+       SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
        {}
 };
 
index a1312a6c8af2c91453be56f1b554de11307ce4d0..a432e6efd19bbe7bbce3ad9b6607c44661f912cf 100644 (file)
@@ -1594,12 +1594,22 @@ static void alc_auto_parse_digital(struct hda_codec *codec)
        }
 
        if (spec->autocfg.dig_in_pin) {
-               hda_nid_t dig_nid;
-               err = snd_hda_get_connections(codec,
-                                             spec->autocfg.dig_in_pin,
-                                             &dig_nid, 1);
-               if (err > 0)
-                       spec->dig_in_nid = dig_nid;
+               dig_nid = codec->start_nid;
+               for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
+                       unsigned int wcaps = get_wcaps(codec, dig_nid);
+                       if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
+                               continue;
+                       if (!(wcaps & AC_WCAP_DIGITAL))
+                               continue;
+                       if (!(wcaps & AC_WCAP_CONN_LIST))
+                               continue;
+                       err = get_connection_index(codec, dig_nid,
+                                                  spec->autocfg.dig_in_pin);
+                       if (err >= 0) {
+                               spec->dig_in_nid = dig_nid;
+                               break;
+                       }
+               }
        }
 }
 
index 289cb4dacfc79ec012b6efb174054efaa0afe855..6c0a11adb2a84511b83b23b69d5efce9fb2085c6 100644 (file)
@@ -543,6 +543,10 @@ static int __devinit get_oxygen_model(struct oxygen *chip,
                chip->model.suspend = claro_suspend;
                chip->model.resume = claro_resume;
                chip->model.set_adc_params = set_ak5385_params;
+               chip->model.device_config = PLAYBACK_0_TO_I2S |
+                                           PLAYBACK_1_TO_SPDIF |
+                                           CAPTURE_0_FROM_I2S_2 |
+                                           CAPTURE_1_FROM_SPDIF;
                break;
        }
        if (id->driver_data == MODEL_MERIDIAN ||
index b92adef8e81e7ae61eef5681925610b87f03a502..d6fa7bfd9aa123d7f8bb8142a8def39888129434 100644 (file)
@@ -4609,6 +4609,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                if (err < 0)
                        return err;
 
+               memset(&info, 0, sizeof(info));
                spin_lock_irqsave(&hdsp->lock, flags);
                info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp);
                info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp);
index 547b713d720449a7bdd746ca04fbf5a6cbe84931..0c98ef9156d8fd919f81711fe7b798be7c0ca7d8 100644 (file)
@@ -4127,6 +4127,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file,
 
        case SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO:
 
+               memset(&info, 0, sizeof(info));
                spin_lock_irq(&hdspm->lock);
                info.pref_sync_ref = hdspm_pref_sync_ref(hdspm);
                info.wordclock_sync_check = hdspm_wc_sync_check(hdspm);
index b823a5c9b9bc81d81b8f64f4847483eae3f253bc..87e2b7fcbf176d9f429506b285dcc2f6ac05d7bc 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 
+#include <asm/clkdev.h>
 #include <asm/clock.h>
 
 #include <cpu/sh7722.h>
@@ -40,12 +41,12 @@ static struct clk_ops siumckb_clk_ops = {
 };
 
 static struct clk siumckb_clk = {
-       .name           = "siumckb_clk",
-       .id             = -1,
        .ops            = &siumckb_clk_ops,
        .rate           = 0, /* initialised at run-time */
 };
 
+static struct clk_lookup *siumckb_lookup;
+
 static int migor_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params)
 {
@@ -180,6 +181,13 @@ static int __init migor_init(void)
        if (ret < 0)
                return ret;
 
+       siumckb_lookup = clkdev_alloc(&siumckb_clk, "siumckb_clk", NULL);
+       if (!siumckb_lookup) {
+               ret = -ENOMEM;
+               goto eclkdevalloc;
+       }
+       clkdev_add(siumckb_lookup);
+
        /* Port number used on this machine: port B */
        migor_snd_device = platform_device_alloc("soc-audio", 1);
        if (!migor_snd_device) {
@@ -200,12 +208,15 @@ static int __init migor_init(void)
 epdevadd:
        platform_device_put(migor_snd_device);
 epdevalloc:
+       clkdev_drop(siumckb_lookup);
+eclkdevalloc:
        clk_unregister(&siumckb_clk);
        return ret;
 }
 
 static void __exit migor_exit(void)
 {
+       clkdev_drop(siumckb_lookup);
        clk_unregister(&siumckb_clk);
        platform_device_unregister(migor_snd_device);
 }
index adbc68ce90508221cc919121fc19e062fd309f44..f6b0d2829ea96d438d1e84550272c6a7bda80b4c 100644 (file)
@@ -203,8 +203,9 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
        data[1] = (value >> 8) & 0xff;
        data[2] = value & 0xff;
 
-       if (!snd_soc_codec_volatile_register(codec, reg))
-               reg_cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg)
+               && reg < codec->reg_cache_size)
+                       reg_cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;