From 43d1b4e38a04008feadd3b6edc062be17a45ec00 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 26 Aug 2010 16:13:49 +0200 Subject: [PATCH] --- yaml --- r: 218158 b: refs/heads/master c: 316f60a120a8f1dacb574f705d5faf7eac3e6e2a h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/MAINTAINERS | 11 - trunk/arch/alpha/kernel/entry.S | 11 +- trunk/arch/alpha/kernel/process.c | 2 +- trunk/arch/m32r/include/asm/signal.h | 1 + trunk/arch/m32r/include/asm/unistd.h | 1 - trunk/arch/m32r/kernel/entry.S | 5 +- trunk/arch/m32r/kernel/ptrace.c | 7 +- trunk/arch/m32r/kernel/signal.c | 105 +- trunk/arch/tile/kernel/intvec_32.S | 7 + trunk/arch/x86/include/asm/cpufeature.h | 1 - trunk/arch/x86/kernel/cpu/scattered.c | 1 - trunk/block/blk-merge.c | 12 - trunk/drivers/char/agp/Makefile | 1 - trunk/drivers/char/agp/agp.h | 5 + trunk/drivers/char/agp/backend.c | 22 +- trunk/drivers/char/agp/generic.c | 8 + trunk/drivers/char/agp/intel-agp.c | 200 +- trunk/drivers/char/agp/intel-agp.h | 43 +- trunk/drivers/char/agp/intel-gtt.c | 1614 ++++++------ trunk/drivers/gpu/drm/drm_buffer.c | 6 +- trunk/drivers/gpu/drm/drm_crtc.c | 3 +- trunk/drivers/gpu/drm/drm_debugfs.c | 1 + trunk/drivers/gpu/drm/drm_edid.c | 1 + trunk/drivers/gpu/drm/drm_gem.c | 51 +- trunk/drivers/gpu/drm/drm_info.c | 16 +- trunk/drivers/gpu/drm/drm_lock.c | 5 - trunk/drivers/gpu/drm/drm_proc.c | 1 + trunk/drivers/gpu/drm/drm_vm.c | 28 +- trunk/drivers/gpu/drm/i810/i810_dma.c | 2 +- trunk/drivers/gpu/drm/i830/i830_dma.c | 2 +- trunk/drivers/gpu/drm/i915/Makefile | 2 +- trunk/drivers/gpu/drm/i915/dvo_ch7017.c | 66 +- trunk/drivers/gpu/drm/i915/dvo_ch7xxx.c | 10 +- trunk/drivers/gpu/drm/i915/dvo_ivch.c | 10 +- trunk/drivers/gpu/drm/i915/dvo_sil164.c | 10 +- trunk/drivers/gpu/drm/i915/dvo_tfp410.c | 10 +- trunk/drivers/gpu/drm/i915/i915_debugfs.c | 340 +-- trunk/drivers/gpu/drm/i915/i915_dma.c | 327 ++- trunk/drivers/gpu/drm/i915/i915_drv.c | 210 +- trunk/drivers/gpu/drm/i915/i915_drv.h | 226 +- trunk/drivers/gpu/drm/i915/i915_gem.c | 1162 ++++----- trunk/drivers/gpu/drm/i915/i915_gem_debug.c | 148 +- trunk/drivers/gpu/drm/i915/i915_gem_evict.c | 50 +- trunk/drivers/gpu/drm/i915/i915_gem_tiling.c | 52 +- trunk/drivers/gpu/drm/i915/i915_irq.c | 183 +- .../{intel_opregion.c => i915_opregion.c} | 181 +- trunk/drivers/gpu/drm/i915/i915_reg.h | 298 +-- trunk/drivers/gpu/drm/i915/i915_suspend.c | 28 +- trunk/drivers/gpu/drm/i915/intel_bios.c | 171 +- trunk/drivers/gpu/drm/i915/intel_bios.h | 3 +- trunk/drivers/gpu/drm/i915/intel_crt.c | 124 +- trunk/drivers/gpu/drm/i915/intel_display.c | 2321 ++++++++--------- trunk/drivers/gpu/drm/i915/intel_dp.c | 272 +- trunk/drivers/gpu/drm/i915/intel_drv.h | 126 +- trunk/drivers/gpu/drm/i915/intel_dvo.c | 69 +- trunk/drivers/gpu/drm/i915/intel_fb.c | 33 +- trunk/drivers/gpu/drm/i915/intel_hdmi.c | 61 +- trunk/drivers/gpu/drm/i915/intel_i2c.c | 483 +--- trunk/drivers/gpu/drm/i915/intel_lvds.c | 435 ++- trunk/drivers/gpu/drm/i915/intel_modes.c | 16 +- trunk/drivers/gpu/drm/i915/intel_overlay.c | 1006 ++++--- trunk/drivers/gpu/drm/i915/intel_panel.c | 109 - trunk/drivers/gpu/drm/i915/intel_ringbuffer.c | 393 ++- trunk/drivers/gpu/drm/i915/intel_ringbuffer.h | 66 +- trunk/drivers/gpu/drm/i915/intel_sdvo.c | 894 +++---- trunk/drivers/gpu/drm/i915/intel_tv.c | 165 +- .../gpu/drm/nouveau/nouveau_connector.c | 6 +- trunk/drivers/gpu/drm/nouveau/nouveau_fbcon.c | 1 - trunk/drivers/gpu/drm/nouveau/nouveau_gem.c | 6 +- trunk/drivers/gpu/drm/nouveau/nouveau_mem.c | 3 +- .../gpu/drm/nouveau/nouveau_notifier.c | 1 - trunk/drivers/gpu/drm/radeon/atombios.h | 2 +- trunk/drivers/gpu/drm/radeon/r600.c | 5 +- .../drivers/gpu/drm/radeon/radeon_atombios.c | 9 - trunk/drivers/gpu/drm/radeon/radeon_display.c | 5 +- trunk/drivers/gpu/drm/radeon/radeon_fb.c | 14 +- trunk/drivers/gpu/drm/radeon/radeon_gem.c | 4 +- trunk/drivers/gpu/drm/radeon/radeon_kms.c | 4 - trunk/drivers/gpu/drm/ttm/ttm_bo_util.c | 1 - trunk/drivers/gpu/drm/ttm/ttm_page_alloc.c | 8 +- trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 257 +- trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 19 +- trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 15 - trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 3 - trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 3 - trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 217 +- trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 55 +- .../drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 4 - trunk/drivers/gpu/vga/vgaarb.c | 2 +- trunk/drivers/hwmon/Kconfig | 2 +- trunk/drivers/hwmon/coretemp.c | 56 +- trunk/drivers/hwmon/lis3lv02d.c | 4 +- trunk/drivers/hwmon/pkgtemp.c | 23 +- trunk/drivers/staging/ti-st/st.h | 1 + trunk/drivers/staging/ti-st/st_core.c | 9 +- trunk/drivers/staging/ti-st/st_core.h | 2 +- trunk/drivers/staging/ti-st/st_kim.c | 22 +- trunk/drivers/usb/core/Kconfig | 6 +- trunk/drivers/usb/core/file.c | 35 +- trunk/drivers/usb/core/message.c | 1 - trunk/drivers/usb/musb/cppi_dma.c | 1 - trunk/drivers/usb/musb/musb_gadget.c | 75 +- trunk/drivers/usb/musb/musb_gadget.h | 2 - trunk/drivers/usb/musb/musb_gadget_ep0.c | 9 - trunk/drivers/usb/musb/musb_host.c | 6 - trunk/fs/ocfs2/acl.c | 3 - trunk/fs/ocfs2/cluster/tcp.c | 2 +- trunk/fs/ocfs2/dir.c | 24 +- trunk/fs/ocfs2/dlm/dlmcommon.h | 1 - trunk/fs/ocfs2/dlm/dlmdebug.c | 9 +- trunk/fs/ocfs2/dlm/dlmdomain.c | 1 - trunk/fs/ocfs2/dlm/dlmmaster.c | 40 - trunk/fs/ocfs2/dlmglue.h | 1 - trunk/fs/ocfs2/ocfs2_fs.h | 37 +- trunk/fs/ocfs2/ocfs2_ioctl.h | 8 +- trunk/fs/ocfs2/refcounttree.c | 5 +- trunk/fs/ocfs2/reservations.c | 22 +- trunk/fs/ocfs2/suballoc.c | 4 +- trunk/fs/ocfs2/xattr.c | 4 +- trunk/include/drm/drmP.h | 36 +- trunk/include/drm/drm_crtc.h | 3 +- trunk/include/drm/drm_pciids.h | 2 +- trunk/include/drm/intel-gtt.h | 18 - trunk/include/drm/vmwgfx_drm.h | 1 - trunk/mm/fremap.c | 7 +- trunk/sound/pci/hda/patch_analog.c | 1 - trunk/sound/pci/hda/patch_realtek.c | 22 +- trunk/sound/pci/oxygen/oxygen.c | 4 - trunk/sound/pci/rme9652/hdsp.c | 1 - trunk/sound/pci/rme9652/hdspm.c | 1 - trunk/sound/soc/sh/migor.c | 15 +- trunk/sound/soc/soc-cache.c | 5 +- 133 files changed, 6089 insertions(+), 7321 deletions(-) rename trunk/drivers/gpu/drm/i915/{intel_opregion.c => i915_opregion.c} (81%) delete mode 100644 trunk/include/drm/intel-gtt.h diff --git a/[refs] b/[refs] index 064aaea1cbb7..58b965f4070d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: e6b46ee712b92db1cc2449cf4f65bc635366cad4 +refs/heads/master: 316f60a120a8f1dacb574f705d5faf7eac3e6e2a diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 5e1169df8c1f..df342839b8c1 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2051,15 +2051,6 @@ S: Maintained F: drivers/gpu/drm/ F: include/drm/ -INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets) -M: Chris Wilson -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 L: netdev@vger.kernel.org @@ -2677,8 +2668,6 @@ M: Guenter Roeck 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/ diff --git a/trunk/arch/alpha/kernel/entry.S b/trunk/arch/alpha/kernel/entry.S index d1273c1a1364..ab1ee0ab082b 100644 --- a/trunk/arch/alpha/kernel/entry.S +++ b/trunk/arch/alpha/kernel/entry.S @@ -73,6 +73,8 @@ 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); \ @@ -314,7 +316,7 @@ ret_from_sys_call: cmovne $26, 0, $19 /* $19 = 0 => non-restartable */ ldq $0, SP_OFF($sp) and $0, 8, $0 - beq $0, ret_to_kernel + beq $0, restore_all ret_to_user: /* Make sure need_resched and sigpending don't change between sampling and the rti. */ @@ -327,11 +329,6 @@ 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: /* @@ -660,7 +657,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 ret_to_kernel + br restore_all .end kernel_thread /* diff --git a/trunk/arch/alpha/kernel/process.c b/trunk/arch/alpha/kernel/process.c index 3ec35066f1dc..842dba308eab 100644 --- a/trunk/arch/alpha/kernel/process.c +++ b/trunk/arch/alpha/kernel/process.c @@ -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] = ti == current_thread_info() ? rdusp() : ti->pcb.usp; + dest[30] = rdusp(); dest[31] = pt->pc; /* Once upon a time this was the PS value. Which is stupid diff --git a/trunk/arch/m32r/include/asm/signal.h b/trunk/arch/m32r/include/asm/signal.h index b2eeb0de1c8d..9c1acb2b1a92 100644 --- a/trunk/arch/m32r/include/asm/signal.h +++ b/trunk/arch/m32r/include/asm/signal.h @@ -157,6 +157,7 @@ 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) diff --git a/trunk/arch/m32r/include/asm/unistd.h b/trunk/arch/m32r/include/asm/unistd.h index c70545689da8..76125777483c 100644 --- a/trunk/arch/m32r/include/asm/unistd.h +++ b/trunk/arch/m32r/include/asm/unistd.h @@ -351,7 +351,6 @@ #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 diff --git a/trunk/arch/m32r/kernel/entry.S b/trunk/arch/m32r/kernel/entry.S index 225412bc227e..403869833b98 100644 --- a/trunk/arch/m32r/kernel/entry.S +++ b/trunk/arch/m32r/kernel/entry.S @@ -235,9 +235,10 @@ work_resched: work_notifysig: ; deal with pending signals and ; notify-resume requests mv r0, sp ; arg1 : struct pt_regs *regs - mv r1, r9 ; arg2 : __u32 thread_info_flags + ldi r1, #0 ; arg2 : sigset_t *oldset + mv r2, r9 ; arg3 : __u32 thread_info_flags bl do_notify_resume - bra resume_userspace + bra restore_all ; perform syscall exit tracing ALIGN diff --git a/trunk/arch/m32r/kernel/ptrace.c b/trunk/arch/m32r/kernel/ptrace.c index 0021ade4cba8..e555091eb97c 100644 --- a/trunk/arch/m32r/kernel/ptrace.c +++ b/trunk/arch/m32r/kernel/ptrace.c @@ -592,17 +592,16 @@ void user_enable_single_step(struct task_struct *child) if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0) != sizeof(insn)) - return -EIO; + break; compute_next_pc(insn, pc, &next_pc, child); if (next_pc & 0x80000000) - return -EIO; + break; if (embed_debug_trap(child, next_pc)) - return -EIO; + break; invalidate_cache(); - return 0; } void user_disable_single_step(struct task_struct *child) diff --git a/trunk/arch/m32r/kernel/signal.c b/trunk/arch/m32r/kernel/signal.c index 7bbe38645ed5..144b0f124fc7 100644 --- a/trunk/arch/m32r/kernel/signal.c +++ b/trunk/arch/m32r/kernel/signal.c @@ -28,6 +28,37 @@ #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(¤t->sighand->siglock); + current->saved_sigmask = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->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, @@ -187,7 +218,7 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) return (void __user *)((sp - frame_size) & -8ul); } -static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, +static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe __user *frame; @@ -244,34 +275,22 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, current->comm, current->pid, frame, regs->pc); #endif - return 0; + return; 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 int +static void 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.. */ @@ -289,14 +308,16 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, /* fallthrough */ case -ERESTARTNOINTR: regs->r0 = regs->orig_r0; - if (prev_insn(regs) < 0) - return -EFAULT; + inst = *(unsigned short *)(regs->bpc - 2); + if ((inst & 0xfff0) == 0x10f0) /* trap ? */ + regs->bpc -= 2; + else + regs->bpc -= 4; } } /* Set up the stack frame */ - if (setup_rt_frame(sig, ka, info, oldset, regs)) - return -EFAULT; + setup_rt_frame(sig, ka, info, oldset, regs); spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -304,7 +325,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - return 0; } /* @@ -312,12 +332,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. */ -static void do_signal(struct pt_regs *regs) +int do_signal(struct pt_regs *regs, sigset_t *oldset) { siginfo_t info; int signr; struct k_sigaction ka; - sigset_t *oldset; + unsigned short inst; /* * We want the common case to go fast, which @@ -326,14 +346,12 @@ static void do_signal(struct pt_regs *regs) * if so. */ if (!user_mode(regs)) - return; + return 1; if (try_to_freeze()) goto no_signal; - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - oldset = ¤t->saved_sigmask; - else + if (!oldset) oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, NULL); @@ -345,10 +363,8 @@ static void do_signal(struct pt_regs *regs) */ /* Whee! Actually deliver the signal. */ - if (handle_signal(signr, &ka, &info, oldset, regs) == 0) - clear_thread_flag(TIF_RESTORE_SIGMASK); - - return; + handle_signal(signr, &ka, &info, oldset, regs); + return 1; } no_signal: @@ -359,24 +375,31 @@ static void do_signal(struct pt_regs *regs) regs->r0 == -ERESTARTSYS || regs->r0 == -ERESTARTNOINTR) { regs->r0 = regs->orig_r0; - prev_insn(regs); - } else if (regs->r0 == -ERESTART_RESTARTBLOCK){ + inst = *(unsigned short *)(regs->bpc - 2); + if ((inst & 0xfff0) == 0x10f0) /* trap ? */ + regs->bpc -= 2; + else + regs->bpc -= 4; + } + if (regs->r0 == -ERESTART_RESTARTBLOCK){ regs->r0 = regs->orig_r0; regs->r7 = __NR_restart_syscall; - prev_insn(regs); + inst = *(unsigned short *)(regs->bpc - 2); + if ((inst & 0xfff0) == 0x10f0) /* trap ? */ + regs->bpc -= 2; + else + regs->bpc -= 4; } } - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); - sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); - } + return 0; } /* * notification of userspace execution resumption * - triggered by current->work.notify_resume */ -void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags) +void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, + __u32 thread_info_flags) { /* Pending single-step? */ if (thread_info_flags & _TIF_SINGLESTEP) @@ -384,7 +407,7 @@ void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags) /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs); + do_signal(regs,oldset); if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); diff --git a/trunk/arch/tile/kernel/intvec_32.S b/trunk/arch/tile/kernel/intvec_32.S index 8f58bdff20d7..84f296ca9e63 100644 --- a/trunk/arch/tile/kernel/intvec_32.S +++ b/trunk/arch/tile/kernel/intvec_32.S @@ -1506,6 +1506,13 @@ 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) diff --git a/trunk/arch/x86/include/asm/cpufeature.h b/trunk/arch/x86/include/asm/cpufeature.h index 3f76523589af..c6fbb7b430d1 100644 --- a/trunk/arch/x86/include/asm/cpufeature.h +++ b/trunk/arch/x86/include/asm/cpufeature.h @@ -168,7 +168,6 @@ #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 */ diff --git a/trunk/arch/x86/kernel/cpu/scattered.c b/trunk/arch/x86/kernel/cpu/scattered.c index d49079515122..34b4dad6f0b8 100644 --- a/trunk/arch/x86/kernel/cpu/scattered.c +++ b/trunk/arch/x86/kernel/cpu/scattered.c @@ -31,7 +31,6 @@ 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 }, diff --git a/trunk/block/blk-merge.c b/trunk/block/blk-merge.c index eafc94f68d79..3b0cd4249671 100644 --- a/trunk/block/blk-merge.c +++ b/trunk/block/blk-merge.c @@ -361,18 +361,6 @@ 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 */ diff --git a/trunk/drivers/char/agp/Makefile b/trunk/drivers/char/agp/Makefile index 8eb56e273e75..627f542827c7 100644 --- a/trunk/drivers/char/agp/Makefile +++ b/trunk/drivers/char/agp/Makefile @@ -13,7 +13,6 @@ 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 diff --git a/trunk/drivers/char/agp/agp.h b/trunk/drivers/char/agp/agp.h index 5259065f3c79..120490949997 100644 --- a/trunk/drivers/char/agp/agp.h +++ b/trunk/drivers/char/agp/agp.h @@ -121,6 +121,11 @@ 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 { diff --git a/trunk/drivers/char/agp/backend.c b/trunk/drivers/char/agp/backend.c index f27d0d0816d3..ee4f855611b6 100644 --- a/trunk/drivers/char/agp/backend.c +++ b/trunk/drivers/char/agp/backend.c @@ -151,7 +151,17 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) } bridge->scratch_page_page = page; - bridge->scratch_page_dma = page_to_phys(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 = bridge->driver->mask_memory(bridge, bridge->scratch_page_dma, 0); @@ -194,6 +204,12 @@ 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); @@ -224,6 +240,10 @@ 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); } diff --git a/trunk/drivers/char/agp/generic.c b/trunk/drivers/char/agp/generic.c index 78235ceccfa1..d2abf5143983 100644 --- a/trunk/drivers/char/agp/generic.c +++ b/trunk/drivers/char/agp/generic.c @@ -437,6 +437,11 @@ 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) @@ -478,6 +483,9 @@ 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); diff --git a/trunk/drivers/char/agp/intel-agp.c b/trunk/drivers/char/agp/intel-agp.c index 5cd2221ab472..cd18493c9527 100644 --- a/trunk/drivers/char/agp/intel-agp.c +++ b/trunk/drivers/char/agp/intel-agp.c @@ -12,6 +12,9 @@ #include #include "agp.h" #include "intel-agp.h" +#include + +#include "intel-gtt.c" int intel_agp_enabled; EXPORT_SYMBOL(intel_agp_enabled); @@ -700,37 +703,179 @@ 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_agp_driver_description { +static const struct intel_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, "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 } + { 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 } }; +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) { @@ -760,7 +905,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, } } - if (!bridge->driver) { + if (intel_agp_chipsets[i].name == NULL) { if (cap_ptr) dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n", pdev->vendor, pdev->device); @@ -768,6 +913,14 @@ 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; @@ -819,7 +972,8 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) agp_remove_bridge(bridge); - intel_gmch_remove(pdev); + if (intel_private.pcidev) + pci_dev_put(intel_private.pcidev); agp_put_bridge(bridge); } diff --git a/trunk/drivers/char/agp/intel-agp.h b/trunk/drivers/char/agp/intel-agp.h index 90539df02504..d09b1ab7e8ab 100644 --- a/trunk/drivers/char/agp/intel-agp.h +++ b/trunk/drivers/char/agp/intel-agp.h @@ -215,7 +215,44 @@ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB 0x0108 /* Server */ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG 0x010A -int intel_gmch_probe(struct pci_dev *pdev, - struct agp_bridge_data *bridge); -void intel_gmch_remove(struct pci_dev *pdev); +/* 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) + #endif diff --git a/trunk/drivers/char/agp/intel-gtt.c b/trunk/drivers/char/agp/intel-gtt.c index 0c8ff6d8824b..75e0a3497888 100644 --- a/trunk/drivers/char/agp/intel-gtt.c +++ b/trunk/drivers/char/agp/intel-gtt.c @@ -15,18 +15,6 @@ * /fairy-tale-mode off */ -#include -#include -#include -#include -#include -#include -#include -#include "agp.h" -#include "intel-agp.h" -#include -#include - /* * 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 @@ -35,12 +23,11 @@ */ #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[] = { @@ -68,36 +55,32 @@ static struct gatt_mask intel_i810_masks[] = #define INTEL_AGP_CACHED_MEMORY_LLC_MLC 3 #define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT 4 -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 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 }, }; 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; @@ -105,14 +88,23 @@ 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; -#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 +#ifdef USE_PCI_DMA_API +static int intel_agp_map_page(struct page *page, dma_addr_t *ret) +{ + *ret = pci_map_page(intel_private.pcidev, page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(intel_private.pcidev, *ret)) + return -EINVAL; + return 0; +} + +static void intel_agp_unmap_page(struct page *page, dma_addr_t dma) +{ + pci_unmap_page(intel_private.pcidev, dma, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); +} static void intel_agp_free_sglist(struct agp_memory *mem) { @@ -133,9 +125,6 @@ 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)) @@ -167,17 +156,70 @@ 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(intel_private.bridge_dev, - I810_SMRAM_MISCC, &smram_miscc); + pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc); values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { - dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n"); + dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n"); return 0; } if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { @@ -242,7 +284,7 @@ static void intel_i810_cleanup(void) iounmap(intel_private.registers); } -static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) +static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode) { return; } @@ -277,6 +319,34 @@ 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) { @@ -444,33 +514,8 @@ static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, return addr | bridge->driver->masks[type].mask; } -static int intel_gtt_setup_scratch_page(void) +static struct aper_size_info_fixed intel_i830_sizes[] = { - 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}, @@ -478,49 +523,102 @@ static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = { {512, 131072, 7}, }; -static unsigned int intel_gtt_stolen_entries(void) +static void intel_i830_init_gtt_entries(void) { u16 gmch_ctrl; + int gtt_entries = 0; u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; - unsigned int overhead_entries, stolen_entries; - unsigned int stolen_size = 0; + int size; /* reserved space (in kb) at the top of stolen memory */ - pci_read_config_word(intel_private.bridge_dev, - I830_GMCH_CTRL, &gmch_ctrl); + pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); - if (INTEL_GTT_GEN > 4 || IS_PINEVIEW) - overhead_entries = 0; - else - overhead_entries = intel_private.base.gtt_mappable_entries - / 1024; + if (IS_I965) { + u32 pgetbl_ctl; + pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); - overhead_entries += 1; /* BIOS popup */ + /* The 965 has a field telling us the size of the GTT, + * which may be larger than what is necessary to map the + * aperture. + */ + switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { + case I965_PGETBL_SIZE_128KB: + size = 128; + break; + case I965_PGETBL_SIZE_256KB: + size = 256; + break; + case I965_PGETBL_SIZE_512KB: + size = 512; + break; + case I965_PGETBL_SIZE_1MB: + size = 1024; + break; + case I965_PGETBL_SIZE_2MB: + size = 2048; + break; + case I965_PGETBL_SIZE_1_5MB: + size = 1024 + 512; + break; + default: + dev_info(&intel_private.pcidev->dev, + "unknown page table size, assuming 512KB\n"); + size = 512; + } + size += 4; /* add in BIOS popup space */ + } else if (IS_G33 && !IS_PINEVIEW) { + /* G33's GTT size defined in gmch_ctrl */ + switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { + case G33_PGETBL_SIZE_1M: + size = 1024; + break; + case G33_PGETBL_SIZE_2M: + size = 2048; + break; + default: + dev_info(&agp_bridge->dev->dev, + "unknown page table size 0x%x, assuming 512KB\n", + (gmch_ctrl & G33_PGETBL_SIZE_MASK)); + size = 512; + } + size += 4; + } else if (IS_G4X || IS_PINEVIEW) { + /* On 4 series hardware, GTT stolen is separate from graphics + * stolen, ignore it in stolen gtt entries counting. However, + * 4KB of the stolen memory doesn't get mapped to the GTT. + */ + size = 4; + } else { + /* On previous hardware, the GTT size was just what was + * required to map the aperture. + */ + size = agp_bridge->driver->fetch_size() + 4; + } - if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || - intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { + if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I830_GMCH_GMS_STOLEN_512: - stolen_size = KB(512); + gtt_entries = KB(512) - KB(size); break; case I830_GMCH_GMS_STOLEN_1024: - stolen_size = MB(1); + gtt_entries = MB(1) - KB(size); break; case I830_GMCH_GMS_STOLEN_8192: - stolen_size = MB(8); + gtt_entries = MB(8) - KB(size); break; case I830_GMCH_GMS_LOCAL: rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE); - stolen_size = (I830_RDRAM_ND(rdct) + 1) * + gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]); local = 1; break; default: - stolen_size = 0; + gtt_entries = 0; break; } - } else if (INTEL_GTT_GEN == 6) { + } else if (IS_SNB) { /* * SandyBridge has new memory control reg at 0x50.w */ @@ -528,292 +626,149 @@ static unsigned int intel_gtt_stolen_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: - stolen_size = MB(32); + gtt_entries = MB(32) - KB(size); break; case SNB_GMCH_GMS_STOLEN_64M: - stolen_size = MB(64); + gtt_entries = MB(64) - KB(size); break; case SNB_GMCH_GMS_STOLEN_96M: - stolen_size = MB(96); + gtt_entries = MB(96) - KB(size); break; case SNB_GMCH_GMS_STOLEN_128M: - stolen_size = MB(128); + gtt_entries = MB(128) - KB(size); break; case SNB_GMCH_GMS_STOLEN_160M: - stolen_size = MB(160); + gtt_entries = MB(160) - KB(size); break; case SNB_GMCH_GMS_STOLEN_192M: - stolen_size = MB(192); + gtt_entries = MB(192) - KB(size); break; case SNB_GMCH_GMS_STOLEN_224M: - stolen_size = MB(224); + gtt_entries = MB(224) - KB(size); break; case SNB_GMCH_GMS_STOLEN_256M: - stolen_size = MB(256); + gtt_entries = MB(256) - KB(size); break; case SNB_GMCH_GMS_STOLEN_288M: - stolen_size = MB(288); + gtt_entries = MB(288) - KB(size); break; case SNB_GMCH_GMS_STOLEN_320M: - stolen_size = MB(320); + gtt_entries = MB(320) - KB(size); break; case SNB_GMCH_GMS_STOLEN_352M: - stolen_size = MB(352); + gtt_entries = MB(352) - KB(size); break; case SNB_GMCH_GMS_STOLEN_384M: - stolen_size = MB(384); + gtt_entries = MB(384) - KB(size); break; case SNB_GMCH_GMS_STOLEN_416M: - stolen_size = MB(416); + gtt_entries = MB(416) - KB(size); break; case SNB_GMCH_GMS_STOLEN_448M: - stolen_size = MB(448); + gtt_entries = MB(448) - KB(size); break; case SNB_GMCH_GMS_STOLEN_480M: - stolen_size = MB(480); + gtt_entries = MB(480) - KB(size); break; case SNB_GMCH_GMS_STOLEN_512M: - stolen_size = MB(512); + gtt_entries = MB(512) - KB(size); break; } } else { switch (gmch_ctrl & I855_GMCH_GMS_MASK) { case I855_GMCH_GMS_STOLEN_1M: - stolen_size = MB(1); + gtt_entries = MB(1) - KB(size); break; case I855_GMCH_GMS_STOLEN_4M: - stolen_size = MB(4); + gtt_entries = MB(4) - KB(size); break; case I855_GMCH_GMS_STOLEN_8M: - stolen_size = MB(8); + gtt_entries = MB(8) - KB(size); break; case I855_GMCH_GMS_STOLEN_16M: - stolen_size = MB(16); + gtt_entries = MB(16) - KB(size); break; case I855_GMCH_GMS_STOLEN_32M: - stolen_size = MB(32); + gtt_entries = MB(32) - KB(size); break; case I915_GMCH_GMS_STOLEN_48M: - stolen_size = MB(48); + /* Check it's really I915G */ + if (IS_I915 || IS_I965 || IS_G33 || IS_G4X) + gtt_entries = MB(48) - KB(size); + else + gtt_entries = 0; break; case I915_GMCH_GMS_STOLEN_64M: - stolen_size = MB(64); + /* Check it's really I915G */ + if (IS_I915 || IS_I965 || IS_G33 || IS_G4X) + gtt_entries = MB(64) - KB(size); + else + gtt_entries = 0; break; case G33_GMCH_GMS_STOLEN_128M: - stolen_size = MB(128); + if (IS_G33 || IS_I965 || IS_G4X) + gtt_entries = MB(128) - KB(size); + else + gtt_entries = 0; break; case G33_GMCH_GMS_STOLEN_256M: - stolen_size = MB(256); + if (IS_G33 || IS_I965 || IS_G4X) + gtt_entries = MB(256) - KB(size); + else + gtt_entries = 0; break; case INTEL_GMCH_GMS_STOLEN_96M: - stolen_size = MB(96); + if (IS_I965 || IS_G4X) + gtt_entries = MB(96) - KB(size); + else + gtt_entries = 0; break; case INTEL_GMCH_GMS_STOLEN_160M: - stolen_size = MB(160); + if (IS_I965 || IS_G4X) + gtt_entries = MB(160) - KB(size); + else + gtt_entries = 0; break; case INTEL_GMCH_GMS_STOLEN_224M: - stolen_size = MB(224); + if (IS_I965 || IS_G4X) + gtt_entries = MB(224) - KB(size); + else + gtt_entries = 0; break; case INTEL_GMCH_GMS_STOLEN_352M: - stolen_size = MB(352); + if (IS_I965 || IS_G4X) + gtt_entries = MB(352) - KB(size); + else + gtt_entries = 0; break; default: - stolen_size = 0; + gtt_entries = 0; break; } } - - if (!local && stolen_size > intel_max_stolen) { - dev_info(&intel_private.bridge_dev->dev, + if (!local && gtt_entries > intel_max_stolen) { + dev_info(&agp_bridge->dev->dev, "detected %dK stolen memory, trimming to %dK\n", - 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"); + 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); } else { - dev_info(&intel_private.bridge_dev->dev, + dev_info(&agp_bridge->dev->dev, "no pre-allocated video memory detected\n"); - 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; - } + gtt_entries = 0; } - return 0; + intel_private.gtt_entries = gtt_entries; } -static void i830_cleanup(void) +static void intel_i830_fini_flush(void) { kunmap(intel_private.i8xx_page); intel_private.i8xx_flush_page = NULL; + unmap_page_from_agp(intel_private.i8xx_page); __free_page(intel_private.i8xx_page); intel_private.i8xx_page = NULL; @@ -825,13 +780,13 @@ static void intel_i830_setup_flush(void) if (intel_private.i8xx_page) return; - intel_private.i8xx_page = alloc_page(GFP_KERNEL); + intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32); if (!intel_private.i8xx_page) return; intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page); if (!intel_private.i8xx_flush_page) - i830_cleanup(); + intel_i830_fini_flush(); } /* The chipset_flush interface needs to get data that has already been @@ -844,7 +799,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 i830_chipset_flush(void) +static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) { unsigned int *pg = intel_private.i8xx_flush_page; @@ -856,184 +811,169 @@ static void i830_chipset_flush(void) printk(KERN_ERR "Timed out waiting for cache flush.\n"); } -static void i830_write_entry(dma_addr_t addr, unsigned int entry, - unsigned int flags) -{ - 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; - } - - writel(addr | pte_flags, intel_private.gtt + entry); -} - -static void intel_enable_gtt(void) +/* 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) { - u32 gma_addr; - u16 gmch_ctrl; - - 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); - - intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); - - 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. */ -} + int page_order; + struct aper_size_info_fixed *size; + int num_entries; + u32 temp; -static int i830_setup(void) -{ - u32 reg_addr; + size = agp_bridge->current_size; + page_order = size->page_order; + num_entries = size->num_entries; + agp_bridge->gatt_table_real = NULL; - pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); - reg_addr &= 0xfff80000; + pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp); + temp &= 0xfff80000; - intel_private.registers = ioremap(reg_addr, KB(64)); + intel_private.registers = ioremap(temp, 128 * 4096); if (!intel_private.registers) return -ENOMEM; - intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; - intel_private.pte_bus_addr = - readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; - - intel_i830_setup_flush(); + temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; + global_cache_flush(); /* FIXME: ?? */ - return 0; -} + /* 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); + return -ENOMEM; + } -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; + + agp_bridge->gatt_bus_addr = temp; return 0; } -static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) +/* Return the gatt table to a sane state. Use the top of stolen + * memory for the GTT. + */ +static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge) { return 0; } -static int intel_fake_agp_configure(void) +static int intel_i830_fetch_size(void) { - int i; - - intel_enable_gtt(); + u16 gmch_ctrl; + struct aper_size_info_fixed *values; - agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; + values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); - 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); + 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; } - readl(intel_private.gtt+i-1); /* PCI Posting. */ - global_cache_flush(); - - return 0; -} + pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); -static bool i830_check_flags(unsigned int flags) -{ - switch (flags) { - case 0: - case AGP_PHYS_MEMORY: - case AGP_USER_CACHED_MEMORY: - case AGP_USER_MEMORY: - return true; + if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { + agp_bridge->current_size = (void *) values; + agp_bridge->aperture_size_idx = 0; + return values[0].size; + } else { + agp_bridge->current_size = (void *) (values + 1); + agp_bridge->aperture_size_idx = 1; + return values[1].size; } - return false; + return 0; } -static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, - unsigned int sg_len, - unsigned int pg_start, - unsigned int flags) +static int intel_i830_configure(void) { - struct scatterlist *sg; - unsigned int len, m; - int i, j; + struct aper_size_info_fixed *current_size; + u32 temp; + u16 gmch_ctrl; + int i; - j = pg_start; + current_size = A_SIZE_FIX(agp_bridge->current_size); - /* 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++; + pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); + agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); + gmch_ctrl |= I830_GMCH_ENABLED; + pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl); + + writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); + readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + + if (agp_bridge->driver->needs_scratch_page) { + for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) { + writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); } + readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */ } - readl(intel_private.gtt+j-1); + + global_cache_flush(); + + intel_i830_setup_flush(); + return 0; } -static int intel_fake_agp_insert_entries(struct agp_memory *mem, - off_t pg_start, int type) +static void intel_i830_cleanup(void) { - int i, j; + iounmap(intel_private.registers); +} + +static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, + int type) +{ + int i, j, num_entries; + void *temp; int ret = -EINVAL; + int mask_type; if (mem->page_count == 0) goto out; - if (pg_start < intel_private.base.gtt_stolen_entries) { + 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, gtt_stolen_entries == 0x%.8x\n", - pg_start, intel_private.base.gtt_stolen_entries); + "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) > intel_private.base.gtt_total_entries) + if ((pg_start + mem->page_count) > num_entries) goto out_err; + /* The i830 can't check the GTT for entries since its read only, + * depend on the caller to make the correct offset decisions. + */ + if (type != mem->type) goto out_err; - if (!intel_private.driver->check_flags(type)) + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); + + if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY && + mask_type != INTEL_AGP_CACHED_MEMORY) goto out_err; if (!mem->is_flushed) global_cache_flush(); - 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); + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + writel(agp_bridge->driver->mask_memory(agp_bridge, + page_to_phys(mem->pages[i]), mask_type), + intel_private.registers+I810_PTE_BASE+(j*4)); } + readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); out: ret = 0; @@ -1042,39 +982,29 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, return ret; } -static int intel_fake_agp_remove_entries(struct agp_memory *mem, - off_t pg_start, int type) +static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start, + int type) { int i; if (mem->page_count == 0) return 0; - if (pg_start < intel_private.base.gtt_stolen_entries) { + if (pg_start < intel_private.gtt_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++) { - intel_private.driver->write_entry(intel_private.scratch_page_dma, - i, 0); + writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); } - readl(intel_private.gtt+i-1); + readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); return 0; } -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) +static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type) { if (type == AGP_PHYS_MEMORY) return alloc_agpphysmem_i8xx(pg_count, type); @@ -1085,9 +1015,9 @@ static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, static int intel_alloc_chipset_flush_resource(void) { int ret; - ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE, + ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE, PAGE_SIZE, PCIBIOS_MIN_MEM, 0, - pcibios_align_resource, intel_private.bridge_dev); + pcibios_align_resource, agp_bridge->dev); return ret; } @@ -1097,11 +1027,11 @@ static void intel_i915_setup_chipset_flush(void) int ret; u32 temp; - pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp); + pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp); if (!(temp & 0x1)) { intel_alloc_chipset_flush_resource(); intel_private.resource_valid = 1; - pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); + pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); } else { temp &= ~1; @@ -1120,17 +1050,17 @@ static void intel_i965_g33_setup_chipset_flush(void) u32 temp_hi, temp_lo; int ret; - 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); + pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi); + pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo); if (!(temp_lo & 0x1)) { intel_alloc_chipset_flush_resource(); intel_private.resource_valid = 1; - pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, + pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4, upper_32_bits(intel_private.ifp_resource.start)); - pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); + pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); } else { u64 l64; @@ -1153,7 +1083,7 @@ static void intel_i9xx_setup_flush(void) if (intel_private.ifp_resource.start) return; - if (INTEL_GTT_GEN == 6) + if (IS_SNB) return; /* setup a resource for this object */ @@ -1161,7 +1091,7 @@ static void intel_i9xx_setup_flush(void) intel_private.ifp_resource.flags = IORESOURCE_MEM; /* Setup chipset flush for 915 */ - if (IS_G33 || INTEL_GTT_GEN >= 4) { + if (IS_I965 || IS_G33 || IS_G4X) { intel_i965_g33_setup_chipset_flush(); } else { intel_i915_setup_chipset_flush(); @@ -1174,7 +1104,41 @@ static void intel_i9xx_setup_flush(void) "can't ioremap flush page - no chipset flushing\n"); } -static void i9xx_cleanup(void) +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) { if (intel_private.i9xx_flush_page) iounmap(intel_private.i9xx_flush_page); @@ -1182,93 +1146,320 @@ static void i9xx_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 i9xx_chipset_flush(void) +static void intel_i915_chipset_flush(struct agp_bridge_data *bridge) { if (intel_private.i9xx_flush_page) writel(1, intel_private.i9xx_flush_page); } -static void i965_write_entry(dma_addr_t addr, unsigned int entry, - unsigned int flags) +static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, + int type) { - /* Shift high bits down */ - addr |= (addr >> 28) & 0xf0; - writel(addr | I810_PTE_VALID, intel_private.gtt + entry); + 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; } -static bool gen6_check_flags(unsigned int flags) +static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start, + int type) { - return true; + 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; } -static void gen6_write_entry(dma_addr_t addr, unsigned int entry, - unsigned int flags) +/* 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) { - unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT; - unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; - u32 pte_flags; + int num_sizes = ARRAY_SIZE(intel_i830_sizes); + int aper_size; /* size in megabytes */ + int i; - 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; + 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; + } } - /* gen6 has bit11-4 for physical addr bit39-32 */ - addr |= (addr >> 28) & 0xff0; - writel(addr | pte_flags, intel_private.gtt + entry); + return 0; } -static void gen6_cleanup(void) +static int intel_i915_get_gtt_size(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); } -static int i9xx_setup(void) +/* 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) { - u32 reg_addr; + 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, ®_addr); + pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); + pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2); - reg_addr &= 0xfff80000; + gtt_map_size = intel_i915_get_gtt_size(); - intel_private.registers = ioremap(reg_addr, 128 * 4096); - if (!intel_private.registers) + intel_private.gtt = ioremap(temp2, gtt_map_size); + if (!intel_private.gtt) return -ENOMEM; - if (INTEL_GTT_GEN == 3) { - u32 gtt_addr; + intel_private.gtt_total_size = gtt_map_size / 4; - pci_read_config_dword(intel_private.pcidev, - I915_PTEADDR, >t_addr); - intel_private.gtt_bus_addr = gtt_addr; - } else { - u32 gtt_offset; + temp &= 0xfff80000; - switch (INTEL_GTT_GEN) { - case 5: - case 6: - gtt_offset = MB(2); - break; - case 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; + } + + agp_bridge->gatt_table = NULL; + + agp_bridge->gatt_bus_addr = temp; + + return 0; +} + +/* + * The i965 supports 36-bit physical addresses, but to keep + * the format of the GTT the same, the bits that don't fit + * in a 32-bit word are shifted down to bits 4..7. + * + * Gcc is smart enough to notice that "(addr >> 28) & 0xf0" + * is always zero on 32-bit architectures, so no need to make + * this conditional. + */ +static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, + dma_addr_t addr, int type) +{ + /* Shift high bits down */ + addr |= (addr >> 28) & 0xf0; + + /* Type checking must be done elsewhere */ + return addr | bridge->driver->masks[type].mask; +} + +static 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_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); + switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) { default: - gtt_offset = KB(512); + case SNB_GTT_SIZE_0M: + printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl); + *gtt_size = MB(0); + break; + case SNB_GTT_SIZE_1M: + *gtt_size = MB(1); + break; + case SNB_GTT_SIZE_2M: + *gtt_size = MB(2); break; } - intel_private.gtt_bus_addr = reg_addr + gtt_offset; + break; + default: + *gtt_offset = *gtt_size = KB(512); } +} - intel_private.pte_bus_addr = - readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; +/* 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; - intel_i9xx_setup_flush(); + 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(>t_offset, >t_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; + } + + agp_bridge->gatt_table = NULL; + + agp_bridge->gatt_bus_addr = temp; return 0; } @@ -1284,7 +1475,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_fake_agp_enable, + .agp_enable = intel_i810_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = agp_generic_create_gatt_table, .free_gatt_table = agp_generic_free_gatt_table, @@ -1299,282 +1490,161 @@ 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_fake_agp_driver = { +static const struct agp_bridge_driver intel_830_driver = { .owner = THIS_MODULE, + .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, - .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, + .num_aperture_sizes = 4, + .needs_scratch_page = true, + .configure = intel_i830_configure, + .fetch_size = intel_i830_fetch_size, + .cleanup = intel_i830_cleanup, + .mask_memory = intel_i810_mask_memory, + .masks = intel_i810_masks, + .agp_enable = intel_i810_agp_enable, .cache_flush = global_cache_flush, - .create_gatt_table = intel_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, + .create_gatt_table = intel_i830_create_gatt_table, + .free_gatt_table = intel_i830_free_gatt_table, + .insert_memory = intel_i830_insert_entries, + .remove_memory = intel_i830_remove_entries, + .alloc_by_type = intel_i830_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_fake_agp_chipset_flush, + .agp_type_to_mask_type = intel_i830_type_to_mask_type, + .chipset_flush = intel_i830_chipset_flush, }; -static const struct intel_gtt_driver i81x_gtt_driver = { - .gen = 1, - .dma_mask_size = 32, -}; -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 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_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 }; -/* 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 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 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); +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 +}; -MODULE_AUTHOR("Dave Jones "); -MODULE_LICENSE("GPL and additional rights"); +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 +}; diff --git a/trunk/drivers/gpu/drm/drm_buffer.c b/trunk/drivers/gpu/drm/drm_buffer.c index 529a0dbe9fc6..55d03ed05000 100644 --- a/trunk/drivers/gpu/drm/drm_buffer.c +++ b/trunk/drivers/gpu/drm/drm_buffer.c @@ -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. */ -int drm_buffer_copy_from_user(struct drm_buffer *buf, - void __user *user_data, int size) +extern 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 = NULL; + void *obj = 0; if (idx + objsize <= PAGE_SIZE) { obj = &buf->data[page][idx]; diff --git a/trunk/drivers/gpu/drm/drm_crtc.c b/trunk/drivers/gpu/drm/drm_crtc.c index 6985cb1da72c..37e0b4fa482a 100644 --- a/trunk/drivers/gpu/drm/drm_crtc.c +++ b/trunk/drivers/gpu/drm/drm_crtc.c @@ -1854,8 +1854,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, } if (fb->funcs->dirty) { - ret = fb->funcs->dirty(fb, file_priv, flags, r->color, - clips, num_clips); + ret = fb->funcs->dirty(fb, flags, r->color, clips, num_clips); } else { ret = -ENOSYS; goto out_err2; diff --git a/trunk/drivers/gpu/drm/drm_debugfs.c b/trunk/drivers/gpu/drm/drm_debugfs.c index 9d8c892d07c9..677b275fa721 100644 --- a/trunk/drivers/gpu/drm/drm_debugfs.c +++ b/trunk/drivers/gpu/drm/drm_debugfs.c @@ -48,6 +48,7 @@ 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 diff --git a/trunk/drivers/gpu/drm/drm_edid.c b/trunk/drivers/gpu/drm/drm_edid.c index fd033ebbdf84..96e963108225 100644 --- a/trunk/drivers/gpu/drm/drm_edid.c +++ b/trunk/drivers/gpu/drm/drm_edid.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "drmP.h" #include "drm_edid.h" #include "drm_edid_modes.h" diff --git a/trunk/drivers/gpu/drm/drm_gem.c b/trunk/drivers/gpu/drm/drm_gem.c index ea1c4b019ebf..cff7317d3830 100644 --- a/trunk/drivers/gpu/drm/drm_gem.c +++ b/trunk/drivers/gpu/drm/drm_gem.c @@ -92,6 +92,12 @@ 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) { @@ -142,9 +148,12 @@ int drm_gem_object_init(struct drm_device *dev, return -ENOMEM; kref_init(&obj->refcount); - atomic_set(&obj->handle_count, 0); + kref_init(&obj->handlecount); obj->size = size; + atomic_inc(&dev->object_count); + atomic_add(obj->size, &dev->object_memory); + return 0; } EXPORT_SYMBOL(drm_gem_object_init); @@ -171,6 +180,8 @@ 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); @@ -425,7 +436,10 @@ 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); @@ -448,6 +462,26 @@ 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(); @@ -460,8 +494,12 @@ 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 drm_gem_object *obj) +void +drm_gem_object_handle_free(struct kref *kref) { + 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 */ @@ -488,10 +526,6 @@ 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); @@ -499,10 +533,7 @@ void drm_gem_vm_close(struct vm_area_struct *vma) { struct drm_gem_object *obj = vma->vm_private_data; - mutex_lock(&obj->dev->struct_mutex); - drm_vm_close_locked(vma); - drm_gem_object_unreference(obj); - mutex_unlock(&obj->dev->struct_mutex); + drm_gem_object_unreference_unlocked(obj); } EXPORT_SYMBOL(drm_gem_vm_close); diff --git a/trunk/drivers/gpu/drm/drm_info.c b/trunk/drivers/gpu/drm/drm_info.c index 3cdbaf379bb5..2ef2c7827243 100644 --- a/trunk/drivers/gpu/drm/drm_info.c +++ b/trunk/drivers/gpu/drm/drm_info.c @@ -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->handle_count), + atomic_read(&obj->handlecount.refcount), atomic_read(&obj->refcount.refcount)); return 0; } @@ -270,6 +270,20 @@ 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) diff --git a/trunk/drivers/gpu/drm/drm_lock.c b/trunk/drivers/gpu/drm/drm_lock.c index 632ae243ede0..1e28b9072068 100644 --- a/trunk/drivers/gpu/drm/drm_lock.c +++ b/trunk/drivers/gpu/drm/drm_lock.c @@ -152,7 +152,6 @@ 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", @@ -162,10 +161,6 @@ 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; } diff --git a/trunk/drivers/gpu/drm/drm_proc.c b/trunk/drivers/gpu/drm/drm_proc.c index 9e5b07efebb7..e571de536dc5 100644 --- a/trunk/drivers/gpu/drm/drm_proc.c +++ b/trunk/drivers/gpu/drm/drm_proc.c @@ -55,6 +55,7 @@ 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 diff --git a/trunk/drivers/gpu/drm/drm_vm.c b/trunk/drivers/gpu/drm/drm_vm.c index 2c3fcbdfd8ff..ee879d6bb522 100644 --- a/trunk/drivers/gpu/drm/drm_vm.c +++ b/trunk/drivers/gpu/drm/drm_vm.c @@ -433,7 +433,15 @@ static void drm_vm_open(struct vm_area_struct *vma) mutex_unlock(&dev->struct_mutex); } -void drm_vm_close_locked(struct vm_area_struct *vma) +/** + * \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; @@ -443,6 +451,7 @@ void drm_vm_close_locked(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); @@ -450,23 +459,6 @@ void drm_vm_close_locked(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); } diff --git a/trunk/drivers/gpu/drm/i810/i810_dma.c b/trunk/drivers/gpu/drm/i810/i810_dma.c index fb07e73581e8..61b4caf220fa 100644 --- a/trunk/drivers/gpu/drm/i810/i810_dma.c +++ b/trunk/drivers/gpu/drm/i810/i810_dma.c @@ -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 = i810_ioctl, + .unlocked_ioctl = drm_ioctl, .mmap = i810_mmap_buffers, .fasync = drm_fasync, }; diff --git a/trunk/drivers/gpu/drm/i830/i830_dma.c b/trunk/drivers/gpu/drm/i830/i830_dma.c index cc92c7e6236f..671aa18415ac 100644 --- a/trunk/drivers/gpu/drm/i830/i830_dma.c +++ b/trunk/drivers/gpu/drm/i830/i830_dma.c @@ -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 = i830_ioctl, + .unlocked_ioctl = drm_ioctl, .mmap = i830_mmap_buffers, .fasync = drm_fasync, }; diff --git a/trunk/drivers/gpu/drm/i915/Makefile b/trunk/drivers/gpu/drm/i915/Makefile index f6e98dd416c9..5c8e53458edb 100644 --- a/trunk/drivers/gpu/drm/i915/Makefile +++ b/trunk/drivers/gpu/drm/i915/Makefile @@ -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 diff --git a/trunk/drivers/gpu/drm/i915/dvo_ch7017.c b/trunk/drivers/gpu/drm/i915/dvo_ch7017.c index af70337567ce..14d59804acd7 100644 --- a/trunk/drivers/gpu/drm/i915/dvo_ch7017.c +++ b/trunk/drivers/gpu/drm/i915/dvo_ch7017.c @@ -165,44 +165,67 @@ 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, u8 addr, u8 *val) +static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *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 = &addr, + .buf = out_buf, }, { .addr = dvo->slave_addr, .flags = I2C_M_RD, .len = 1, - .buf = val, + .buf = in_buf, } }; - return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2; + + out_buf[0] = addr; + out_buf[1] = 0; + + if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + *val= in_buf[0]; + return true; + }; + + return false; } -static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val) +static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) { - uint8_t buf[2] = { addr, 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]; struct i2c_msg msg = { .addr = dvo->slave_addr, .flags = 0, .len = 2, - .buf = buf, + .buf = out_buf, }; - return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1; + + out_buf[0] = addr; + out_buf[1] = val; + + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + return true; + + return false; } /** 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; - const char *str; - u8 val; + uint8_t val; priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL); if (priv == NULL) @@ -214,27 +237,16 @@ static bool ch7017_init(struct intel_dvo_device *dvo, if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val)) goto fail; - 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: + if (val != CH7017_DEVICE_ID_VALUE && + val != CH7018_DEVICE_ID_VALUE && + val != CH7019_DEVICE_ID_VALUE) { DRM_DEBUG_KMS("ch701x not detected, got %d: from %s " - "slave %d.\n", - val, adapter->name,dvo->slave_addr); + "Slave %d.\n", + val, i2cbus->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; @@ -356,7 +368,7 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode) } /* XXX: Should actually wait for update power status somehow */ - msleep(20); + udelay(20000); } static void ch7017_dump_regs(struct intel_dvo_device *dvo) diff --git a/trunk/drivers/gpu/drm/i915/dvo_ch7xxx.c b/trunk/drivers/gpu/drm/i915/dvo_ch7xxx.c index 7eaa94e4ff06..6f1944b24441 100644 --- a/trunk/drivers/gpu/drm/i915/dvo_ch7xxx.c +++ b/trunk/drivers/gpu/drm/i915/dvo_ch7xxx.c @@ -113,6 +113,7 @@ 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]; @@ -134,14 +135,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(adapter, msgs, 2) == 2) { + if (i2c_transfer(&i2cbus->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, adapter->name, dvo->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; } @@ -151,6 +152,7 @@ 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, @@ -162,12 +164,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(adapter, &msg, 1) == 1) + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) return true; if (!ch7xxx->quiet) { DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", - addr, adapter->name, dvo->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; diff --git a/trunk/drivers/gpu/drm/i915/dvo_ivch.c b/trunk/drivers/gpu/drm/i915/dvo_ivch.c index a12ed9414cc7..a2ec3f487202 100644 --- a/trunk/drivers/gpu/drm/i915/dvo_ivch.c +++ b/trunk/drivers/gpu/drm/i915/dvo_ivch.c @@ -167,6 +167,7 @@ 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]; @@ -192,7 +193,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) out_buf[0] = addr; - if (i2c_transfer(adapter, msgs, 3) == 3) { + if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) { *data = (in_buf[1] << 8) | in_buf[0]; return true; }; @@ -200,7 +201,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, adapter->name, dvo->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; } @@ -210,6 +211,7 @@ 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, @@ -222,12 +224,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(adapter, &msg, 1) == 1) + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) return true; if (!priv->quiet) { DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", - addr, adapter->name, dvo->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; diff --git a/trunk/drivers/gpu/drm/i915/dvo_sil164.c b/trunk/drivers/gpu/drm/i915/dvo_sil164.c index e4b4091df942..9b8e6765cf26 100644 --- a/trunk/drivers/gpu/drm/i915/dvo_sil164.c +++ b/trunk/drivers/gpu/drm/i915/dvo_sil164.c @@ -69,6 +69,7 @@ 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]; @@ -90,14 +91,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(adapter, msgs, 2) == 2) { + if (i2c_transfer(&i2cbus->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, adapter->name, dvo->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; } @@ -106,6 +107,7 @@ 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, @@ -117,12 +119,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(adapter, &msg, 1) == 1) + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) return true; if (!sil->quiet) { DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", - addr, adapter->name, dvo->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; diff --git a/trunk/drivers/gpu/drm/i915/dvo_tfp410.c b/trunk/drivers/gpu/drm/i915/dvo_tfp410.c index 8ab2855bb544..56f66426207f 100644 --- a/trunk/drivers/gpu/drm/i915/dvo_tfp410.c +++ b/trunk/drivers/gpu/drm/i915/dvo_tfp410.c @@ -94,6 +94,7 @@ 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]; @@ -115,14 +116,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(adapter, msgs, 2) == 2) { + if (i2c_transfer(&i2cbus->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, adapter->name, dvo->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; } @@ -131,6 +132,7 @@ 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, @@ -142,12 +144,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(adapter, &msg, 1) == 1) + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) return true; if (!tfp->quiet) { DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", - addr, adapter->name, dvo->slave_addr); + addr, i2cbus->adapter.name, dvo->slave_addr); } return false; diff --git a/trunk/drivers/gpu/drm/i915/i915_debugfs.c b/trunk/drivers/gpu/drm/i915/i915_debugfs.c index d598070fb279..5e43d7076789 100644 --- a/trunk/drivers/gpu/drm/i915/i915_debugfs.c +++ b/trunk/drivers/gpu/drm/i915/i915_debugfs.c @@ -40,51 +40,9 @@ #if defined(CONFIG_DEBUG_FS) -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; -} +#define ACTIVE_LIST 1 +#define FLUSHING_LIST 2 +#define INACTIVE_LIST 3 static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv) { @@ -106,27 +64,6 @@ 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; @@ -135,84 +72,56 @@ 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; - size_t total_obj_size, total_gtt_size; - int count, ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; + spinlock_t *lock = NULL; switch (list) { - case RENDER_LIST: - seq_printf(m, "Render:\n"); + case ACTIVE_LIST: + seq_printf(m, "Active:\n"); + lock = &dev_priv->mm.active_list_lock; 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: - mutex_unlock(&dev->struct_mutex); - return -EINVAL; + DRM_INFO("Ooops, unexpected list\n"); + return 0; } - total_obj_size = total_gtt_size = count = 0; - list_for_each_entry(obj_priv, head, list) { - seq_printf(m, " "); - describe_obj(m, obj_priv); + 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); + 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); - seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", - count, total_obj_size, total_gtt_size); + if (lock) + spin_unlock(lock); 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; @@ -267,11 +176,6 @@ 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, @@ -280,8 +184,6 @@ 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; } @@ -290,24 +192,16 @@ 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", - dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring)); + i915_get_gem_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; } @@ -317,11 +211,6 @@ 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", @@ -358,7 +247,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", - dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring)); + i915_get_gem_seqno(dev, &dev_priv->render_ring)); } else { seq_printf(m, "Current sequence: hws uninitialized\n"); } @@ -366,8 +255,6 @@ 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; } @@ -376,11 +263,7 @@ 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, ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; + int i; seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start); seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs); @@ -406,7 +289,6 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data) seq_printf(m, "\n"); } } - mutex_unlock(&dev->struct_mutex); return 0; } @@ -431,19 +313,16 @@ static int i915_hws_info(struct seq_file *m, void *data) return 0; } -static void i915_dump_object(struct seq_file *m, - struct io_mapping *mapping, - struct drm_i915_gem_object *obj_priv) +static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_count) { - int page, page_count, i; + int page, i; + uint32_t *mem; - page_count = obj_priv->base.size / PAGE_SIZE; for (page = 0; page < page_count; page++) { - u32 *mem = io_mapping_map_wc(mapping, - obj_priv->gtt_offset + page * PAGE_SIZE); + mem = kmap_atomic(pages[page], KM_USER0); for (i = 0; i < PAGE_SIZE; i += 4) seq_printf(m, "%08x : %08x\n", i, mem[i / 4]); - io_mapping_unmap(mem); + kunmap_atomic(mem, KM_USER0); } } @@ -456,21 +335,27 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) struct drm_i915_gem_object *obj_priv; int ret; - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; + spin_lock(&dev_priv->mm.active_list_lock); 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) { - seq_printf(m, "--- gtt_offset = 0x%08x\n", - obj_priv->gtt_offset); - i915_dump_object(m, dev_priv->mm.gtt_mapping, obj_priv); + 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); } } - mutex_unlock(&dev->struct_mutex); + spin_unlock(&dev_priv->mm.active_list_lock); return 0; } @@ -480,24 +365,20 @@ 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; - int ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; + u8 *virt; + uint32_t *ptr, off; if (!dev_priv->render_ring.gem_object) { seq_printf(m, "No ringbuffer setup\n"); - } else { - u8 *virt = dev_priv->render_ring.virtual_start; - uint32_t off; + return 0; + } - 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); - } + virt = dev_priv->render_ring.virtual_start; + + for (off = 0; off < dev_priv->render_ring.size; off += 4) { + ptr = (uint32_t *)(virt + off); + seq_printf(m, "%08x : %08x\n", off, *ptr); } - mutex_unlock(&dev->struct_mutex); return 0; } @@ -515,7 +396,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(INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD)); + seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); return 0; } @@ -577,7 +458,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 (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { seq_printf(m, " INSTPS: 0x%08x\n", error->instps); seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1); } @@ -761,9 +642,6 @@ 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; @@ -797,17 +675,15 @@ 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_IRONLAKE(dev)) - sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN; - else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev)) + if (IS_I965GM(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; } @@ -818,16 +694,10 @@ 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); @@ -848,68 +718,6 @@ 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) @@ -933,9 +741,6 @@ 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); } @@ -965,7 +770,7 @@ i915_wedged_write(struct file *filp, atomic_set(&dev_priv->mm.wedged, val); if (val) { - wake_up_all(&dev_priv->irq_queue); + DRM_WAKEUP(&dev_priv->irq_queue); queue_work(dev_priv->wq, &dev_priv->error_work); } @@ -1018,14 +823,9 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) } static struct drm_info_list i915_debugfs_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_active", i915_gem_object_list_info, 0, (void *) ACTIVE_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}, @@ -1045,8 +845,6 @@ 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) diff --git a/trunk/drivers/gpu/drm/i915/i915_dma.c b/trunk/drivers/gpu/drm/i915/i915_dma.c index 726c3736082f..9d67b4853030 100644 --- a/trunk/drivers/gpu/drm/i915/i915_dma.c +++ b/trunk/drivers/gpu/drm/i915/i915_dma.c @@ -40,7 +40,8 @@ #include #include #include -#include + +extern int intel_max_stolen; /* from AGP driver */ /** * Sets up the hardware status page for devices that need a physical address @@ -63,7 +64,7 @@ static int i915_init_phys_hws(struct drm_device *dev) memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE); - if (INTEL_INFO(dev)->gen >= 4) + if (IS_I965G(dev)) dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) & 0xf0; @@ -221,7 +222,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) - intel_ring_setup_status_page(dev, ring); + ring->setup_status_page(dev, ring); else I915_WRITE(HWS_PGA, dev_priv->dma_status_page); @@ -376,7 +377,7 @@ i915_emit_box(struct drm_device *dev, return -EINVAL; } - if (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { BEGIN_LP_RING(4); OUT_RING(GFX_OP_DRAWRECT_INFO_I965); OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); @@ -480,7 +481,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, if (!IS_I830(dev) && !IS_845G(dev)) { BEGIN_LP_RING(2); - if (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); OUT_RING(batch->start); } else { @@ -887,12 +888,12 @@ static int intel_alloc_mchbar_resource(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - int reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915; + int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; u32 temp_lo, temp_hi = 0; u64 mchbar_addr; int ret; - if (INTEL_INFO(dev)->gen >= 4) + if (IS_I965G(dev)) 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; @@ -919,7 +920,7 @@ intel_alloc_mchbar_resource(struct drm_device *dev) return ret; } - if (INTEL_INFO(dev)->gen >= 4) + if (IS_I965G(dev)) pci_write_config_dword(dev_priv->bridge_dev, reg + 4, upper_32_bits(dev_priv->mch_res.start)); @@ -933,7 +934,7 @@ static void intel_setup_mchbar(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915; + int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; u32 temp; bool enabled; @@ -970,7 +971,7 @@ static void intel_teardown_mchbar(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915; + int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; u32 temp; if (dev_priv->mchbar_need_disable) { @@ -989,6 +990,174 @@ 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) @@ -1012,11 +1181,11 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev, { unsigned long *gtt; unsigned long entry, phys; - int gtt_bar = IS_GEN2(dev) ? 1 : 0; + int gtt_bar = IS_I9XX(dev) ? 0 : 1; int gtt_offset, gtt_size; - if (INTEL_INFO(dev)->gen >= 4) { - if (IS_G4X(dev) || INTEL_INFO(dev)->gen > 4) { + if (IS_I965G(dev)) { + if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) { gtt_offset = 2*1024*1024; gtt_size = 2*1024*1024; } else { @@ -1041,8 +1210,10 @@ 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 (INTEL_INFO(dev)->gen < 4 && !IS_G33(dev)) + if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev) || + IS_I945G(dev) || IS_I945GM(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 && @@ -1081,7 +1252,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->mm.vram, size, 4096, 0); + compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0); if (!compressed_fb) { dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; i915_warn_stolen(dev); @@ -1102,7 +1273,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->mm.vram, 4096, + compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096, 4096, 0); if (!compressed_llb) { i915_warn_stolen(dev); @@ -1172,8 +1343,10 @@ 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); } } @@ -1190,14 +1363,20 @@ 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; - /* Basic memrange allocator for stolen space (aka mm.vram) */ - drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size); + 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)); /* We're off and running w/KMS */ dev_priv->mm.suspended = 0; @@ -1264,6 +1443,12 @@ 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; @@ -1602,9 +1787,9 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) } } - diff = div_u64(diff, diff1); + div_u64(diff, diff1); ret = ((m * diff) + c); - ret = div_u64(ret, 10); + div_u64(ret, 10); dev_priv->last_count1 = total_count; dev_priv->last_time1 = now; @@ -1673,7 +1858,7 @@ void i915_update_gfx_val(struct drm_i915_private *dev_priv) /* More magic constants... */ diff = diff * 1181; - diff = div_u64(diff, diffms * 10); + div_u64(diff, diffms * 10); dev_priv->gfx_power = diff; } @@ -1722,7 +1907,7 @@ static struct drm_i915_private *i915_mch_dev; * - dev_priv->fmax * - dev_priv->gpu_busy */ -static DEFINE_SPINLOCK(mchdev_lock); +DEFINE_SPINLOCK(mchdev_lock); /** * i915_read_mch_val - return value for IPS use @@ -1877,7 +2062,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; + uint32_t agp_size, prealloc_size, prealloc_start; /* i915 has 4 more counters */ dev->counters += 4; dev->types[6] = _DRM_STAT_IRQ; @@ -1894,7 +2079,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_GEN2(dev) ? 1 : 0; + mmio_bar = IS_I9XX(dev) ? 0 : 1; base = pci_resource_start(dev->pdev, mmio_bar); size = pci_resource_len(dev->pdev, mmio_bar); @@ -1936,32 +2121,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) "performance may suffer.\n"); } - dev_priv->mm.gtt = intel_gtt_get(); - if (!dev_priv->mm.gtt) { - DRM_ERROR("Failed to initialize GTT\n"); - ret = -ENODEV; + ret = i915_probe_agp(dev, &agp_size, &prealloc_size, &prealloc_start); + if (ret) goto out_iomapfree; - } - prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; - agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + 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; + } - /* 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); + dev_priv->wq = create_singlethread_workqueue("i915"); if (dev_priv->wq == NULL) { DRM_ERROR("Failed to create our workqueue.\n"); ret = -ENOMEM; @@ -1996,8 +2166,6 @@ 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); @@ -2044,7 +2212,8 @@ 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_size, agp_size); + ret = i915_load_modeset_init(dev, prealloc_start, + prealloc_size, agp_size); if (ret < 0) { DRM_ERROR("failed to init modeset\n"); goto out_workqueue_free; @@ -2052,8 +2221,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } /* Must be done after probing outputs */ - intel_opregion_init(dev); - acpi_video_register(); + intel_opregion_init(dev, 0); setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, (unsigned long) dev); @@ -2081,20 +2249,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) int i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int ret; + + i915_destroy_error_state(dev); spin_lock(&mchdev_lock); i915_mch_dev = NULL; spin_unlock(&mchdev_lock); - 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); + destroy_workqueue(dev_priv->wq); + del_timer_sync(&dev_priv->hangcheck_timer); io_mapping_free(dev_priv->mm.gtt_mapping); if (dev_priv->mm.gtt_mtrr >= 0) { @@ -2103,10 +2266,7 @@ 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); /* @@ -2118,28 +2278,20 @@ 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_fini(dev); + intel_opregion_free(dev, 0); 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); @@ -2147,35 +2299,34 @@ 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->mm.vram); + drm_mm_takedown(&dev_priv->vram); + i915_gem_lastclose(dev); 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) +int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) { - struct drm_i915_file_private *file_priv; + struct drm_i915_file_private *i915_file_priv; DRM_DEBUG_DRIVER("\n"); - file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL); - if (!file_priv) + i915_file_priv = (struct drm_i915_file_private *) + kmalloc(sizeof(*i915_file_priv), GFP_KERNEL); + + if (!i915_file_priv) return -ENOMEM; - file->driver_priv = file_priv; + file_priv->driver_priv = i915_file_priv; - spin_lock_init(&file_priv->mm.lock); - INIT_LIST_HEAD(&file_priv->mm.request_list); + INIT_LIST_HEAD(&i915_file_priv->mm.request_list); return 0; } @@ -2218,11 +2369,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) +void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) { - struct drm_i915_file_private *file_priv = file->driver_priv; + struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; - kfree(file_priv); + kfree(i915_file_priv); } struct drm_ioctl_desc i915_ioctls[] = { diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.c b/trunk/drivers/gpu/drm/i915/i915_drv.c index c3decb2fef4b..9ed9d23caf14 100644 --- a/trunk/drivers/gpu/drm/i915/i915_drv.c +++ b/trunk/drivers/gpu/drm/i915/i915_drv.c @@ -32,7 +32,6 @@ #include "drm.h" #include "i915_drm.h" #include "i915_drv.h" -#include "intel_drv.h" #include #include "drm_crtc_helper.h" @@ -62,108 +61,86 @@ extern int intel_agp_enabled; .driver_data = (unsigned long) info } static const struct intel_device_info intel_i830_info = { - .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, - .has_overlay = 1, .overlay_needs_physical = 1, + .gen = 2, .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, }; static const struct intel_device_info intel_845g_info = { - .gen = 2, - .has_overlay = 1, .overlay_needs_physical = 1, + .gen = 2, .is_i8xx = 1, }; static const struct intel_device_info intel_i85x_info = { - .gen = 2, .is_i85x = 1, .is_mobile = 1, + .gen = 2, .is_i8xx = 1, .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, - .has_overlay = 1, .overlay_needs_physical = 1, + .gen = 2, .is_i8xx = 1, }; static const struct intel_device_info intel_i915g_info = { - .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, - .has_overlay = 1, .overlay_needs_physical = 1, + .gen = 3, .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1, }; static const struct intel_device_info intel_i915gm_info = { - .gen = 3, .is_mobile = 1, + .gen = 3, .is_i9xx = 1, .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, .has_hotplug = 1, .cursor_needs_physical = 1, - .has_overlay = 1, .overlay_needs_physical = 1, + .gen = 3, .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1, }; static const struct intel_device_info intel_i945gm_info = { - .gen = 3, .is_i945gm = 1, .is_mobile = 1, + .gen = 3, .is_i945gm = 1, .is_i9xx = 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, + .gen = 4, .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1, - .has_overlay = 1, }; static const struct intel_device_info intel_i965gm_info = { - .gen = 4, .is_crestline = 1, + .gen = 4, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 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, + .gen = 3, .is_g33 = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, - .has_overlay = 1, }; static const struct intel_device_info intel_g45_info = { - .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, + .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 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_g4x = 1, + .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 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, + .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 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, + .gen = 5, .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 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, + .gen = 5, .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 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, + .gen = 6, .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, - .has_bsd_ring = 1, }; static const struct intel_device_info intel_sandybridge_m_info = { - .gen = 6, .is_mobile = 1, + .gen = 6, .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, - .has_bsd_ring = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ @@ -260,7 +237,7 @@ static int i915_drm_freeze(struct drm_device *dev) i915_save_state(dev); - intel_opregion_fini(dev); + intel_opregion_free(dev, 1); /* Modeset on resume, not lid events */ dev_priv->modeset_on_lid = 0; @@ -281,8 +258,6 @@ 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; @@ -302,7 +277,8 @@ static int i915_drm_thaw(struct drm_device *dev) int error = 0; i915_restore_state(dev); - intel_opregion_setup(dev); + + intel_opregion_init(dev, 1); /* KMS EnterVT equivalent */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { @@ -318,8 +294,6 @@ 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; @@ -327,79 +301,12 @@ 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); - 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); + return i915_drm_thaw(dev); } /** @@ -418,39 +325,54 @@ static int ironlake_do_reset(struct drm_device *dev, u8 flags) * - re-init interrupt state * - re-init display */ -int i915_reset(struct drm_device *dev, u8 flags) +int i965_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); - 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"); + /* + * 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"); mutex_unlock(&dev->struct_mutex); - return ret; + return -ENODEV; } /* Ok, now get things going again... */ @@ -478,19 +400,13 @@ int i915_reset(struct drm_device *dev, u8 flags) mutex_lock(&dev->struct_mutex); } - mutex_unlock(&dev->struct_mutex); - /* - * 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. + * Display needs restore too... */ - if (need_display) { - mutex_lock(&dev->mode_config.mutex); - drm_helper_resume_force_mode(dev); - mutex_unlock(&dev->mode_config.mutex); - } + if (need_display) + i915_restore_display(dev); + mutex_unlock(&dev->struct_mutex); return 0; } diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.h b/trunk/drivers/gpu/drm/i915/i915_drv.h index 73ad8bff2c2a..af4a263cf257 100644 --- a/trunk/drivers/gpu/drm/i915/i915_drv.h +++ b/trunk/drivers/gpu/drm/i915/i915_drv.h @@ -34,8 +34,6 @@ #include "intel_bios.h" #include "intel_ringbuffer.h" #include -#include -#include /* General customization: */ @@ -75,9 +73,11 @@ 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_LISTS 0 +#define WATCH_INACTIVE 0 #define WATCH_PWRITE 0 #define I915_GEM_PHYS_CURSOR_0 1 @@ -110,9 +110,8 @@ struct intel_opregion { struct opregion_acpi *acpi; struct opregion_swsci *swsci; struct opregion_asle *asle; - void *vbt; + int enabled; }; -#define OPREGION_SIZE (8*1024) struct intel_overlay; struct intel_overlay_error_state; @@ -126,16 +125,13 @@ 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 i2c_pin; - u8 i2c_speed; + u8 initialized; u8 ddc_pin; }; @@ -197,9 +193,13 @@ 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,14 +212,9 @@ 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 */ @@ -246,12 +241,6 @@ 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; @@ -274,9 +263,6 @@ 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; @@ -303,21 +289,24 @@ 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 250 /* in ms */ +#define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */ 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; @@ -327,7 +316,8 @@ typedef struct drm_i915_private { struct intel_overlay *overlay; /* LVDS info */ - int backlight_level; /* restore backlight to this value */ + int backlight_duty_cycle; /* restore backlight to this value */ + bool panel_wants_dither; 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 */ @@ -338,22 +328,13 @@ 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; - - struct { - u8 rate:4; - u8 lanes:4; - u8 preemphasis:4; - u8 vswing:4; - - u8 initialized:1; - u8 support:1; - u8 bpp:6; - } edp; + int edp_bpp; struct notifier_block lid_notifier; - int crt_ddc_pin; + int crt_ddc_bus; /* 0 = unknown, else GPIO to use for CRT DDC */ 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 */ @@ -363,7 +344,6 @@ 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 */ @@ -527,11 +507,6 @@ 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; @@ -546,6 +521,8 @@ 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 @@ -578,12 +555,6 @@ 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; @@ -640,17 +611,6 @@ 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 */ @@ -666,6 +626,8 @@ 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; @@ -699,8 +661,6 @@ 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; @@ -856,14 +816,12 @@ 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; }; @@ -904,7 +862,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 i915_reset(struct drm_device *dev, u8 flags); +extern int i965_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); @@ -913,6 +871,7 @@ 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, @@ -949,12 +908,6 @@ 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, @@ -969,7 +922,6 @@ 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, @@ -1020,22 +972,13 @@ 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); - -/** - * 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); +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); void i915_gem_retire_requests(struct drm_device *dev); -void i915_gem_reset(struct drm_device *dev); +void i915_gem_retire_work_handler(struct work_struct *work); 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, @@ -1047,18 +990,16 @@ 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, - struct drm_i915_gem_request *request, - struct intel_ring_buffer *ring); + struct drm_file *file_priv, + uint32_t flush_domains, + struct intel_ring_buffer *ring); int i915_do_wait_request(struct drm_device *dev, - uint32_t seqno, - bool interruptible, - struct intel_ring_buffer *ring); + uint32_t seqno, int 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, - bool pipelined); +int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj); int i915_gem_attach_phys_object(struct drm_device *dev, struct drm_gem_object *obj, int id, @@ -1066,7 +1007,10 @@ 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); @@ -1088,14 +1032,15 @@ 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_LISTS -int i915_verify_lists(struct drm_device *dev); +#if WATCH_INACTIVE +void i915_verify_inactive(struct drm_device *dev, char *file, int line); #else -#define i915_verify_lists(dev) 0 +#define i915_verify_inactive(dev, file, line) #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); @@ -1109,31 +1054,19 @@ 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 -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); +/* 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); #else -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; } +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; } #endif /* modesetting */ @@ -1151,10 +1084,8 @@ 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. @@ -1168,26 +1099,8 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove LOCK_TEST_WITH_RETURN(dev, file_priv); \ } while (0) -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_READ(reg) readl(dev_priv->regs + (reg)) +#define I915_WRITE(reg, val) writel(val, dev_priv->regs + (reg)) #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)) @@ -1197,11 +1110,6 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #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 { \ @@ -1258,6 +1166,8 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #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) @@ -1269,6 +1179,7 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #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) @@ -1277,27 +1188,26 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5) #define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6) -#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring) +#define HAS_BSD(dev) (IS_IRONLAKE(dev) || IS_G4X(dev)) #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_GEN2(dev) && !(IS_I915G(dev) || \ +#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \ IS_I915GM(dev))) -#define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) +#define SUPPORTS_DIGITAL_OUTPUTS(dev) (IS_I9XX(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) (INTEL_INFO(dev)->supports_tv) +#define SUPPORTS_TV(dev) (IS_I9XX(dev) && IS_MOBILE(dev) && \ + !IS_IRONLAKE(dev) && !IS_PINEVIEW(dev) && \ + !IS_GEN6(dev)) #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) (INTEL_INFO(dev)->gen > 2) +#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IRONLAKE(dev)) #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) diff --git a/trunk/drivers/gpu/drm/i915/i915_gem.c b/trunk/drivers/gpu/drm/i915/i915_gem.c index 100a7537980e..cf4ffbee1c00 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem.c @@ -37,9 +37,7 @@ #include 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, - bool pipelined); +static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); 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, @@ -48,8 +46,7 @@ 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, - bool interruptible); +static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); 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); @@ -58,111 +55,9 @@ 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) { @@ -171,8 +66,7 @@ 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; @@ -186,7 +80,7 @@ int i915_gem_do_init(struct drm_device *dev, drm_mm_init(&dev_priv->mm.gtt_space, start, end - start); - dev_priv->mm.gtt_total = end - start; + dev->gtt_total = (uint32_t) (end - start); return 0; } @@ -209,16 +103,14 @@ 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; - 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); + args->aper_size = dev->gtt_total; + args->aper_available_size = (args->aper_size - + atomic_read(&dev->pin_memory)); return 0; } @@ -244,12 +136,14 @@ 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; } @@ -371,9 +265,7 @@ 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; - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return ret; + mutex_lock(&dev->struct_mutex); ret = i915_gem_object_get_pages(obj, 0); if (ret != 0) @@ -492,9 +384,7 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); - ret = i915_mutex_lock_interruptible(dev); - if (ret) - goto fail_put_user_pages; + mutex_lock(&dev->struct_mutex); ret = i915_gem_object_get_pages_or_evict(obj); if (ret) @@ -574,27 +464,21 @@ 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 = 0; + int ret; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) return -ENOENT; obj_priv = to_intel_bo(obj); - /* 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; + /* 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; } if (i915_gem_object_needs_bit17_swizzle(obj)) { @@ -606,8 +490,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, file_priv); } -out: drm_gem_object_unreference_unlocked(obj); + return ret; } @@ -696,11 +580,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); @@ -795,10 +679,7 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, goto out_unpin_pages; } - ret = i915_mutex_lock_interruptible(dev); - if (ret) - goto out_unpin_pages; - + mutex_lock(&dev->struct_mutex); ret = i915_gem_object_pin(obj, 0); if (ret) goto out_unlock; @@ -872,9 +753,7 @@ 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; - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return ret; + mutex_lock(&dev->struct_mutex); ret = i915_gem_object_get_pages(obj, 0); if (ret != 0) @@ -970,9 +849,7 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); - ret = i915_mutex_lock_interruptible(dev); - if (ret) - goto fail_put_user_pages; + mutex_lock(&dev->struct_mutex); ret = i915_gem_object_get_pages_or_evict(obj); if (ret) @@ -1057,20 +934,14 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, return -ENOENT; obj_priv = to_intel_bo(obj); - /* 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; + /* 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; } /* We can only do the GTT pwrite on untiled buffers, as otherwise @@ -1082,7 +953,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 && - obj_priv->gtt_space && + dev->gtt_total != 0 && obj->write_domain != I915_GEM_DOMAIN_CPU) { ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv); if (ret == -EFAULT) { @@ -1104,8 +975,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; } @@ -1146,14 +1017,14 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, return -ENOENT; obj_priv = to_intel_bo(obj); - ret = i915_mutex_lock_interruptible(dev); - if (ret) { - drm_gem_object_unreference_unlocked(obj); - return ret; - } + mutex_lock(&dev->struct_mutex); 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); @@ -1177,6 +1048,7 @@ 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); @@ -1195,23 +1067,27 @@ 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) + if (obj == NULL) { + mutex_unlock(&dev->struct_mutex); return -ENOENT; - - ret = i915_mutex_lock_interruptible(dev); - if (ret) { - drm_gem_object_unreference_unlocked(obj); - return ret; } +#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); + /* Pinned buffers may be scanout, so flush the cache */ - if (to_intel_bo(obj)->pin_count) + if (obj_priv->pin_count) i915_gem_object_flush_cpu_write_domain(obj); drm_gem_object_unreference(obj); @@ -1303,7 +1179,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, true); + ret = i915_gem_object_get_fence_reg(obj); if (ret) goto unlock; } @@ -1368,7 +1244,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 = -ENOSPC; + ret = -ENOMEM; goto out_free_list; } @@ -1380,9 +1256,9 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) } list->hash.key = list->file_offset_node->start; - ret = drm_ht_insert_item(&mm->offset_hash, &list->hash); - if (ret) { + if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) { DRM_ERROR("failed to add to map hash\n"); + ret = -ENOMEM; goto out_free_mm; } @@ -1467,14 +1343,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 (INTEL_INFO(dev)->gen >= 4 || obj_priv->tiling_mode == I915_TILING_NONE) + if (IS_I965G(dev) || 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 (INTEL_INFO(dev)->gen == 3) + if (IS_I9XX(dev)) start = 1024*1024; else start = 512*1024; @@ -1516,11 +1392,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -ENOENT; - ret = i915_mutex_lock_interruptible(dev); - if (ret) { - drm_gem_object_unreference_unlocked(obj); - return ret; - } + mutex_lock(&dev->struct_mutex); obj_priv = to_intel_bo(obj); @@ -1562,7 +1434,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, return 0; } -static void +void i915_gem_object_put_pages(struct drm_gem_object *obj) { struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); @@ -1596,24 +1468,13 @@ 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, +i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno, 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; @@ -1622,9 +1483,10 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, 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; } @@ -1674,8 +1536,9 @@ 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_move_tail(&obj_priv->list, &dev_priv->mm.pinned_list); + list_del_init(&obj_priv->list); else list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); @@ -1687,12 +1550,12 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) obj_priv->active = 0; drm_gem_object_unreference(obj); } - WARN_ON(i915_verify_lists(dev)); + i915_verify_inactive(dev, __FILE__, __LINE__); } static void i915_gem_process_flushing_list(struct drm_device *dev, - uint32_t flush_domains, + uint32_t flush_domains, uint32_t seqno, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -1703,13 +1566,14 @@ 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_priv->ring == ring) { + if ((obj->write_domain & flush_domains) == + obj->write_domain && + obj_priv->ring->ring_flag == ring->ring_flag) { 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, ring); + i915_gem_object_move_to_active(obj, seqno, ring); /* update the fence lru list */ if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { @@ -1727,27 +1591,23 @@ i915_gem_process_flushing_list(struct drm_device *dev, } uint32_t -i915_add_request(struct drm_device *dev, - struct drm_file *file, - struct drm_i915_gem_request *request, - struct intel_ring_buffer *ring) +i915_add_request(struct drm_device *dev, struct drm_file *file_priv, + uint32_t flush_domains, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_file_private *file_priv = NULL; + struct drm_i915_file_private *i915_file_priv = NULL; + struct drm_i915_gem_request *request; uint32_t seqno; int was_empty; - if (file != NULL) - file_priv = file->driver_priv; + if (file_priv != NULL) + i915_file_priv = file_priv->driver_priv; - if (request == NULL) { - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return 0; - } + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return 0; - seqno = ring->add_request(dev, ring, 0); - ring->outstanding_lazy_request = false; + seqno = ring->add_request(dev, ring, file_priv, flush_domains); request->seqno = seqno; request->ring = ring; @@ -1755,20 +1615,23 @@ i915_add_request(struct drm_device *dev, was_empty = list_empty(&ring->request_list); list_add_tail(&request->list, &ring->request_list); - if (file_priv) { - spin_lock(&file_priv->mm.lock); - request->file_priv = file_priv; + if (i915_file_priv) { list_add_tail(&request->client_list, - &file_priv->mm.request_list); - spin_unlock(&file_priv->mm.lock); + &i915_file_priv->mm.request_list); + } else { + INIT_LIST_HEAD(&request->client_list); } + /* 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 + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); + mod_timer(&dev_priv->hangcheck_timer, 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; } @@ -1779,105 +1642,91 @@ i915_add_request(struct drm_device *dev, * Ensures that all commands in the ring are finished * before signalling the CPU */ -static void +static uint32_t 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 (INTEL_INFO(dev)->gen >= 4) + if (IS_I965G(dev)) flush_domains |= I915_GEM_DOMAIN_SAMPLER; ring->flush(dev, ring, I915_GEM_DOMAIN_COMMAND, flush_domains); + return flush_domains; } -static inline void -i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) -{ - struct drm_i915_file_private *file_priv = request->file_priv; - - if (!file_priv) - return; - - 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) +/** + * 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) { - 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); + drm_i915_private_t *dev_priv = dev->dev_private; - list_del(&request->list); - i915_gem_request_remove_from_client(request); - kfree(request); - } + trace_i915_gem_request_retire(dev, request->seqno); - while (!list_empty(&ring->active_list)) { + /* 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; struct drm_i915_gem_object *obj_priv; - obj_priv = list_first_entry(&ring->active_list, + obj_priv = list_first_entry(&request->ring->active_list, struct drm_i915_gem_object, list); + obj = &obj_priv->base; - obj_priv->base.write_domain = 0; - list_del_init(&obj_priv->gpu_write_list); - i915_gem_object_move_to_inactive(&obj_priv->base); - } -} - -void i915_gem_reset(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv; - int i; - - 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); + /* 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; - obj_priv->base.write_domain = 0; - list_del_init(&obj_priv->gpu_write_list); - i915_gem_object_move_to_inactive(&obj_priv->base); - } +#if WATCH_LRU + DRM_INFO("%s: retire %d moves to inactive list %p\n", + __func__, request->seqno, obj); +#endif - /* 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; + 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); + } } +out: + spin_unlock(&dev_priv->mm.active_list_lock); +} - /* 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; +/** + * Returns true if seq1 is later than seq2. + */ +bool +i915_seqno_passed(uint32_t seq1, uint32_t seq2) +{ + return (int32_t)(seq1 - seq2) >= 0; +} - i915_gem_clear_fence_reg(reg->obj); - } +uint32_t +i915_get_gem_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + return ring->get_gem_seqno(dev, ring); } /** @@ -1890,58 +1739,38 @@ 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; - WARN_ON(i915_verify_lists(dev)); + seqno = i915_get_gem_seqno(dev, ring); - 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, 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); + if (i915_seqno_passed(seqno, retiring_seqno) || + atomic_read(&dev_priv->mm.wedged)) { + i915_gem_retire_request(dev, request); - if (!i915_seqno_passed(seqno, obj_priv->last_rendering_seqno)) + list_del(&request->list); + list_del(&request->client_list); + kfree(request); + } else 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 @@ -1968,7 +1797,7 @@ i915_gem_retire_requests(struct drm_device *dev) i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring); } -static void +void i915_gem_retire_work_handler(struct work_struct *work) { drm_i915_private_t *dev_priv; @@ -1978,12 +1807,7 @@ i915_gem_retire_work_handler(struct work_struct *work) mm.retire_work.work); dev = dev_priv->dev; - /* 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; - } - + mutex_lock(&dev->struct_mutex); i915_gem_retire_requests(dev); if (!dev_priv->mm.suspended && @@ -1996,7 +1820,7 @@ i915_gem_retire_work_handler(struct work_struct *work) int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, - bool interruptible, struct intel_ring_buffer *ring) + int interruptible, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; u32 ier; @@ -2005,16 +1829,9 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, BUG_ON(seqno == 0); if (atomic_read(&dev_priv->mm.wedged)) - 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); + return -EIO; - if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) { + if (!i915_seqno_passed(ring->get_gem_seqno(dev, ring), seqno)) { if (HAS_PCH_SPLIT(dev)) ier = I915_READ(DEIER) | I915_READ(GTIER); else @@ -2033,12 +1850,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_seqno(dev, ring), seqno) + ring->get_gem_seqno(dev, ring), seqno) || atomic_read(&dev_priv->mm.wedged)); else wait_event(ring->irq_queue, i915_seqno_passed( - ring->get_seqno(dev, ring), seqno) + ring->get_gem_seqno(dev, ring), seqno) || atomic_read(&dev_priv->mm.wedged)); ring->user_irq_put(dev, ring); @@ -2047,12 +1864,11 @@ 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 = -EAGAIN; + ret = -EIO; if (ret && ret != -ERESTARTSYS) - DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n", - __func__, ret, seqno, ring->get_seqno(dev, ring), - dev_priv->next_seqno); + DRM_ERROR("%s returns %d (awaiting %d at %d)\n", + __func__, ret, seqno, ring->get_gem_seqno(dev, ring)); /* Directly dispatch request retiring. While we have the work queue * to handle this, the waiter on a request often wants an associated @@ -2071,44 +1887,27 @@ 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_rings) + uint32_t flush_domains) { 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 ((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); - } + if (HAS_BSD(dev)) + dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring, + invalidate_domains, + flush_domains); } /** @@ -2116,8 +1915,7 @@ 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, - bool interruptible) +i915_gem_object_wait_rendering(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); @@ -2132,11 +1930,13 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj, * it. */ if (obj_priv->active) { - ret = i915_do_wait_request(dev, - obj_priv->last_rendering_seqno, - interruptible, - obj_priv->ring); - if (ret) +#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) return ret; } @@ -2150,10 +1950,14 @@ int i915_gem_object_unbind(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + drm_i915_private_t *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; @@ -2178,26 +1982,33 @@ 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); - drm_unbind_agp(obj_priv->agp_mem); - drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE); + 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; + } i915_gem_object_put_pages(obj); BUG_ON(obj_priv->pages_refcount); - i915_gem_info_remove_gtt(dev_priv, obj->size); - list_del_init(&obj_priv->list); + if (obj_priv->gtt_space) { + atomic_dec(&dev->gtt_count); + atomic_sub(obj->size, &dev->gtt_memory); - drm_mm_put_block(obj_priv->gtt_space); - obj_priv->gtt_space = NULL; + 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); if (i915_gem_object_is_purgeable(obj_priv)) i915_gem_object_truncate(obj); @@ -2207,45 +2018,48 @@ 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. */ - ret = i915_ring_idle(dev, &dev_priv->render_ring); - if (ret) - return ret; + 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); if (HAS_BSD(dev)) { - ret = i915_ring_idle(dev, &dev_priv->bsd_ring); + 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); if (ret) return ret; } - return 0; + + return ret; } -static int +int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask) { @@ -2425,8 +2239,7 @@ 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, - bool interruptible) +static int i915_find_fence_reg(struct drm_device *dev) { struct drm_i915_fence_reg *reg = NULL; struct drm_i915_gem_object *obj_priv = NULL; @@ -2471,7 +2284,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, interruptible); + ret = i915_gem_object_put_fence_reg(obj); drm_gem_object_unreference(obj); if (ret != 0) return ret; @@ -2493,8 +2306,7 @@ 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, - bool interruptible) +i915_gem_object_get_fence_reg(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2529,7 +2341,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj, break; } - ret = i915_find_fence_reg(dev, interruptible); + ret = i915_find_fence_reg(dev); if (ret < 0) return ret; @@ -2588,7 +2400,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: @@ -2607,19 +2419,15 @@ 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, - bool interruptible) +i915_gem_object_put_fence_reg(struct drm_gem_object *obj) { 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; @@ -2634,23 +2442,20 @@ 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. */ - reg = &dev_priv->fence_regs[obj_priv->fence_reg]; - if (reg->gpu) { + if (!IS_I965G(dev)) { int ret; - ret = i915_gem_object_flush_gpu_write_domain(obj, true); - if (ret) + ret = i915_gem_object_flush_gpu_write_domain(obj); + if (ret != 0) return ret; - ret = i915_gem_object_wait_rendering(obj, interruptible); - if (ret) + ret = i915_gem_object_wait_rendering(obj); + if (ret != 0) 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; } @@ -2683,7 +2488,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_priv->mm.gtt_total) { + if (obj->size > dev->gtt_total) { DRM_ERROR("Attempting to bind an object larger than the aperture\n"); return -E2BIG; } @@ -2701,6 +2506,9 @@ 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; @@ -2708,6 +2516,10 @@ 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); @@ -2752,10 +2564,11 @@ 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 @@ -2788,30 +2601,25 @@ 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, - bool pipelined) +i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) { 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_ring(dev, NULL, - to_intel_bo(obj)->ring, - 0, obj->write_domain); - BUG_ON(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; trace_i915_gem_object_change_domain(obj, obj->read_domains, old_write_domain); - - if (pipelined) - return 0; - - return i915_gem_object_wait_rendering(obj, true); + return 0; } /** Flushes the GTT write domain for the object if it's dirty. */ @@ -2855,6 +2663,26 @@ 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. * @@ -2872,28 +2700,32 @@ 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, false); + ret = i915_gem_object_flush_gpu_write_domain(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; - } + /* Wait on any GPU rendering and flushing to occur. */ + ret = i915_gem_object_wait_rendering(obj); + if (ret != 0) + 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; } @@ -2910,36 +2742,51 @@ 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, - bool pipelined) +i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) { + struct drm_device *dev = obj->dev; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - uint32_t old_read_domains; + uint32_t old_write_domain, 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, true); + ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret) return ret; - /* Currently, we are always called from an non-interruptible context. */ - if (!pipelined) { - ret = i915_gem_object_wait_rendering(obj, false); - if (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) return ret; } i915_gem_object_flush_cpu_write_domain(obj); + old_write_domain = obj->write_domain; old_read_domains = obj->read_domains; - obj->read_domains |= I915_GEM_DOMAIN_GTT; + + /* 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; trace_i915_gem_object_change_domain(obj, old_read_domains, - obj->write_domain); + old_write_domain); return 0; } @@ -2956,7 +2803,12 @@ 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, false); + 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); if (ret != 0) return ret; @@ -2967,12 +2819,6 @@ 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; @@ -2992,7 +2838,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; } @@ -3118,7 +2964,7 @@ static void i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + drm_i915_private_t *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; @@ -3129,6 +2975,12 @@ 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 @@ -3155,8 +3007,13 @@ 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 ((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 i915_gem_clflush_object(obj); + } old_read_domains = obj->read_domains; @@ -3170,10 +3027,21 @@ 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 (obj_priv->ring) - dev_priv->mm.flush_rings |= obj_priv->ring->id; +#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 trace_i915_gem_object_change_domain(obj, old_read_domains, @@ -3236,7 +3104,12 @@ 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, false); + 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); if (ret != 0) return ret; i915_gem_object_flush_gtt_write_domain(obj); @@ -3323,13 +3196,11 @@ 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, true); + ret = i915_gem_object_get_fence_reg(obj); 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; @@ -3387,8 +3258,6 @@ 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 || @@ -3464,7 +3333,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 ret; + return -EINVAL; } /* Map the page containing the relocation we're going to @@ -3479,6 +3348,11 @@ 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); @@ -3490,6 +3364,10 @@ 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; } @@ -3504,48 +3382,28 @@ 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) +i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_file_private *file_priv = file->driver_priv; + struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; + int ret = 0; 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; - 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; - - ring = request->ring; - seqno = request->seqno; - } - spin_unlock(&file_priv->mm.lock); + mutex_lock(&dev->struct_mutex); + while (!list_empty(&i915_file_priv->mm.request_list)) { + struct drm_i915_gem_request *request; - if (seqno == 0) - return 0; + request = list_first_entry(&i915_file_priv->mm.request_list, + struct drm_i915_gem_request, + client_list); - 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 (time_after_eq(request->emitted_jiffies, recent_enough)) + break; - if (ret == 0 && atomic_read(&dev_priv->mm.wedged)) - ret = -EIO; + ret = i915_wait_request(dev, request->seqno, request->ring); + if (ret != 0) + break; } - - if (ret == 0) - queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -3681,7 +3539,8 @@ i915_gem_wait_for_pending_flip(struct drm_device *dev, return ret; } -static int + +int i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv, struct drm_i915_gem_execbuffer2 *args, @@ -3693,18 +3552,13 @@ 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; - struct drm_i915_gem_request *request = NULL; - int ret, ret2, i, pinned = 0; + int ret = 0, ret2, i, pinned = 0; uint64_t exec_offset; - uint32_t reloc_index; + uint32_t seqno, flush_domains, 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); @@ -3751,20 +3605,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; - ret = i915_mutex_lock_interruptible(dev); - if (ret) + 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; goto pre_mutex_err; + } if (dev_priv->mm.suspended) { mutex_unlock(&dev->struct_mutex); @@ -3844,16 +3698,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, pinned+1, args->buffer_count, total_size, num_fences, ret); - 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); + 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); } goto err; } @@ -3886,13 +3739,15 @@ 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->mm.flush_rings = 0; + dev_priv->flush_rings = 0; for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; @@ -3901,6 +3756,8 @@ 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", @@ -3908,10 +3765,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, dev->invalidate_domains, dev->flush_domains); #endif - i915_gem_flush(dev, file_priv, + i915_gem_flush(dev, dev->invalidate_domains, - dev->flush_domains, - dev_priv->mm.flush_rings); + 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); } for (i = 0; i < args->buffer_count; i++) { @@ -3923,12 +3787,16 @@ 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], @@ -3955,17 +3823,33 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * Ensure that the commands in the batch buffer are * finished before the interrupt fires */ - i915_retire_commands(dev, ring); + flush_domains = i915_retire_commands(dev, ring); + + i915_verify_inactive(dev, __FILE__, __LINE__); + /* + * 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, ring); + i915_gem_object_move_to_active(obj, seqno, ring); +#if WATCH_LRU + DRM_INFO("%s: move to exec list %p\n", __func__, obj); +#endif } +#if WATCH_LRU + i915_dump_lru(dev, __func__); +#endif - i915_add_request(dev, file_priv, request, ring); - request = NULL; + i915_verify_inactive(dev, __FILE__, __LINE__); err: for (i = 0; i < pinned; i++) @@ -3998,7 +3882,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, drm_free_large(object_list); kfree(cliprects); - kfree(request); return ret; } @@ -4055,7 +3938,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 (INTEL_INFO(dev)->gen < 4) + if (!IS_I965G(dev)) exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE; else exec2_list[i].flags = 0; @@ -4152,12 +4035,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); - WARN_ON(i915_verify_lists(dev)); + + i915_verify_inactive(dev, __FILE__, __LINE__); if (obj_priv->gtt_space != NULL) { if (alignment == 0) @@ -4185,13 +4068,14 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) * remove it from the inactive list */ if (obj_priv->pin_count == 1) { - i915_gem_info_add_pin(dev_priv, obj->size); - if (!obj_priv->active) - list_move_tail(&obj_priv->list, - &dev_priv->mm.pinned_list); + 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_verify_inactive(dev, __FILE__, __LINE__); - WARN_ON(i915_verify_lists(dev)); return 0; } @@ -4202,7 +4086,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); - WARN_ON(i915_verify_lists(dev)); + i915_verify_inactive(dev, __FILE__, __LINE__); obj_priv->pin_count--; BUG_ON(obj_priv->pin_count < 0); BUG_ON(obj_priv->gtt_space == NULL); @@ -4212,12 +4096,14 @@ i915_gem_object_unpin(struct drm_gem_object *obj) * the inactive list */ if (obj_priv->pin_count == 0) { - if (!obj_priv->active) + if (!obj_priv->active && + (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); - i915_gem_info_remove_pin(dev_priv, obj->size); + atomic_dec(&dev->pin_count); + atomic_sub(obj->size, &dev->pin_memory); } - WARN_ON(i915_verify_lists(dev)); + i915_verify_inactive(dev, __FILE__, __LINE__); } int @@ -4229,20 +4115,17 @@ 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); @@ -4287,23 +4170,18 @@ 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; - 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_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); @@ -4329,7 +4207,6 @@ 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) { @@ -4338,11 +4215,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, return -ENOENT; } - ret = i915_mutex_lock_interruptible(dev); - if (ret) { - drm_gem_object_unreference_unlocked(obj); - return ret; - } + mutex_lock(&dev->struct_mutex); /* Count all active objects as busy, even if they are currently not used * by the gpu. Users of this interface expect objects to eventually @@ -4357,10 +4230,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_GPU_DOMAINS) - i915_gem_flush_ring(dev, file_priv, - obj_priv->ring, - 0, obj->write_domain); + 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); + } /* Update the active list for the hardware's current position. * Otherwise this only updates on a delayed timer or when irqs @@ -4391,7 +4264,6 @@ 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: @@ -4407,13 +4279,9 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, args->handle); return -ENOENT; } - obj_priv = to_intel_bo(obj); - ret = i915_mutex_lock_interruptible(dev); - if (ret) { - drm_gem_object_unreference_unlocked(obj); - return ret; - } + mutex_lock(&dev->struct_mutex); + obj_priv = to_intel_bo(obj); if (obj_priv->pin_count) { drm_gem_object_unreference(obj); @@ -4442,7 +4310,6 @@ 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); @@ -4454,8 +4321,6 @@ 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; @@ -4496,7 +4361,6 @@ 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); @@ -4555,7 +4419,7 @@ i915_gem_idle(struct drm_device *dev) * And not confound mm.suspended! */ dev_priv->mm.suspended = 1; - del_timer_sync(&dev_priv->hangcheck_timer); + del_timer(&dev_priv->hangcheck_timer); i915_kernel_lost_context(dev); i915_gem_cleanup_ringbuffer(dev); @@ -4635,18 +4499,28 @@ 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_render_ring_buffer(dev); + ret = intel_init_ring_buffer(dev, &dev_priv->render_ring); if (ret) goto cleanup_pipe_control; if (HAS_BSD(dev)) { - ret = intel_init_bsd_ring_buffer(dev); + dev_priv->bsd_ring = bsd_ring; + ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring); if (ret) goto cleanup_render_ring; } @@ -4699,8 +4573,11 @@ 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)); @@ -4752,10 +4629,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); @@ -4768,7 +4645,6 @@ 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); @@ -4787,30 +4663,21 @@ i915_gem_load(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) dev_priv->fence_reg_start = 3; - if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + if (IS_I965G(dev) || 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 */ - 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: + if (IS_I965G(dev)) { for (i = 0; i < 16; i++) I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0); - break; - case 3: + } else { + for (i = 0; i < 8; i++) + I915_WRITE(FENCE_REG_830_0 + (i * 4), 0); 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); @@ -4820,8 +4687,8 @@ i915_gem_load(struct drm_device *dev) * Create a physically contiguous memory object for this object * e.g. for cursor + overlay regs */ -static int i915_gem_init_phys_object(struct drm_device *dev, - int id, int size, int align) +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; @@ -4853,7 +4720,7 @@ static int i915_gem_init_phys_object(struct drm_device *dev, return ret; } -static void i915_gem_free_phys_object(struct drm_device *dev, int id) +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; @@ -4998,25 +4865,18 @@ 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) +void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv) { - struct drm_i915_file_private *file_priv = file->driver_priv; + struct drm_i915_file_private *i915_file_priv = file_priv->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. */ - 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); + 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); } static int @@ -5025,10 +4885,12 @@ 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; } diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_debug.c b/trunk/drivers/gpu/drm/i915/i915_gem_debug.c index 48644b840a8d..80f380b1d951 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem_debug.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem_debug.c @@ -30,112 +30,29 @@ #include "i915_drm.h" #include "i915_drv.h" -#if WATCH_LISTS -int -i915_verify_lists(struct drm_device *dev) +#if WATCH_INACTIVE +void +i915_verify_inactive(struct drm_device *dev, char *file, int line) { - static int warned; drm_i915_private_t *dev_priv = dev->dev_private; - 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", + 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", obj, - 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++; - } + obj_priv->pin_count, obj_priv->active, + obj->write_domain, file, line); } - - 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_EXEC | WATCH_PWRITE +#if WATCH_BUF | 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) @@ -180,6 +97,41 @@ 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) diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_evict.c b/trunk/drivers/gpu/drm/i915/i915_gem_evict.c index 3d7fbf32bb18..e85246ef691c 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem_evict.c @@ -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; + struct drm_i915_gem_object *obj_priv, *tmp_obj_priv; struct list_head *render_iter, *bsd_iter; int ret = 0; @@ -175,34 +175,39 @@ 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); - while (!list_empty(&unwind_list)) { - obj_priv = list_first_entry(&unwind_list, - struct drm_i915_gem_object, - evict_list); + list_for_each_entry_safe(obj_priv, tmp_obj_priv, + &unwind_list, 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); - continue; - } - list_del(&obj_priv->evict_list); - drm_gem_object_unreference(&obj_priv->base); + } else + drm_gem_object_unreference(&obj_priv->base); } /* Unbinding will emit any required flushes */ - 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); + 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; + drm_gem_object_unreference(&obj_priv->base); } - return ret; + /* 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; } int @@ -212,11 +217,14 @@ 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; @@ -231,11 +239,13 @@ 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; diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c b/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c index 8c9ffc4768ee..710eca70b323 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -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_GEN2(dev)) { + } else if (!IS_I9XX(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_GEN2(dev) || + if (!IS_I9XX(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 (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { /* 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 { + } else if (IS_GEN3(dev) || IS_GEN2(dev)) { 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 (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { if (stride & (tile_width - 1)) return false; return true; @@ -244,18 +244,16 @@ i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode) if (tiling_mode == I915_TILING_NONE) return true; - 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) + if (!IS_I965G(dev)) { + if (obj_priv->gtt_offset & (obj->size - 1)) 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; @@ -273,11 +271,7 @@ 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; - - ret = i915_gem_check_is_wedged(dev); - if (ret) - return ret; + int ret = 0; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) @@ -334,7 +328,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, true); + ret = i915_gem_object_put_fence_reg(obj); else i915_gem_release_mmap(obj); @@ -405,14 +399,16 @@ 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 void +static int 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); @@ -421,6 +417,8 @@ i915_gem_swizzle_page(struct page *page) } kunmap(page); + + return 0; } void @@ -442,7 +440,11 @@ 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)) { - i915_gem_swizzle_page(obj_priv->pages[i]); + int ret = i915_gem_swizzle_page(obj_priv->pages[i]); + if (ret != 0) { + DRM_ERROR("Failed to swizzle page\n"); + return; + } set_page_dirty(obj_priv->pages[i]); } } diff --git a/trunk/drivers/gpu/drm/i915/i915_irq.c b/trunk/drivers/gpu/drm/i915/i915_irq.c index 64c07c24e300..744225ebb4b2 100644 --- a/trunk/drivers/gpu/drm/i915/i915_irq.c +++ b/trunk/drivers/gpu/drm/i915/i915_irq.c @@ -85,7 +85,7 @@ ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) } /* For display hotplug interrupt */ -static void +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 (INTEL_INFO(dev)->gen >= 4) + if (IS_I965G(dev)) i915_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE); } @@ -191,7 +191,12 @@ static int i915_pipe_enabled(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE; + unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; + + if (I915_READ(pipeconf) & PIPEACONF_ENABLE) + return 1; + + return 0; } /* Called from drm generic code, passed a 'crtc', which @@ -202,7 +207,10 @@ 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; + u32 high1, high2, low, count; + + high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; + low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; if (!i915_pipe_enabled(dev, pipe)) { DRM_DEBUG_DRIVER("trying to get vblank count for disabled " @@ -210,23 +218,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; - low = I915_READ(low_frame) & PIPE_FRAME_LOW_MASK; - high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; + 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); } while (high1 != high2); - high1 >>= PIPE_FRAME_HIGH_SHIFT; - low >>= PIPE_FRAME_LOW_SHIFT; - return (high1 << 8) | low; + count = (high1 << 8) | low; + + return count; } u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) @@ -252,12 +260,16 @@ 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 intel_encoder *encoder; - - list_for_each_entry(encoder, &mode_config->encoder_list, base.head) - if (encoder->hot_plug) - encoder->hot_plug(encoder); - + 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); + } + } /* Just fire off a uevent and let userspace tell us what to do */ drm_helper_hpd_irq_event(dev); } @@ -293,17 +305,13 @@ static void i915_handle_rps_change(struct drm_device *dev) return; } -static irqreturn_t ironlake_irq_handler(struct drm_device *dev) +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); @@ -327,28 +335,28 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) } if (gt_iir & GT_PIPE_NOTIFY) { - u32 seqno = render_ring->get_seqno(dev, render_ring); + u32 seqno = render_ring->get_gem_seqno(dev, render_ring); render_ring->irq_gem_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); - wake_up_all(&dev_priv->render_ring.irq_queue); + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); dev_priv->hangcheck_count = 0; - mod_timer(&dev_priv->hangcheck_timer, - jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); + mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } - if (gt_iir & bsd_usr_interrupt) - wake_up_all(&dev_priv->bsd_ring.irq_queue); + if (gt_iir & GT_BSD_USER_INTERRUPT) + DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + if (de_iir & DE_GSE) - intel_opregion_gse_intr(dev); + ironlake_opregion_gse_intr(dev); if (de_iir & DE_PLANEA_FLIP_DONE) { intel_prepare_page_flip(dev, 0); - intel_finish_page_flip_plane(dev, 0); + intel_finish_page_flip(dev, 0); } if (de_iir & DE_PLANEB_FLIP_DONE) { intel_prepare_page_flip(dev, 1); - intel_finish_page_flip_plane(dev, 1); + intel_finish_page_flip(dev, 1); } if (de_iir & DE_PIPEA_VBLANK) @@ -396,20 +404,23 @@ 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)) { - 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); + 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"); } - 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) @@ -500,7 +511,7 @@ i915_get_bbaddr(struct drm_device *dev, u32 *ring) if (IS_I830(dev) || IS_845G(dev)) cmd = MI_BATCH_BUFFER; - else if (INTEL_INFO(dev)->gen >= 4) + else if (IS_I965G(dev)) cmd = (MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); else @@ -573,16 +584,13 @@ static void i915_capture_error_state(struct drm_device *dev) return; } - DRM_DEBUG_DRIVER("generating error event\n"); - - error->seqno = - dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring); + error->seqno = i915_get_gem_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 (INTEL_INFO(dev)->gen < 4) { + if (!IS_I965G(dev)) { error->ipeir = I915_READ(IPEIR); error->ipehr = I915_READ(IPEHR); error->instdone = I915_READ(INSTDONE); @@ -736,9 +744,6 @@ 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) { @@ -780,7 +785,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) } } - if (!IS_GEN2(dev)) { + if (IS_I9XX(dev)) { if (eir & I915_ERROR_PAGE_TABLE) { u32 pgtbl_err = I915_READ(PGTBL_ER); printk(KERN_ERR "page table error\n"); @@ -806,7 +811,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 (INTEL_INFO(dev)->gen < 4) { + if (!IS_I965G(dev)) { u32 ipeir = I915_READ(IPEIR); printk(KERN_ERR " IPEIR: 0x%08x\n", @@ -871,15 +876,12 @@ 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 */ - wake_up_all(&dev_priv->render_ring.irq_queue); - if (HAS_BSD(dev)) - wake_up_all(&dev_priv->bsd_ring.irq_queue); + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); } queue_work(dev_priv->wq, &dev_priv->error_work); @@ -910,7 +912,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 (INTEL_INFO(dev)->gen >= 4) { + if(IS_I965G(dev)) { int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF; stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset; } else { @@ -949,7 +951,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) iir = I915_READ(IIR); - if (INTEL_INFO(dev)->gen >= 4) + if (IS_I965G(dev)) vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS; else vblank_status = PIPE_VBLANK_INTERRUPT_STATUS; @@ -1018,17 +1020,17 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (iir & I915_USER_INTERRUPT) { - u32 seqno = render_ring->get_seqno(dev, render_ring); + u32 seqno = + render_ring->get_gem_seqno(dev, render_ring); render_ring->irq_gem_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); - wake_up_all(&dev_priv->render_ring.irq_queue); + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); dev_priv->hangcheck_count = 0; - mod_timer(&dev_priv->hangcheck_timer, - jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); + mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT)) - wake_up_all(&dev_priv->bsd_ring.irq_queue); + DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { intel_prepare_page_flip(dev, 0); @@ -1063,7 +1065,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)) - intel_opregion_asle_intr(dev); + opregion_asle_intr(dev); /* With MSI, interrupts are only generated when iir * transitions from zero to nonzero. If another bit got @@ -1205,15 +1207,18 @@ 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; - if (!i915_pipe_enabled(dev, pipe)) + pipeconf = I915_READ(pipeconf_reg); + if (!(pipeconf & PIPEACONF_ENABLE)) 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 (INTEL_INFO(dev)->gen >= 4) + else if (IS_I965G(dev)) i915_enable_pipestat(dev_priv, pipe, PIPE_START_VBLANK_INTERRUPT_ENABLE); else @@ -1247,7 +1252,7 @@ void i915_enable_interrupt (struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; if (!HAS_PCH_SPLIT(dev)) - intel_opregion_enable_asle(dev); + opregion_enable_asle(dev); dev_priv->irq_enabled = 1; } @@ -1306,7 +1311,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, return -EINVAL; } -static struct drm_i915_gem_request * +struct drm_i915_gem_request * i915_get_tail_request(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -1326,7 +1331,11 @@ void i915_hangcheck_elapsed(unsigned long data) drm_i915_private_t *dev_priv = dev->dev_private; uint32_t acthd, instdone, instdone1; - if (INTEL_INFO(dev)->gen < 4) { + /* No reset support on this chip yet. */ + if (IS_GEN6(dev)) + return; + + if (!IS_I965G(dev)) { acthd = I915_READ(ACTHD); instdone = I915_READ(INSTDONE); instdone1 = 0; @@ -1338,8 +1347,9 @@ 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(dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring), - i915_get_tail_request(dev)->seqno)) { + i915_seqno_passed(i915_get_gem_seqno(dev, + &dev_priv->render_ring), + i915_get_tail_request(dev)->seqno)) { bool missed_wakeup = false; dev_priv->hangcheck_count = 0; @@ -1347,13 +1357,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)) { - wake_up_all(&dev_priv->render_ring.irq_queue); + DRM_WAKEUP(&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)) { - wake_up_all(&dev_priv->bsd_ring.irq_queue); + DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); missed_wakeup = true; } @@ -1367,21 +1377,6 @@ 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; } @@ -1393,10 +1388,8 @@ 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 + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); + mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } /* drm_dma.h hooks @@ -1443,19 +1436,17 @@ 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 | GT_GEN6_BSD_USER_INTERRUPT; + render_mask = GT_PIPE_NOTIFY; 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); @@ -1587,7 +1578,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev) I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); } - intel_opregion_enable_asle(dev); + opregion_enable_asle(dev); return 0; } diff --git a/trunk/drivers/gpu/drm/i915/intel_opregion.c b/trunk/drivers/gpu/drm/i915/i915_opregion.c similarity index 81% rename from trunk/drivers/gpu/drm/i915/intel_opregion.c rename to trunk/drivers/gpu/drm/i915/i915_opregion.c index 917c7dc3cd6b..ea5d3fea4b61 100644 --- a/trunk/drivers/gpu/drm/i915/intel_opregion.c +++ b/trunk/drivers/gpu/drm/i915/i915_opregion.c @@ -31,16 +31,17 @@ #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 0x400 +#define OPREGION_VBT_OFFSET 0x1000 #define OPREGION_SIGNATURE "IntelGraphicsMem" #define MBOX_ACPI (1<<0) @@ -142,22 +143,40 @@ 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 max; + u32 blc_pwm_ctl, blc_pwm_ctl2; + u32 max_backlight, level, shift; if (!(bclp & ASLE_BCLP_VALID)) return ASLE_BACKLIGHT_FAILED; bclp &= ASLE_BCLP_MSK; - if (bclp > 255) + if (bclp < 0 || bclp > 255) return ASLE_BACKLIGHT_FAILED; - max = intel_panel_get_max_backlight(dev); - intel_panel_set_backlight(dev, bclp * max / 255); + 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)); + } asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; return 0; @@ -192,7 +211,7 @@ static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) return 0; } -void intel_opregion_asle_intr(struct drm_device *dev) +void opregion_asle_intr(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct opregion_asle *asle = dev_priv->opregion.asle; @@ -224,8 +243,37 @@ void intel_opregion_asle_intr(struct drm_device *dev) asle->aslc = asle_stat; } -/* Only present on Ironlake+ */ -void intel_opregion_gse_intr(struct drm_device *dev) +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) { struct drm_i915_private *dev_priv = dev->dev_private; struct opregion_asle *asle = dev_priv->opregion.asle; @@ -248,7 +296,7 @@ void intel_opregion_gse_intr(struct drm_device *dev) } if (asle_req & ASLE_SET_BACKLIGHT) - asle_stat |= asle_set_backlight(dev, asle->bclp); + asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp); if (asle_req & ASLE_SET_PFIT) { DRM_DEBUG_DRIVER("Pfit is not supported\n"); @@ -267,7 +315,7 @@ void intel_opregion_gse_intr(struct drm_device *dev) #define ASLE_PFIT_EN (1<<2) #define ASLE_PFMB_EN (1<<3) -void intel_opregion_enable_asle(struct drm_device *dev) +void opregion_enable_asle(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct opregion_asle *asle = dev_priv->opregion.asle; @@ -416,58 +464,7 @@ static void intel_didl_outputs(struct drm_device *dev) goto end; } -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) +int intel_opregion_init(struct drm_device *dev, int resume) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; @@ -482,23 +479,29 @@ int intel_opregion_setup(struct drm_device *dev) return -ENOTSUPP; } - base = ioremap(asls, OPREGION_SIZE); + base = ioremap(asls, OPREGION_SZ); if (!base) return -ENOMEM; - if (memcmp(base, OPREGION_SIGNATURE, 16)) { + opregion->header = base; + if (memcmp(opregion->header->signature, 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"); @@ -507,11 +510,53 @@ int intel_opregion_setup(struct drm_device *dev) 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; +} diff --git a/trunk/drivers/gpu/drm/i915/i915_reg.h b/trunk/drivers/gpu/drm/i915/i915_reg.h index d02de212e6ad..4f5e15577e89 100644 --- a/trunk/drivers/gpu/drm/i915/i915_reg.h +++ b/trunk/drivers/gpu/drm/i915/i915_reg.h @@ -25,16 +25,52 @@ #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 */ @@ -70,13 +106,10 @@ #define I915_GC_RENDER_CLOCK_200_MHZ (1 << 0) #define I915_GC_RENDER_CLOCK_333_MHZ (4 << 0) #define LBB 0xf4 - -/* 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) +#define GDRST 0xc0 +#define GDRST_FULL (0<<2) +#define GDRST_RENDER (1<<2) +#define GDRST_MEDIA (3<<2) /* VGA stuff */ @@ -159,11 +192,11 @@ #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 */ @@ -216,16 +249,6 @@ #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 */ @@ -260,16 +283,6 @@ #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 @@ -282,8 +295,6 @@ #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 */ @@ -295,6 +306,7 @@ #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 */ @@ -452,17 +464,17 @@ #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 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 +#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 /* * Framebuffer compression (915+ only) @@ -567,51 +579,12 @@ # define GPIO_DATA_VAL_IN (1 << 12) # define GPIO_DATA_PULLUP_DISABLE (1 << 13) -#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) +#define GMBUS0 0x5100 +#define GMBUS1 0x5104 +#define GMBUS2 0x5108 +#define GMBUS3 0x510c +#define GMBUS4 0x5110 +#define GMBUS5 0x5120 /* * Clock control & power management @@ -630,7 +603,6 @@ #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) @@ -668,6 +640,24 @@ #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 @@ -746,13 +736,10 @@ #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 @@ -773,7 +760,6 @@ #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) @@ -940,8 +926,6 @@ #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 @@ -1086,8 +1070,6 @@ #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 @@ -1168,15 +1150,6 @@ #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) @@ -1508,7 +1481,6 @@ # 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). * @@ -2103,35 +2075,29 @@ /* 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 PIPECONF_ENABLE (1<<31) -#define PIPECONF_DISABLE 0 -#define PIPECONF_DOUBLE_WIDE (1<<30) +#define PIPEACONF_ENABLE (1<<31) +#define PIPEACONF_DISABLE 0 +#define PIPEACONF_DOUBLE_WIDE (1<<30) #define I965_PIPECONF_ACTIVE (1<<30) -#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 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_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) @@ -2162,15 +2128,12 @@ #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 @@ -2243,8 +2206,8 @@ #define WM1_LP_SR_EN (1<<31) #define WM1_LP_LATENCY_SHIFT 24 #define WM1_LP_LATENCY_MASK (0x7f<<24) -#define WM1_LP_FBC_MASK (0xf<<20) -#define WM1_LP_FBC_SHIFT 20 +#define WM1_LP_FBC_LP1_MASK (0xf<<20) +#define WM1_LP_FBC_LP1_SHIFT 20 #define WM1_LP_SR_MASK (0x1ff<<8) #define WM1_LP_SR_SHIFT 8 #define WM1_LP_CURSOR_MASK (0x3f) @@ -2370,14 +2333,6 @@ #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 @@ -2442,7 +2397,6 @@ #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 @@ -2466,47 +2420,46 @@ #define PIPEA_DATA_M1 0x60030 #define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ #define TU_SIZE_MASK 0x7e000000 -#define PIPE_DATA_M1_OFFSET 0 +#define PIPEA_DATA_M1_OFFSET 0 #define PIPEA_DATA_N1 0x60034 -#define PIPE_DATA_N1_OFFSET 0 +#define PIPEA_DATA_N1_OFFSET 0 #define PIPEA_DATA_M2 0x60038 -#define PIPE_DATA_M2_OFFSET 0 +#define PIPEA_DATA_M2_OFFSET 0 #define PIPEA_DATA_N2 0x6003c -#define PIPE_DATA_N2_OFFSET 0 +#define PIPEA_DATA_N2_OFFSET 0 #define PIPEA_LINK_M1 0x60040 -#define PIPE_LINK_M1_OFFSET 0 +#define PIPEA_LINK_M1_OFFSET 0 #define PIPEA_LINK_N1 0x60044 -#define PIPE_LINK_N1_OFFSET 0 +#define PIPEA_LINK_N1_OFFSET 0 #define PIPEA_LINK_M2 0x60048 -#define PIPE_LINK_M2_OFFSET 0 +#define PIPEA_LINK_M2_OFFSET 0 #define PIPEA_LINK_N2 0x6004c -#define PIPE_LINK_N2_OFFSET 0 +#define PIPEA_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 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) +#define PIPEB_LINK_N2_OFFSET 0 /* CPU panel fitter */ #define PFA_CTL_1 0x68080 @@ -2563,7 +2516,7 @@ #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 @@ -2647,14 +2600,11 @@ #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 @@ -2740,13 +2690,6 @@ #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 @@ -2758,7 +2701,6 @@ #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) @@ -2783,7 +2725,6 @@ /* 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) @@ -2825,8 +2766,8 @@ /* 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) @@ -2841,7 +2782,8 @@ #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_PCDCLK (1<<4) +#define FDI_SEL_RAWCLK (0<<4) +#define FDI_SEL_PCDCLK (1<<4) /* CPT */ #define FDI_AUTO_TRAINING (1<<10) #define FDI_LINK_TRAIN_PATTERN_1_CPT (0<<8) @@ -2856,9 +2798,6 @@ #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) @@ -2877,8 +2816,6 @@ #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 @@ -2998,7 +2935,6 @@ #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) diff --git a/trunk/drivers/gpu/drm/i915/i915_suspend.c b/trunk/drivers/gpu/drm/i915/i915_suspend.c index 989c19d2d959..31f08581e93a 100644 --- a/trunk/drivers/gpu/drm/i915/i915_suspend.c +++ b/trunk/drivers/gpu/drm/i915/i915_suspend.c @@ -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 (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) + if (IS_I965G(dev) && !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 (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { 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 (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) + if (IS_I965G(dev) && !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 (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965GM(dev) || IS_GM45(dev)) { 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 (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { + if (IS_I965G(dev) && !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 (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { 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 (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { + if (IS_I965G(dev) && !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 (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { 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_GEN2(dev)) + if (!IS_I9XX(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 (INTEL_INFO(dev)->gen >= 4) + if (IS_I965G(dev)) 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_GEN2(dev)) + if (!IS_I9XX(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 (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); if (HAS_PCH_SPLIT(dev)) { @@ -878,7 +878,9 @@ int i915_restore_state(struct drm_device *dev) for (i = 0; i < 3; i++) I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); - intel_i2c_reset(dev); + /* I2C state */ + intel_i2c_reset_gmbus(dev); return 0; } + diff --git a/trunk/drivers/gpu/drm/i915/intel_bios.c b/trunk/drivers/gpu/drm/i915/intel_bios.c index b1f73ac0f3fd..96f75d7f6633 100644 --- a/trunk/drivers/gpu/drm/i915/intel_bios.c +++ b/trunk/drivers/gpu/drm/i915/intel_bios.c @@ -129,6 +129,10 @@ 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; @@ -136,7 +140,6 @@ 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); @@ -166,8 +169,6 @@ 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); @@ -229,6 +230,8 @@ 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; @@ -257,6 +260,10 @@ 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; @@ -282,6 +289,14 @@ 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) { @@ -289,8 +304,10 @@ 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_pin = bus_pin; + if ((bus_pin >= 1) && (bus_pin <= 6)) { + dev_priv->crt_ddc_bus = + crt_bus_map_table[bus_pin-1]; + } } else { DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", block_size); @@ -300,7 +317,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; @@ -310,7 +327,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, unable to construct sdvo mapping.\n"); + DRM_DEBUG_KMS("No general definition block is found\n"); return; } /* judge whether the size of child device meets the requirements. @@ -360,16 +377,7 @@ 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"); @@ -401,11 +409,14 @@ parse_driver_features(struct drm_i915_private *dev_priv, if (!driver) return; - if (SUPPORTS_EDP(dev) && - driver->lvds_config == BDB_DRIVER_FEATURE_EDP) - dev_priv->edp.support = 1; + if (driver && SUPPORTS_EDP(dev) && + driver->lvds_config == BDB_DRIVER_FEATURE_EDP) { + dev_priv->edp_support = 1; + } else { + dev_priv->edp_support = 0; + } - if (driver->dual_frequency) + if (driver && driver->dual_frequency) dev_priv->render_reclock_avail = true; } @@ -416,40 +427,26 @@ 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 %dbpp panel color " - "depth.\n", - dev_priv->edp.bpp); + "supported, assume 18bpp panel color " + "depth.\n"); + dev_priv->edp_bpp = 18; } 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 @@ -463,7 +460,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, no devices defined.\n"); + DRM_DEBUG_KMS("No general definition block is found\n"); return; } /* judge whether the size of child device meets the requirements. @@ -516,28 +513,6 @@ 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 @@ -545,6 +520,11 @@ init_vbt_defaults(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 @@ -552,48 +532,32 @@ intel_init_bios(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct pci_dev *pdev = dev->pdev; - 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 (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; - } - } - - if (!vbt) { - DRM_ERROR("VBT signature missing\n"); - pci_unmap_rom(pdev, bios); - return -1; + 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; } + } - 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); parse_general_definitions(dev_priv, bdb); @@ -604,8 +568,7 @@ intel_init_bios(struct drm_device *dev) parse_driver_features(dev_priv, bdb); parse_edp(dev_priv, bdb); - if (bios) - pci_unmap_rom(pdev, bios); + pci_unmap_rom(pdev, bios); return 0; } diff --git a/trunk/drivers/gpu/drm/i915/intel_bios.h b/trunk/drivers/gpu/drm/i915/intel_bios.h index e1a598f2a966..4c18514f6f80 100644 --- a/trunk/drivers/gpu/drm/i915/intel_bios.h +++ b/trunk/drivers/gpu/drm/i915/intel_bios.h @@ -197,8 +197,7 @@ struct bdb_general_features { struct child_device_config { u16 handle; u16 device_type; - u8 i2c_speed; - u8 rsvd[9]; + u8 device_id[10]; /* See DEVICE_TYPE_* above */ u16 addin_offset; u8 dvo_port; /* See Device_PORT_* above */ u8 i2c_pin; diff --git a/trunk/drivers/gpu/drm/i915/intel_crt.c b/trunk/drivers/gpu/drm/i915/intel_crt.c index 389fcd2aea1f..197d4f32585a 100644 --- a/trunk/drivers/gpu/drm/i915/intel_crt.c +++ b/trunk/drivers/gpu/drm/i915/intel_crt.c @@ -79,7 +79,7 @@ static int intel_crt_mode_valid(struct drm_connector *connector, if (mode->clock < 25000) return MODE_CLOCK_LOW; - if (IS_GEN2(dev)) + if (!IS_I9XX(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 (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { + if (IS_I965G(dev) && !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)) + 1000, 1)) 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)) + 1000, 1)) DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off"); } @@ -261,47 +261,21 @@ 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 = to_intel_encoder(encoder); - struct drm_i915_private *dev_priv = encoder->dev->dev_private; + struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); /* CRT should always be at 0, but check anyway */ if (intel_encoder->type != INTEL_OUTPUT_ANALOG) return false; - 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; + return intel_ddc_probe(intel_encoder); } static enum drm_connector_status intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder) { - struct drm_encoder *encoder = &intel_encoder->base; + struct drm_encoder *encoder = &intel_encoder->enc; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -321,8 +295,6 @@ 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; @@ -352,10 +324,9 @@ 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_GEN2(dev)) { + if (IS_I9XX(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); @@ -433,37 +404,34 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; - struct intel_encoder *encoder = intel_attached_encoder(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct drm_crtc *crtc; int dpms_mode; enum drm_connector_status status; - if (I915_HAS_HOTPLUG(dev)) { - if (intel_crt_detect_hotplug(connector)) { - DRM_DEBUG_KMS("CRT detected via hotplug\n"); + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { + if (intel_crt_detect_hotplug(connector)) return connector_status_connected; - } else + else return connector_status_disconnected; } - if (intel_crt_detect_ddc(&encoder->base)) + if (intel_crt_detect_ddc(encoder)) return connector_status_connected; if (!force) return connector->status; /* for pre-945g platforms use load detect */ - if (encoder->base.crtc && encoder->base.crtc->enabled) { - status = intel_crt_load_detect(encoder->base.crtc, encoder); + if (encoder->crtc && encoder->crtc->enabled) { + status = intel_crt_load_detect(encoder->crtc, intel_encoder); } else { - crtc = intel_get_load_detect_pipe(encoder, connector, + crtc = intel_get_load_detect_pipe(intel_encoder, connector, NULL, &dpms_mode); if (crtc) { - 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, + status = intel_crt_load_detect(crtc, intel_encoder); + intel_release_load_detect_pipe(intel_encoder, connector, dpms_mode); } else status = connector_status_unknown; @@ -481,18 +449,32 @@ static void intel_crt_destroy(struct drm_connector *connector) static int intel_crt_get_modes(struct drm_connector *connector) { - struct drm_device *dev = connector->dev; - struct drm_i915_private *dev_priv = dev->dev_private; 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; + - ret = intel_ddc_get_modes(connector, - &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); + ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); if (ret || !IS_G4X(dev)) - return ret; + goto end; /* Try to probe digital port for output in DVI-I -> VGA mode. */ - return intel_ddc_get_modes(connector, - &dev_priv->gmbus[GMBUS_PORT_DPB].adapter); + 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; + } static int intel_crt_set_property(struct drm_connector *connector, @@ -525,7 +507,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_best_encoder, + .best_encoder = intel_attached_encoder, }; static const struct drm_encoder_funcs intel_crt_enc_funcs = { @@ -538,6 +520,7 @@ 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) @@ -553,10 +536,27 @@ 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->base, &intel_crt_enc_funcs, + drm_encoder_init(dev, &intel_encoder->enc, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); - intel_connector_attach_encoder(intel_connector, intel_encoder); + 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_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->base, &intel_crt_helper_funcs); + drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_sysfs_connector_add(connector); diff --git a/trunk/drivers/gpu/drm/i915/intel_display.c b/trunk/drivers/gpu/drm/i915/intel_display.c index 69c54c5a4254..b5bf51a4502d 100644 --- a/trunk/drivers/gpu/drm/i915/intel_display.c +++ b/trunk/drivers/gpu/drm/i915/intel_display.c @@ -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); -static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); +static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule); +static void intel_crtc_update_cursor(struct drm_crtc *crtc); typedef struct { /* given values */ @@ -342,13 +342,6 @@ 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 }, @@ -708,16 +701,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; @@ -751,17 +744,20 @@ 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 intel_encoder *encoder; + struct drm_device *dev = crtc->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_encoder *l_entry; - list_for_each_entry(encoder, &mode_config->encoder_list, base.head) - if (encoder->base.crtc == crtc && encoder->type == type) - return true; - - return false; + 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; } #define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) @@ -959,26 +955,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; } /** @@ -1011,14 +1007,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)) + if (wait_for((I915_READ(pipestat_reg) & + PIPE_VBLANK_INTERRUPT_STATUS), + 50, 0)) DRM_DEBUG_KMS("vblank wait timed out\n"); } -/* - * intel_wait_for_pipe_off - wait for pipe to turn off +/** + * intel_wait_for_vblank_off - wait for vblank after disabling a pipe * @dev: drm device * @pipe: pipe to wait for * @@ -1026,41 +1022,28 @@ 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. * - * 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). - * + * So this function waits for the display line value to settle (it + * usually ends up stopping at the start of the next frame). */ -void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) +void intel_wait_for_vblank_off(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - - 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"); - } + 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"); } +/* Parameters have changed, update FBC info */ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) { struct drm_device *dev = crtc->dev; @@ -1072,14 +1055,6 @@ 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) @@ -1113,7 +1088,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) @@ -1121,16 +1096,19 @@ void i8xx_disable_fbc(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 fbc_ctl; - /* Disable compression */ - fbc_ctl = I915_READ(FBC_CONTROL); - if ((fbc_ctl & FBC_CTL_EN) == 0) + 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); 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)) { + if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) { DRM_DEBUG_KMS("FBC idle timed out\n"); return; } @@ -1153,27 +1131,14 @@ 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) { @@ -1183,6 +1148,7 @@ 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)); @@ -1201,12 +1167,10 @@ void g4x_disable_fbc(struct drm_device *dev) /* Disable compression */ dpfc_ctl = I915_READ(DPFC_CONTROL); - if (dpfc_ctl & DPFC_CTL_EN) { - dpfc_ctl &= ~DPFC_CTL_EN; - I915_WRITE(DPFC_CONTROL, dpfc_ctl); + 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) @@ -1224,30 +1188,16 @@ 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) { @@ -1257,13 +1207,15 @@ 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, dpfc_ctl | DPFC_CTL_EN); + I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) | + DPFC_CTL_EN); DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); } @@ -1275,12 +1227,10 @@ void ironlake_disable_fbc(struct drm_device *dev) /* Disable compression */ dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); - if (dpfc_ctl & DPFC_CTL_EN) { - dpfc_ctl &= ~DPFC_CTL_EN; - I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); + 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) @@ -1322,7 +1272,8 @@ void intel_disable_fbc(struct drm_device *dev) /** * intel_update_fbc - enable/disable FBC as needed - * @dev: the drm_device + * @crtc: CRTC to point the compressor at + * @mode: mode in use * * Set up the framebuffer compression hardware at mode set time. We * enable it if possible: @@ -1339,14 +1290,18 @@ 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_device *dev) +static void intel_update_fbc(struct drm_crtc *crtc, + struct drm_display_mode *mode) { + struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = NULL, *tmp_crtc; - struct intel_crtc *intel_crtc; - struct drm_framebuffer *fb; + struct drm_framebuffer *fb = crtc->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"); @@ -1356,6 +1311,12 @@ static void intel_update_fbc(struct drm_device *dev) 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... @@ -1366,47 +1327,35 @@ static void intel_update_fbc(struct drm_device *dev) * - 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) { - 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; - } + if (tmp_crtc->enabled) + crtcs_enabled++; } - - if (!crtc || crtc->fb == NULL) { - DRM_DEBUG_KMS("no output, disabling\n"); - dev_priv->no_fbc_reason = FBC_NO_OUTPUT; + 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; 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 ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) || - (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) { + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) || + (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 ((crtc->mode.hdisplay > 2048) || - (crtc->mode.vdisplay > 1536)) { + if ((mode->hdisplay > 2048) || + (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)) && intel_crtc->plane != 0) { + if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) { DRM_DEBUG_KMS("plane not 0, disabling compression\n"); dev_priv->no_fbc_reason = FBC_BAD_PLANE; goto out_disable; @@ -1421,7 +1370,18 @@ static void intel_update_fbc(struct drm_device *dev) if (in_dbg_master()) goto out_disable; - intel_enable_fbc(crtc, 500); + 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); + return; out_disable: @@ -1433,9 +1393,7 @@ static void intel_update_fbc(struct drm_device *dev) } int -intel_pin_and_fence_fb_obj(struct drm_device *dev, - struct drm_gem_object *obj, - bool pipelined) +intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) { struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); u32 alignment; @@ -1445,7 +1403,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, case I915_TILING_NONE: if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) alignment = 128 * 1024; - else if (INTEL_INFO(dev)->gen >= 4) + else if (IS_I965G(dev)) alignment = 4 * 1024; else alignment = 64 * 1024; @@ -1463,13 +1421,9 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, } ret = i915_gem_object_pin(obj, alignment); - if (ret) + if (ret != 0) 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 @@ -1477,16 +1431,14 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, */ if (obj_priv->fence_reg == I915_FENCE_REG_NONE && obj_priv->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj, false); - if (ret) - goto err_unpin; + ret = i915_gem_object_get_fence_reg(obj); + if (ret != 0) { + i915_gem_object_unpin(obj); + return ret; + } } return 0; - -err_unpin: - i915_gem_object_unpin(obj); - return ret; } /* Assume fb object is pinned & idle & fenced and just update base pointers */ @@ -1502,8 +1454,12 @@ 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: @@ -1518,8 +1474,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, obj = intel_fb->obj; obj_priv = to_intel_bo(obj); - reg = DSPCNTR(plane); - dspcntr = I915_READ(reg); + dspcntr = I915_READ(dspcntr_reg); /* Mask out pixel format bits in case we change it */ dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; switch (fb->bits_per_pixel) { @@ -1540,7 +1495,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, DRM_ERROR("Unknown color depth\n"); return -EINVAL; } - if (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { if (obj_priv->tiling_mode != I915_TILING_NONE) dspcntr |= DISPPLANE_TILED; else @@ -1551,24 +1506,28 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, /* must disable */ dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; - I915_WRITE(reg, dspcntr); + I915_WRITE(dspcntr_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(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); + 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); - intel_update_fbc(dev); - intel_increase_pllclock(crtc); + if (IS_I965G(dev) || plane == 0) + intel_update_fbc(crtc, &crtc->mode); + + intel_wait_for_vblank(dev, intel_crtc->pipe); + intel_increase_pllclock(crtc, true); return 0; } @@ -1580,6 +1539,11 @@ 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 */ @@ -1588,41 +1552,45 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } - switch (intel_crtc->plane) { + switch (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, - to_intel_framebuffer(crtc->fb)->obj, - false); + ret = intel_pin_and_fence_fb_obj(dev, obj); if (ret != 0) { 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 = i915_gem_object_set_to_display_plane(obj); + if (ret != 0) { + i915_gem_object_unpin(obj); + mutex_unlock(&dev->struct_mutex); + return ret; } ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y); if (ret) { - i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); + i915_gem_object_unpin(obj); mutex_unlock(&dev->struct_mutex); return ret; } - if (old_fb) - i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj); + 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); + } mutex_unlock(&dev->struct_mutex); @@ -1633,7 +1601,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (!master_priv->sarea_priv) return 0; - if (intel_crtc->pipe) { + if (pipe) { master_priv->sarea_priv->pipeB_x = x; master_priv->sarea_priv->pipeB_y = y; } else { @@ -1644,7 +1612,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; @@ -1677,7 +1645,6 @@ static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock) } I915_WRITE(DP_A, dpa_ctl); - POSTING_READ(DP_A); udelay(500); } @@ -1688,84 +1655,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; - u32 reg, temp, tries; + 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; /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ - reg = FDI_RX_IMR(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_rx_imr_reg); temp &= ~FDI_RX_SYMBOL_LOCK; temp &= ~FDI_RX_BIT_LOCK; - I915_WRITE(reg, temp); - I915_READ(reg); + I915_WRITE(fdi_rx_imr_reg, temp); + I915_READ(fdi_rx_imr_reg); udelay(150); /* enable CPU FDI TX and PCH FDI RX */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_tx_reg); + temp |= FDI_TX_ENABLE; temp &= ~(7 << 19); temp |= (intel_crtc->fdi_lanes - 1) << 19; temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; - I915_WRITE(reg, temp | FDI_TX_ENABLE); + I915_WRITE(fdi_tx_reg, temp); + I915_READ(fdi_tx_reg); - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_rx_reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; - I915_WRITE(reg, temp | FDI_RX_ENABLE); - - POSTING_READ(reg); + I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE); + I915_READ(fdi_rx_reg); udelay(150); - reg = FDI_RX_IIR(pipe); for (tries = 0; tries < 5; tries++) { - temp = I915_READ(reg); + temp = I915_READ(fdi_rx_iir_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(reg, temp | FDI_RX_BIT_LOCK); + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_BIT_LOCK); break; } } if (tries == 5) - DRM_ERROR("FDI train 1 fail!\n"); + DRM_DEBUG_KMS("FDI train 1 fail!\n"); /* Train 2 */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_tx_reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; - I915_WRITE(reg, temp); + I915_WRITE(fdi_tx_reg, temp); - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_rx_reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; - I915_WRITE(reg, temp); - - POSTING_READ(reg); + I915_WRITE(fdi_rx_reg, temp); udelay(150); - reg = FDI_RX_IIR(pipe); + tries = 0; + for (tries = 0; tries < 5; tries++) { - temp = I915_READ(reg); + temp = I915_READ(fdi_rx_iir_reg); DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); if (temp & FDI_RX_SYMBOL_LOCK) { - I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_SYMBOL_LOCK); DRM_DEBUG_KMS("FDI train 2 done.\n"); break; } } if (tries == 5) - DRM_ERROR("FDI train 2 fail!\n"); + DRM_DEBUG_KMS("FDI train 2 fail!\n"); DRM_DEBUG_KMS("FDI train done\n"); } -static const int const snb_b_fdi_train_param [] = { +static int 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, @@ -1779,22 +1746,24 @@ 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; - u32 reg, temp, i; + 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; /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ - reg = FDI_RX_IMR(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_rx_imr_reg); temp &= ~FDI_RX_SYMBOL_LOCK; temp &= ~FDI_RX_BIT_LOCK; - I915_WRITE(reg, temp); - - POSTING_READ(reg); + I915_WRITE(fdi_rx_imr_reg, temp); + I915_READ(fdi_rx_imr_reg); udelay(150); /* enable CPU FDI TX and PCH FDI RX */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_tx_reg); + temp |= FDI_TX_ENABLE; temp &= ~(7 << 19); temp |= (intel_crtc->fdi_lanes - 1) << 19; temp &= ~FDI_LINK_TRAIN_NONE; @@ -1802,10 +1771,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(reg, temp | FDI_TX_ENABLE); + I915_WRITE(fdi_tx_reg, temp); + I915_READ(fdi_tx_reg); - reg = FDI_RX_CTL(pipe); - temp = I915_READ(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; @@ -1813,37 +1782,32 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; } - I915_WRITE(reg, temp | FDI_RX_ENABLE); - - POSTING_READ(reg); + I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE); + I915_READ(fdi_rx_reg); udelay(150); for (i = 0; i < 4; i++ ) { - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_tx_reg); temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; temp |= snb_b_fdi_train_param[i]; - I915_WRITE(reg, temp); - - POSTING_READ(reg); + I915_WRITE(fdi_tx_reg, temp); udelay(500); - reg = FDI_RX_IIR(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_rx_iir_reg); DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); if (temp & FDI_RX_BIT_LOCK) { - I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_BIT_LOCK); DRM_DEBUG_KMS("FDI train 1 done.\n"); break; } } if (i == 4) - DRM_ERROR("FDI train 1 fail!\n"); + DRM_DEBUG_KMS("FDI train 1 fail!\n"); /* Train 2 */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_tx_reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; if (IS_GEN6(dev)) { @@ -1851,10 +1815,9 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) /* SNB-B */ temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; } - I915_WRITE(reg, temp); + I915_WRITE(fdi_tx_reg, temp); - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_rx_reg); if (HAS_PCH_CPT(dev)) { temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; temp |= FDI_LINK_TRAIN_PATTERN_2_CPT; @@ -1862,600 +1825,446 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_2; } - I915_WRITE(reg, temp); - - POSTING_READ(reg); + I915_WRITE(fdi_rx_reg, temp); udelay(150); for (i = 0; i < 4; i++ ) { - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_tx_reg); temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; temp |= snb_b_fdi_train_param[i]; - I915_WRITE(reg, temp); - - POSTING_READ(reg); + I915_WRITE(fdi_tx_reg, temp); udelay(500); - reg = FDI_RX_IIR(pipe); - temp = I915_READ(reg); + temp = I915_READ(fdi_rx_iir_reg); DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); if (temp & FDI_RX_SYMBOL_LOCK) { - I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_SYMBOL_LOCK); DRM_DEBUG_KMS("FDI train 2 done.\n"); break; } } if (i == 4) - DRM_ERROR("FDI train 2 fail!\n"); + DRM_DEBUG_KMS("FDI train 2 fail!\n"); DRM_DEBUG_KMS("FDI train done.\n"); } -static void ironlake_fdi_enable(struct drm_crtc *crtc) +static void ironlake_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; - u32 reg, temp; - - /* Write the TU size bits so error detection works */ - I915_WRITE(FDI_RX_TUSIZE1(pipe), - I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK); - - /* 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); - - POSTING_READ(reg); - udelay(200); - - /* Switch from Rawclk to PCDclk */ - temp = I915_READ(reg); - I915_WRITE(reg, temp | FDI_PCDCLK); - - POSTING_READ(reg); - udelay(200); + 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; - /* 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); + /* 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); - POSTING_READ(reg); - udelay(100); - } -} + 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); + } + } -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)); -} + if (!HAS_eDP) { -/* - * 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; + /* 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); - if (IS_GEN2(dev)) - /* Can't break the hang on i8xx */ - return; + /* 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); - tmp = I915_READ(PRB0_CTL); - if (tmp & RING_WAIT) { - I915_WRITE(PRB0_CTL, tmp); - POSTING_READ(PRB0_CTL); - } -} + /* 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); + } + } -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; + /* 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); + } - if (crtc->fb == NULL) - return; + /* 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); + } - 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); -} + /* 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)); + } -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; + 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 (intel_crtc->active) - 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); - intel_crtc->active = true; - intel_update_watermarks(dev); + 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); + } - 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); - } + /* 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); - ironlake_fdi_enable(crtc); + /* wait one idle pattern time */ + udelay(100); - /* 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); - } + /* 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; + } - /* 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); - } + I915_WRITE(trans_dp_ctl, reg); + POSTING_READ(trans_dp_ctl); + } - /* 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); - } + /* 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); - 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); - } + if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100, 1)) + DRM_ERROR("failed to enable transcoder\n"); + } - /* 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))); + intel_crtc_load_lut(crtc); - 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))); + intel_update_fbc(crtc, &crtc->mode); + break; - /* 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); + case DRM_MODE_DPMS_OFF: + DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane); - 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; + 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); } - I915_WRITE(reg, temp); - } - - /* 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"); + if (dev_priv->cfb_plane == plane && + dev_priv->display.disable_fbc) + dev_priv->display.disable_fbc(dev); - intel_crtc_load_lut(crtc); - intel_update_fbc(dev); - intel_crtc_update_cursor(crtc, true); -} + /* 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); -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; + /* 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); - if (!intel_crtc->active) - return; + udelay(100); - intel_crtc_wait_for_pending_flips(crtc); - drm_vblank_off(dev, pipe); - intel_crtc_update_cursor(crtc, false); + /* Disable PF */ + I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0); + I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0); - /* 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); - } + /* 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); - if (dev_priv->cfb_plane == plane && - dev_priv->display.disable_fbc) - dev_priv->display.disable_fbc(dev); + 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); - /* 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); + udelay(100); - 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 { + /* still set train pattern 1 */ + temp = I915_READ(fdi_tx_reg); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; - } - /* 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); + I915_WRITE(fdi_tx_reg, temp); + POSTING_READ(fdi_tx_reg); - POSTING_READ(reg); - udelay(100); + 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); - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - temp = I915_READ(PCH_LVDS); - if (temp & LVDS_PORT_EN) { + udelay(100); + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + temp = I915_READ(PCH_LVDS); I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN); - POSTING_READ(PCH_LVDS); + I915_READ(PCH_LVDS); udelay(100); } - } - /* 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"); - } + /* disable PCH transcoder */ + temp = I915_READ(transconf_reg); + if ((temp & TRANS_ENABLE) != 0) { + I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); - 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); - - /* 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); - } - - /* disable PCH DPLL */ - reg = PCH_DPLL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE); - - /* Switch from PCDclk to Rawclk */ - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp & ~FDI_PCDCLK); + /* 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"); + } - /* Disable CPU FDI TX PLL */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE); + 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); - POSTING_READ(reg); - udelay(100); + 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; - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp & ~FDI_RX_PLL_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); - /* Wait for the clocks to turn off. */ - POSTING_READ(reg); - udelay(100); + /* 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); - 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; + /* 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); - /* 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; + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_RX_PLL_ENABLE; + I915_WRITE(fdi_rx_reg, temp); + I915_READ(fdi_rx_reg); - case DRM_MODE_DPMS_OFF: - DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane); - ironlake_crtc_disable(crtc); + /* Wait for the clocks to turn off. */ + udelay(100); break; } } -static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) -{ - 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; - - /* Next, disable display pipes */ - reg = PIPECONF(pipe); - temp = I915_READ(reg); - if (temp & PIPECONF_ENABLE) { - I915_WRITE(reg, temp & ~PIPECONF_ENABLE); - - /* Wait for the pipe to turn off */ - POSTING_READ(reg); - intel_wait_for_pipe_off(dev, pipe); - } +static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) +{ + struct intel_overlay *overlay; + int ret; - reg = DPLL(pipe); - temp = I915_READ(reg); - if (temp & DPLL_VCO_ENABLE) { - I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE); + 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; - /* Wait for the clocks to turn off. */ - POSTING_READ(reg); - udelay(150); + 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); } + /* Let userspace switch the overlay on again. In most cases userspace + * has to recompute where to put it anyway. */ -done: - intel_crtc->active = false; - intel_update_fbc(dev); - intel_update_watermarks(dev); - intel_clear_scanline_wait(dev); + return; } 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. */ @@ -2463,10 +2272,88 @@ 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: - i9xx_crtc_enable(crtc); - break; + /* 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; case DRM_MODE_DPMS_OFF: - i9xx_crtc_disable(crtc); + /* 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); break; } } @@ -2487,9 +2374,26 @@ 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; @@ -2514,46 +2418,16 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) } } -static void intel_crtc_disable(struct drm_crtc *crtc) +static void intel_crtc_prepare (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); - } } -/* 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) -{ - 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) +static void intel_crtc_commit (struct drm_crtc *crtc) { - ironlake_crtc_disable(crtc); -} - -static void ironlake_crtc_commit(struct drm_crtc *crtc) -{ - ironlake_crtc_enable(crtc); + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); } void intel_encoder_prepare (struct drm_encoder *encoder) @@ -2572,7 +2446,13 @@ void intel_encoder_commit (struct drm_encoder *encoder) void intel_encoder_destroy(struct drm_encoder *encoder) { - struct intel_encoder *intel_encoder = to_intel_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); drm_encoder_cleanup(encoder); kfree(intel_encoder); @@ -2663,6 +2543,33 @@ 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; @@ -2981,7 +2888,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; } @@ -2998,7 +2905,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; } @@ -3013,8 +2920,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; } @@ -3029,14 +2936,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; @@ -3148,13 +3055,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) @@ -3166,7 +3073,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", @@ -3204,7 +3111,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; @@ -3213,11 +3120,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; @@ -3225,11 +3132,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_CRESTLINE(dev)) + if (IS_I965GM(dev)) I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); } else { /* Turn off self refresh if both pipes are enabled */ - if (IS_CRESTLINE(dev)) + if (IS_I965GM(dev)) I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN); } @@ -3259,9 +3166,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_CRESTLINE(dev) || IS_I945GM(dev)) + if (IS_I965GM(dev) || IS_I945GM(dev)) planea_params = planeb_params = i945_wm_info; - else if (!IS_GEN2(dev)) + else if (IS_I9XX(dev)) planea_params = planeb_params = i915_wm_info; else planea_params = planeb_params = i855_wm_info; @@ -3296,7 +3203,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; @@ -3321,7 +3228,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); @@ -3355,130 +3262,146 @@ 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 bool ironlake_compute_wm0(struct drm_device *dev, - int pipe, - int *plane_wm, - int *cursor_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 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; - crtc = intel_get_crtc_for_pipe(dev, pipe); - if (crtc->fb == NULL || !crtc->enabled) - return false; + /* 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; + } + } - 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; + /* 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; - return true; -} + if (planea_wm > (int)ironlake_display_wm_info.max_wm) + planea_wm = ironlake_display_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++; - } + /* Use the large buffer method to calculate cursor watermark */ + line_time_us = (planea_htotal * 1000) / planea_clock; - 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++; + /* 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; + + /* Use the large buffer method to calculate cursor watermark */ + line_time_us = (planeb_htotal * 1000) / planeb_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 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; + + 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); } /* * Calculate and update the self-refresh watermark only when one * display plane is used. */ - 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; + if (!planea_clock || !planeb_clock) { + /* 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; - line_size = sr_hdisplay * pixel_size; + / 1000; - /* 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; - - entries = DIV_ROUND_UP(min(small, large), - ironlake_display_srwm_info.cacheline_size); - - plane_fbc = entries * 64; - plane_fbc = DIV_ROUND_UP(plane_fbc, line_size); - - 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; + /* 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; /* 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; + 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; /* 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 */ -} + 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; + + I915_WRITE(WM1_LP_ILK, reg_value); + DRM_DEBUG_KMS("self-refresh watermark: display plane %d " + "cursor %d\n", sr_wm, cursor_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); + } +} /** * intel_update_watermarks - update FIFO watermark values based on current modes * @@ -3510,7 +3433,7 @@ static void ironlake_update_wm(struct drm_device *dev, * * 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; @@ -3526,15 +3449,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->active) { + if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) { 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; @@ -3565,35 +3488,62 @@ 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; - u32 fp_reg, dpll_reg; + 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; int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; - u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf; + u32 dpll = 0, 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 intel_encoder *encoder; + struct drm_encoder *encoder; const intel_limit_t *limit; int ret; struct fdi_m_n m_n = {0}; - u32 reg, temp; + 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; int target_clock; drm_vblank_pre_modeset(dev, pipe); - list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { - if (encoder->base.crtc != crtc) + list_for_each_entry(encoder, &mode_config->encoder_list, head) { + struct intel_encoder *intel_encoder; + + if (encoder->crtc != crtc) continue; - switch (encoder->type) { + intel_encoder = enc_to_intel_encoder(encoder); + switch (intel_encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; break; case INTEL_OUTPUT_SDVO: case INTEL_OUTPUT_HDMI: is_sdvo = true; - if (encoder->needs_tv_clock) + if (intel_encoder->needs_tv_clock) is_tv = true; break; case INTEL_OUTPUT_DVO: @@ -3609,7 +3559,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, is_dp = true; break; case INTEL_OUTPUT_EDP: - has_edp_encoder = encoder; + has_edp_encoder = intel_encoder; break; } @@ -3619,14 +3569,15 @@ 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_GEN2(dev)) { + refclk / 1000); + } else if (IS_I9XX(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 @@ -3642,13 +3593,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, true); + intel_crtc_update_cursor(crtc); 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 @@ -3657,7 +3608,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; } } @@ -3665,14 +3616,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; @@ -3697,28 +3648,21 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, target_clock = mode->clock; else target_clock = adjusted_mode->clock; - - /* 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; + link_bw = 270000; } /* determine panel color depth */ - temp = I915_READ(PIPECONF(pipe)); + temp = I915_READ(pipeconf_reg); 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 ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) + if ((lvds_reg & 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; @@ -3734,7 +3678,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } } else temp |= PIPE_8BPC; - I915_WRITE(PIPECONF(pipe), temp); + I915_WRITE(pipeconf_reg, temp); + I915_READ(pipeconf_reg); switch (temp & PIPE_BPC_MASK) { case PIPE_8BPC: @@ -3779,27 +3724,33 @@ 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); + 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); + 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); } } @@ -3815,24 +3766,21 @@ 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_GEN2(dev)) { + if (IS_I9XX(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; @@ -3862,7 +3810,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; break; } - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); } else { if (is_lvds) { @@ -3889,7 +3837,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= PLL_REF_INPUT_DREFCLK; /* setup pipeconf */ - pipeconf = I915_READ(PIPECONF(pipe)); + pipeconf = I915_READ(pipeconf_reg); /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; @@ -3903,7 +3851,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dspcntr |= DISPPLANE_SEL_PIPE_B; } - if (pipe == 0 && INTEL_INFO(dev)->gen < 4) { + if (pipe == 0 && !IS_I965G(dev)) { /* Enable pixel doubling when the dot clock is > 90% of the (display) * core speed. * @@ -3912,104 +3860,107 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, */ if (mode->clock > dev_priv->display.get_display_clock_speed(dev) * 9 / 10) - pipeconf |= PIPECONF_DOUBLE_WIDE; + pipeconf |= PIPEACONF_DOUBLE_WIDE; else - pipeconf &= ~PIPECONF_DOUBLE_WIDE; + pipeconf &= ~PIPEACONF_DOUBLE_WIDE; } dspcntr |= DISPLAY_PLANE_ENABLE; - pipeconf |= PIPECONF_ENABLE; + pipeconf |= PIPEACONF_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_FP0(pipe); - dpll_reg = PCH_DPLL(pipe); - } else { - fp_reg = FP0(pipe); - dpll_reg = DPLL(pipe); + fp_reg = pch_fp_reg; + dpll_reg = pch_dpll_reg; } if (!has_edp_encoder) { I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); - - POSTING_READ(dpll_reg); + I915_READ(dpll_reg); udelay(150); } /* enable transcoder DPLL */ if (HAS_PCH_CPT(dev)) { temp = I915_READ(PCH_DPLL_SEL); - if (pipe == 0) - temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL; + if (trans_dpll_sel == 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); - - POSTING_READ(PCH_DPLL_SEL); + I915_READ(PCH_DPLL_SEL); udelay(150); } + if (HAS_PCH_SPLIT(dev)) { + pipeconf &= ~PIPE_ENABLE_DITHER; + pipeconf &= ~PIPE_DITHER_TYPE_MASK; + } + /* The LVDS pin pair needs to be on before the DPLLs are enabled. * This is an exception to the general rule that mode_set doesn't turn * things on. */ if (is_lvds) { - reg = LVDS; + u32 lvds; + if (HAS_PCH_SPLIT(dev)) - reg = PCH_LVDS; + lvds_reg = PCH_LVDS; - temp = I915_READ(reg); - temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; + lvds = I915_READ(lvds_reg); + lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; if (pipe == 1) { if (HAS_PCH_CPT(dev)) - temp |= PORT_TRANS_B_SEL_CPT; + lvds |= PORT_TRANS_B_SEL_CPT; else - temp |= LVDS_PIPEB_SELECT; + lvds |= LVDS_PIPEB_SELECT; } else { if (HAS_PCH_CPT(dev)) - temp &= ~PORT_TRANS_SEL_MASK; + lvds &= ~PORT_TRANS_SEL_MASK; else - temp &= ~LVDS_PIPEB_SELECT; + lvds &= ~LVDS_PIPEB_SELECT; } /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; + lvds |= 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) - temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; else - temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + lvds &= ~(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 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; + /* 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; + } + } } + 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)) { @@ -4030,32 +3981,26 @@ 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 (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - temp = 0; + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { if (is_sdvo) { - 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); + 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); } 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; @@ -4065,6 +4010,7 @@ 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; @@ -4083,72 +4029,58 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } else pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */ - I915_WRITE(HTOTAL(pipe), - (adjusted_mode->crtc_hdisplay - 1) | + I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16)); - I915_WRITE(HBLANK(pipe), - (adjusted_mode->crtc_hblank_start - 1) | + I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16)); - I915_WRITE(HSYNC(pipe), - (adjusted_mode->crtc_hsync_start - 1) | + I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16)); - - I915_WRITE(VTOTAL(pipe), - (adjusted_mode->crtc_vdisplay - 1) | + I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16)); - I915_WRITE(VBLANK(pipe), - (adjusted_mode->crtc_vblank_start - 1) | + I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16)); - I915_WRITE(VSYNC(pipe), - (adjusted_mode->crtc_vsync_start - 1) | + I915_WRITE(vsync_reg, (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(plane), - ((mode->vdisplay - 1) << 16) | - (mode->hdisplay - 1)); - I915_WRITE(DSPPOS(plane), 0); + I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | + (mode->hdisplay - 1)); + I915_WRITE(dsppos_reg, 0); } - I915_WRITE(PIPESRC(pipe), - ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); + I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); if (HAS_PCH_SPLIT(dev)) { - 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); + 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); if (has_edp_encoder) { ironlake_set_pll_edp(crtc, adjusted_mode->clock); } else { /* enable FDI RX PLL too */ - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE); - - POSTING_READ(reg); + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); + I915_READ(fdi_rx_reg); udelay(200); /* enable FDI TX PLL too */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE); + temp = I915_READ(fdi_tx_reg); + I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); + I915_READ(fdi_tx_reg); /* enable FDI RX PCDCLK */ - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp | FDI_PCDCLK); - - POSTING_READ(reg); + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK); + I915_READ(fdi_rx_reg); udelay(200); } } - I915_WRITE(PIPECONF(pipe), pipeconf); - POSTING_READ(PIPECONF(pipe)); + I915_WRITE(pipeconf_reg, pipeconf); + I915_READ(pipeconf_reg); intel_wait_for_vblank(dev, pipe); @@ -4158,8 +4090,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING); } - I915_WRITE(DSPCNTR(plane), dspcntr); + I915_WRITE(dspcntr_reg, dspcntr); + /* Flush the plane changes */ ret = intel_pipe_set_base(crtc, x, y, old_fb); intel_update_watermarks(dev); @@ -4252,8 +4185,7 @@ 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, - bool on) +static void intel_crtc_update_cursor(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4266,7 +4198,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, pos = 0; - if (on && crtc->enabled && crtc->fb) { + if (intel_crtc->cursor_on && crtc->fb) { base = intel_crtc->cursor_addr; if (x > (int) crtc->fb->width) base = 0; @@ -4378,7 +4310,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, addr = obj_priv->phys_obj->handle->busaddr; } - if (IS_GEN2(dev)) + if (!IS_I9XX(dev)) I915_WRITE(CURSIZE, (height << 12) | width); finish: @@ -4398,7 +4330,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, true); + intel_crtc_update_cursor(crtc); return 0; fail_unpin: @@ -4417,7 +4349,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, true); + intel_crtc_update_cursor(crtc); return 0; } @@ -4486,7 +4418,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->base; + struct drm_encoder *encoder = &intel_encoder->enc; struct drm_crtc *crtc = NULL; struct drm_device *dev = encoder->dev; struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; @@ -4567,7 +4499,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->base; + struct drm_encoder *encoder = &intel_encoder->enc; struct drm_device *dev = encoder->dev; struct drm_crtc *crtc = encoder->crtc; struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; @@ -4613,7 +4545,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_GEN2(dev)) { + if (IS_I9XX(dev)) { if (IS_PINEVIEW(dev)) clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >> DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW); @@ -4717,6 +4649,8 @@ 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); @@ -4730,12 +4664,14 @@ 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) +static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule) { struct drm_device *dev = crtc->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -4770,8 +4706,9 @@ static void intel_increase_pllclock(struct drm_crtc *crtc) } /* Schedule downclock */ - mod_timer(&intel_crtc->idle_timer, jiffies + - msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); + if (schedule) + mod_timer(&intel_crtc->idle_timer, jiffies + + msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); } static void intel_decrease_pllclock(struct drm_crtc *crtc) @@ -4907,7 +4844,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); + intel_increase_pllclock(crtc, true); intel_crtc->busy = true; } else { /* Busy -> busy, put off timer */ @@ -4921,22 +4858,8 @@ 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); } @@ -4996,7 +4919,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)) - wake_up(&dev_priv->pending_flip_queue); + DRM_WAKEUP(&dev_priv->pending_flip_queue); schedule_work(&work->work); trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); @@ -5077,7 +5000,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, true); + ret = intel_pin_and_fence_fb_obj(dev, obj); if (ret) goto cleanup_work; @@ -5086,6 +5009,9 @@ 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) @@ -5098,16 +5024,14 @@ 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(MI_NOOP); + OUT_RING(0); ADVANCE_LP_RING(); } @@ -5188,14 +5112,15 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, return ret; } -static struct drm_crtc_helper_funcs intel_helper_funcs = { +static const 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 = { @@ -5221,6 +5146,8 @@ 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; @@ -5230,9 +5157,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_GEN3(dev)) { + if (IS_MOBILE(dev) && (IS_I9XX(dev) && !IS_I965G(dev))) { DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); - intel_crtc->plane = !pipe; + intel_crtc->plane = ((pipe == 0) ? 1 : 0); } BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || @@ -5242,16 +5169,6 @@ 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; @@ -5287,25 +5204,38 @@ 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, base.head) { - if (type_mask & encoder->clone_mask) + 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) 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 intel_encoder *encoder; + struct drm_encoder *encoder; bool dpd_is_edp = false; if (IS_MOBILE(dev) && !IS_I830(dev)) @@ -5394,10 +5324,12 @@ 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, base.head) { - encoder->base.possible_crtcs = encoder->crtc_mask; - encoder->base.possible_clones = - intel_encoder_clones(dev, encoder->clone_mask); + 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); } } @@ -5431,25 +5363,8 @@ 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); @@ -5558,10 +5473,6 @@ 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); @@ -5604,7 +5515,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, 1, 0)) DRM_ERROR("stuck trying to change perf mode\n"); msleep(1); @@ -5803,20 +5714,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_CRESTLINE(dev)) { + } else if (IS_I965GM(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_BROADWATER(dev)) { + } else if (IS_I965G(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_GEN3(dev)) { + } else if (IS_I9XX(dev)) { u32 dstate = I915_READ(D_STATE); dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING | @@ -5898,7 +5809,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_CRESTLINE(dev)) { + } else if (IS_I965GM(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; @@ -5958,9 +5869,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_GEN4(dev)) + else if (IS_I965G(dev)) dev_priv->display.update_wm = i965_update_wm; - else if (IS_GEN3(dev)) { + else if (IS_I9XX(dev)) { dev_priv->display.update_wm = i9xx_update_wm; dev_priv->display.get_fifo_size = i9xx_get_fifo_size; } else if (IS_I85X(dev)) { @@ -6074,24 +5985,24 @@ void intel_modeset_init(struct drm_device *dev) intel_init_display(dev); - if (IS_GEN2(dev)) { - dev->mode_config.max_width = 2048; - dev->mode_config.max_height = 2048; - } else if (IS_GEN3(dev)) { + if (IS_I965G(dev)) { + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; + } else if (IS_I9XX(dev)) { dev->mode_config.max_width = 4096; dev->mode_config.max_height = 4096; } else { - dev->mode_config.max_width = 8192; - dev->mode_config.max_height = 8192; + dev->mode_config.max_width = 2048; + dev->mode_config.max_height = 2048; } /* set memory base */ - if (IS_GEN2(dev)) - dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); - else + if (IS_I9XX(dev)) dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2); + else + dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); - if (IS_MOBILE(dev) || !IS_GEN2(dev)) + if (IS_MOBILE(dev) || IS_I9XX(dev)) dev_priv->num_pipe = 2; else dev_priv->num_pipe = 1; @@ -6127,18 +6038,23 @@ void intel_modeset_cleanup(struct drm_device *dev) struct drm_crtc *crtc; struct intel_crtc *intel_crtc; - drm_kms_helper_poll_fini(dev); mutex_lock(&dev->struct_mutex); + drm_kms_helper_poll_fini(dev); + intel_fbdev_fini(dev); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { /* Skip inactive CRTCs */ if (!crtc->fb) continue; intel_crtc = to_intel_crtc(crtc); - intel_increase_pllclock(crtc); + intel_increase_pllclock(crtc, false); + del_timer_sync(&intel_crtc->idle_timer); } + del_timer_sync(&dev_priv->idle_timer); + if (dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); @@ -6167,36 +6083,33 @@ 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_best_encoder(struct drm_connector *connector) +struct drm_encoder *intel_attached_encoder (struct drm_connector *connector) { - return &intel_attached_encoder(connector)->base; -} + struct drm_mode_object *obj; + struct drm_encoder *encoder; + int i; -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); + 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; + + encoder = obj_to_encoder(obj); + return encoder; + } + return NULL; } /* diff --git a/trunk/drivers/gpu/drm/i915/intel_dp.c b/trunk/drivers/gpu/drm/i915/intel_dp.c index 152d94507b79..1a51ee07de3e 100644 --- a/trunk/drivers/gpu/drm/i915/intel_dp.c +++ b/trunk/drivers/gpu/drm/i915/intel_dp.c @@ -58,23 +58,14 @@ 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(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); + return container_of(enc_to_intel_encoder(encoder), struct intel_dp, base); } -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_train(struct intel_dp *intel_dp); static void intel_dp_link_down(struct intel_dp *intel_dp); void @@ -139,7 +130,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 + 7) / 8; + return (pixel_clock * dev_priv->edp_bpp) / 8; else return pixel_clock * 3; } @@ -154,7 +145,8 @@ static int intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct intel_dp *intel_dp = intel_attached_dp(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 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)); @@ -241,7 +233,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.base.dev; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t ch_ctl = output_reg + 0x10; uint32_t ch_data = ch_ctl + 4; @@ -254,11 +246,8 @@ 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) && !IS_PCH_eDP(intel_dp)) { + if (IS_eDP(intel_dp)) { if (IS_GEN6(dev)) aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */ else @@ -653,7 +642,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; } } @@ -709,7 +698,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.base.crtc; + struct drm_crtc *crtc = intel_dp->base.enc.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); intel_dp->DP = (DP_VOLTAGE_0_4 | @@ -765,14 +754,13 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, } } -/* Returns true if the panel was already on when called */ -static bool ironlake_edp_panel_on (struct drm_device *dev) +static void 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 true; + return; pp = I915_READ(PCH_PP_CONTROL); @@ -781,24 +769,17 @@ static bool ironlake_edp_panel_on (struct drm_device *dev) I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); - pp |= POWER_TARGET_ON; + pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); - /* 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)) + if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10)) DRM_ERROR("panel on wait timed out: 0x%08x\n", I915_READ(PCH_PP_STATUS)); - pp &= ~(PANEL_UNLOCK_REGS); + pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); 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) @@ -816,43 +797,14 @@ 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)) + if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10)) 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 |= PANEL_POWER_RESET; /* restore panel reset bit */ + pp |= EDP_FORCE_VDD | 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) @@ -898,7 +850,6 @@ 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); } @@ -909,10 +860,9 @@ 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) || IS_PCH_eDP(intel_dp)) { - ironlake_edp_panel_off(dev); + if (IS_eDP(intel_dp)) { ironlake_edp_backlight_off(dev); - ironlake_edp_panel_vdd_on(dev); + ironlake_edp_panel_on(dev); ironlake_edp_pll_on(encoder); } if (dp_reg & DP_PORT_EN) @@ -923,17 +873,14 @@ 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); - 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 (!(dp_reg & DP_PORT_EN)) { + intel_dp_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 @@ -955,10 +902,9 @@ 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_complete_link_train(intel_dp); + intel_dp_link_train(intel_dp); if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) ironlake_edp_backlight_on(dev); } @@ -971,13 +917,14 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) * link status information */ static bool -intel_dp_get_link_status(struct intel_dp *intel_dp) +intel_dp_get_link_status(struct intel_dp *intel_dp, + uint8_t link_status[DP_LINK_STATUS_SIZE]) { int ret; ret = intel_dp_aux_native_read(intel_dp, DP_LANE0_1_STATUS, - intel_dp->link_status, DP_LINK_STATUS_SIZE); + link_status, DP_LINK_STATUS_SIZE); if (ret != DP_LINK_STATUS_SIZE) return false; return true; @@ -1052,15 +999,18 @@ intel_dp_pre_emphasis_max(uint8_t voltage_swing) } static void -intel_get_adjust_train(struct intel_dp *intel_dp) +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]) { uint8_t v = 0; uint8_t p = 0; int 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); + 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); if (this_v > v) v = this_v; @@ -1075,7 +1025,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++) - intel_dp->train_set[lane] = v | p; + train_set[lane] = v | p; } static uint32_t @@ -1166,18 +1116,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(struct intel_dp *intel_dp) +intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) { uint8_t lane_align; uint8_t lane_status; int lane; - lane_align = intel_dp_link_status(intel_dp->link_status, + lane_align = intel_dp_link_status(link_status, DP_LANE_ALIGN_STATUS_UPDATED); if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) return false; - for (lane = 0; lane < intel_dp->lane_count; lane++) { - lane_status = intel_get_lane_status(intel_dp->link_status, lane); + for (lane = 0; lane < lane_count; lane++) { + lane_status = intel_get_lane_status(link_status, lane); if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS) return false; } @@ -1187,47 +1137,48 @@ intel_channel_eq_ok(struct intel_dp *intel_dp) static bool intel_dp_set_link_train(struct intel_dp *intel_dp, uint32_t dp_reg_value, - uint8_t dp_train_pat) + uint8_t dp_train_pat, + uint8_t train_set[4], + bool first) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp->base.enc.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, - intel_dp->train_set, 4); + DP_TRAINING_LANE0_SET, train_set, 4); if (ret != 4) return false; return true; } -/* Enable corresponding port and start training pattern 1 */ static void -intel_dp_start_link_train(struct intel_dp *intel_dp) +intel_dp_link_train(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc); + uint8_t train_set[4]; + uint8_t link_status[DP_LINK_STATUS_SIZE]; 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, @@ -1238,18 +1189,18 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) DP &= ~DP_LINK_TRAIN_MASK_CPT; else DP &= ~DP_LINK_TRAIN_MASK; - memset(intel_dp->train_set, 0, 4); + memset(train_set, 0, 4); voltage = 0xff; tries = 0; clock_recovery = false; for (;;) { - /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ + /* Use 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(intel_dp->train_set[0]); + signal_levels = intel_gen6_edp_signal_levels(train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count); + signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } @@ -1259,64 +1210,52 @@ intel_dp_start_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)) + DP_TRAINING_PATTERN_1, train_set, first)) break; + first = false; /* Set training pattern 1 */ udelay(100); - if (!intel_dp_get_link_status(intel_dp)) + if (!intel_dp_get_link_status(intel_dp, link_status)) break; - if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) { + if (intel_clock_recovery_ok(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 ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) + if ((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 ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { + if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { ++tries; if (tries == 5) break; } else tries = 0; - voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; + voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; - /* Compute new intel_dp->train_set as requested by target */ - intel_get_adjust_train(intel_dp); + /* Compute new train_set as requested by target */ + intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set); } - 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 intel_dp->train_set[0] to set the voltage and pre emphasis values */ + /* Use 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(intel_dp->train_set[0]); + signal_levels = intel_gen6_edp_signal_levels(train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count); + signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } @@ -1327,14 +1266,15 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) /* channel eq pattern */ if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_2)) + DP_TRAINING_PATTERN_2, train_set, + false)) break; udelay(400); - if (!intel_dp_get_link_status(intel_dp)) + if (!intel_dp_get_link_status(intel_dp, link_status)) break; - if (intel_channel_eq_ok(intel_dp)) { + if (intel_channel_eq_ok(link_status, intel_dp->lane_count)) { channel_eq = true; break; } @@ -1343,8 +1283,8 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) if (tries > 5) break; - /* Compute new intel_dp->train_set as requested by target */ - intel_get_adjust_train(intel_dp); + /* Compute new train_set as requested by target */ + intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set); ++tries; } @@ -1362,7 +1302,7 @@ intel_dp_complete_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.base.dev; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t DP = intel_dp->DP; @@ -1378,13 +1318,14 @@ 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); - msleep(17); + udelay(17000); if (IS_eDP(intel_dp)) DP |= DP_LINK_TRAIN_OFF; @@ -1404,29 +1345,27 @@ intel_dp_link_down(struct intel_dp *intel_dp) static void intel_dp_check_link_status(struct intel_dp *intel_dp) { - if (!intel_dp->base.base.crtc) + uint8_t link_status[DP_LINK_STATUS_SIZE]; + + if (!intel_dp->base.enc.crtc) return; - if (!intel_dp_get_link_status(intel_dp)) { + if (!intel_dp_get_link_status(intel_dp, link_status)) { intel_dp_link_down(intel_dp); return; } - if (!intel_channel_eq_ok(intel_dp)) { - intel_dp_start_link_train(intel_dp); - intel_dp_complete_link_train(intel_dp); - } + if (!intel_channel_eq_ok(link_status, intel_dp->lane_count)) + intel_dp_link_train(intel_dp); } static enum drm_connector_status ironlake_dp_detect(struct drm_connector *connector) { - struct intel_dp *intel_dp = intel_attached_dp(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 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, @@ -1437,8 +1376,6 @@ 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; } @@ -1451,8 +1388,9 @@ ironlake_dp_detect(struct drm_connector *connector) static enum drm_connector_status intel_dp_detect(struct drm_connector *connector, bool force) { - struct intel_dp *intel_dp = intel_attached_dp(connector); - struct drm_device *dev = intel_dp->base.base.dev; + 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 drm_i915_private *dev_priv = dev->dev_private; uint32_t temp, bit; enum drm_connector_status status; @@ -1494,15 +1432,16 @@ intel_dp_detect(struct drm_connector *connector, bool force) static int intel_dp_get_modes(struct drm_connector *connector) { - struct intel_dp *intel_dp = intel_attached_dp(connector); - struct drm_device *dev = intel_dp->base.base.dev; + 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 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->adapter); + ret = intel_ddc_get_modes(connector, intel_dp->base.ddc_bus); if (ret) { if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && !dev_priv->panel_fixed_mode) { @@ -1540,15 +1479,6 @@ 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, @@ -1567,14 +1497,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_best_encoder, + .best_encoder = intel_attached_encoder, }; static const struct drm_encoder_funcs intel_dp_enc_funcs = { - .destroy = intel_dp_encoder_destroy, + .destroy = intel_encoder_destroy, }; -static void +void intel_dp_hot_plug(struct intel_encoder *intel_encoder) { struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); @@ -1683,11 +1613,12 @@ 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->base, &intel_dp_enc_funcs, + drm_encoder_init(dev, &intel_encoder->enc, &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS); - drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs); + drm_encoder_helper_add(&intel_encoder->enc, &intel_dp_helper_funcs); - intel_connector_attach_encoder(intel_connector, intel_encoder); + drm_mode_connector_attach_encoder(&intel_connector->base, + &intel_encoder->enc); drm_sysfs_connector_add(connector); /* Set up the DDC bus. */ @@ -1717,6 +1648,7 @@ 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)) { diff --git a/trunk/drivers/gpu/drm/i915/intel_drv.h b/trunk/drivers/gpu/drm/i915/intel_drv.h index 40e99bf27ff7..ad312ca6b3e5 100644 --- a/trunk/drivers/gpu/drm/i915/intel_drv.h +++ b/trunk/drivers/gpu/drm/i915/intel_drv.h @@ -26,12 +26,14 @@ #define __INTEL_DRV_H__ #include +#include +#include #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)) { \ @@ -39,24 +41,11 @@ ret__ = -ETIMEDOUT; \ break; \ } \ - if (W && !in_dbg_master()) msleep(W); \ + if (W) 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 */ @@ -107,39 +96,24 @@ #define INTEL_DVO_CHIP_TMDS 2 #define INTEL_DVO_CHIP_TVOUT 4 -/* 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_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; +}; 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 base; + struct drm_encoder enc; 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 *); @@ -149,7 +123,32 @@ struct intel_encoder { struct intel_connector { struct drm_connector base; - struct intel_encoder *encoder; +}; + +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_crtc { @@ -158,7 +157,6 @@ 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; @@ -170,21 +168,14 @@ struct intel_crtc { uint32_t cursor_addr; int16_t cursor_x, cursor_y; int16_t cursor_width, cursor_height; - bool cursor_visible; + bool cursor_visible, cursor_on; }; #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 to_intel_encoder(x) container_of(x, struct intel_encoder, base) +#define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc) #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; @@ -195,8 +186,13 @@ 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, int ddc_bus); +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 void intel_crt_init(struct drm_device *dev); extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); @@ -213,37 +209,29 @@ 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); -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_encoder *intel_attached_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 void intel_wait_for_pipe_off(struct drm_device *dev, int pipe); +extern struct drm_crtc *intel_get_crtc_from_pipe(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, @@ -265,8 +253,7 @@ 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, - bool pipelined); + struct drm_gem_object *obj); extern int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, @@ -281,8 +268,9 @@ 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, - bool interruptible); +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_put_image(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int intel_overlay_attrs(struct drm_device *dev, void *data, diff --git a/trunk/drivers/gpu/drm/i915/intel_dvo.c b/trunk/drivers/gpu/drm/i915/intel_dvo.c index ea373283c93b..7c9ec1472d46 100644 --- a/trunk/drivers/gpu/drm/i915/intel_dvo.c +++ b/trunk/drivers/gpu/drm/i915/intel_dvo.c @@ -72,7 +72,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .name = "ch7017", .dvo_reg = DVOC, .slave_addr = 0x75, - .gpio = GMBUS_PORT_DPB, + .gpio = GPIOE, .dev_ops = &ch7017_ops, } }; @@ -88,13 +88,7 @@ struct intel_dvo { static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder) { - 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); + return container_of(enc_to_intel_encoder(encoder), struct intel_dvo, base); } static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) @@ -118,7 +112,8 @@ 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 intel_dvo *intel_dvo = intel_attached_dvo(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; @@ -229,22 +224,23 @@ 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 intel_dvo *intel_dvo = intel_attached_dvo(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); + return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev); } static int intel_dvo_get_modes(struct drm_connector *connector) { - struct intel_dvo *intel_dvo = intel_attached_dvo(connector); - struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); /* 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, - &dev_priv->gmbus[GMBUS_PORT_DPC].adapter); + intel_ddc_get_modes(connector, intel_dvo->base.ddc_bus); if (!list_empty(&connector->probed_modes)) return 1; @@ -285,7 +281,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_best_encoder, + .best_encoder = intel_attached_encoder, }; static void intel_dvo_enc_destroy(struct drm_encoder *encoder) @@ -315,7 +311,8 @@ 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 intel_dvo *intel_dvo = intel_attached_dvo(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg); struct drm_display_mode *mode = NULL; @@ -326,7 +323,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_for_pipe(dev, pipe); + crtc = intel_get_crtc_from_pipe(dev, pipe); if (crtc) { mode = intel_crtc_mode_get(dev, crtc); if (mode) { @@ -344,10 +341,11 @@ 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; @@ -362,14 +360,16 @@ void intel_dvo_init(struct drm_device *dev) } intel_encoder = &intel_dvo->base; - drm_encoder_init(dev, &intel_encoder->base, - &intel_dvo_enc_funcs, encoder_type); + + /* Set up the DDC bus */ + intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D"); + if (!intel_encoder->ddc_bus) + goto free_intel; /* 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,18 +379,24 @@ void intel_dvo_init(struct drm_device *dev) if (dvo->gpio != 0) gpio = dvo->gpio; else if (dvo->type == INTEL_DVO_CHIP_LVDS) - gpio = GMBUS_PORT_SSC; + gpio = GPIOB; else - gpio = GMBUS_PORT_DPB; + gpio = GPIOE; /* 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). */ - i2c = &dev_priv->gmbus[gpio].adapter; + if (i2cbus != NULL) + intel_i2c_destroy(i2cbus); + if (!(i2cbus = intel_i2c_create(dev, gpio, + gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) { + continue; + } intel_dvo->dev = *dvo; - if (!dvo->dev_ops->init(&intel_dvo->dev, i2c)) + ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus); + if (!ret) continue; intel_encoder->type = INTEL_OUTPUT_DVO; @@ -421,10 +427,13 @@ void intel_dvo_init(struct drm_device *dev) connector->interlace_allowed = false; connector->doublescan_allowed = false; - drm_encoder_helper_add(&intel_encoder->base, + drm_encoder_init(dev, &intel_encoder->enc, + &intel_dvo_enc_funcs, encoder_type); + drm_encoder_helper_add(&intel_encoder->enc, &intel_dvo_helper_funcs); - intel_connector_attach_encoder(intel_connector, intel_encoder); + drm_mode_connector_attach_encoder(&intel_connector->base, + &intel_encoder->enc); 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. @@ -442,7 +451,11 @@ void intel_dvo_init(struct drm_device *dev) return; } - drm_encoder_cleanup(&intel_encoder->base); + intel_i2c_destroy(intel_encoder->ddc_bus); + /* Didn't find a chip, so tear down. */ + if (i2cbus != NULL) + intel_i2c_destroy(i2cbus); +free_intel: kfree(intel_dvo); kfree(intel_connector); } diff --git a/trunk/drivers/gpu/drm/i915/intel_fb.c b/trunk/drivers/gpu/drm/i915/intel_fb.c index b937ccfa7bec..7bdc96256bf5 100644 --- a/trunk/drivers/gpu/drm/i915/intel_fb.c +++ b/trunk/drivers/gpu/drm/i915/intel_fb.c @@ -44,6 +44,13 @@ #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, @@ -68,7 +75,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_GEN2(dev) ? 1 : 0; + int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1; /* we don't do packed 24bpp */ if (sizes->surface_bpp == 24) @@ -93,13 +100,19 @@ static int intelfb_create(struct intel_fbdev *ifbdev, mutex_lock(&dev->struct_mutex); - /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(dev, fbo, false); + ret = intel_pin_and_fence_fb_obj(dev, fbo); 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; @@ -129,7 +142,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, goto out_unpin; } info->apertures->ranges[0].base = dev->mode_config.fb_base; - if (!IS_GEN2(dev)) + if (IS_I9XX(dev)) info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2); else info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0); @@ -206,8 +219,8 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = { .fb_probe = intel_fb_find_or_create_single, }; -static void intel_fbdev_destroy(struct drm_device *dev, - struct intel_fbdev *ifbdev) +int intel_fbdev_destroy(struct drm_device *dev, + struct intel_fbdev *ifbdev) { struct fb_info *info; struct intel_framebuffer *ifb = &ifbdev->ifb; @@ -224,10 +237,10 @@ static void intel_fbdev_destroy(struct drm_device *dev, drm_fb_helper_fini(&ifbdev->helper); drm_framebuffer_cleanup(&ifb->base); - if (ifb->obj) { - drm_gem_object_handle_unreference_unlocked(ifb->obj); - drm_gem_object_unreference_unlocked(ifb->obj); - } + if (ifb->obj) + drm_gem_object_unreference(ifb->obj); + + return 0; } int intel_fbdev_init(struct drm_device *dev) diff --git a/trunk/drivers/gpu/drm/i915/intel_hdmi.c b/trunk/drivers/gpu/drm/i915/intel_hdmi.c index 9fb9501f2d07..926934a482ec 100644 --- a/trunk/drivers/gpu/drm/i915/intel_hdmi.c +++ b/trunk/drivers/gpu/drm/i915/intel_hdmi.c @@ -40,19 +40,12 @@ 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(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); + return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base); } static void intel_hdmi_mode_set(struct drm_encoder *encoder, @@ -148,14 +141,13 @@ 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 intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); - struct drm_i915_private *dev_priv = connector->dev->dev_private; - struct edid *edid; + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct edid *edid = NULL; enum drm_connector_status status = connector_status_disconnected; intel_hdmi->has_hdmi_sink = false; - edid = drm_get_edid(connector, - &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); + edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus); if (edid) { if (edid->input & DRM_EDID_INPUT_DIGITAL) { @@ -171,15 +163,14 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) static int intel_hdmi_get_modes(struct drm_connector *connector) { - struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); - struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); /* 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, - &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); + return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus); } static void intel_hdmi_destroy(struct drm_connector *connector) @@ -207,7 +198,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_best_encoder, + .best_encoder = intel_attached_encoder, }; static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { @@ -233,9 +224,6 @@ 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); @@ -251,31 +239,39 @@ 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_hdmi->ddc_bus = GMBUS_PORT_DPB; + intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB"); dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == SDVOC) { intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); - intel_hdmi->ddc_bus = GMBUS_PORT_DPC; + intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC"); dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIB) { intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); - intel_hdmi->ddc_bus = GMBUS_PORT_DPB; + intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOE, + "HDMIB"); dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIC) { intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); - intel_hdmi->ddc_bus = GMBUS_PORT_DPC; + intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOD, + "HDMIC"); dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMID) { intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); - intel_hdmi->ddc_bus = GMBUS_PORT_DPD; + intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOF, + "HDMID"); 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_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); + 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); - intel_connector_attach_encoder(intel_connector, intel_encoder); + drm_mode_connector_attach_encoder(&intel_connector->base, + &intel_encoder->enc); drm_sysfs_connector_add(connector); /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written @@ -286,4 +282,13 @@ 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; } diff --git a/trunk/drivers/gpu/drm/i915/intel_i2c.c b/trunk/drivers/gpu/drm/i915/intel_i2c.c index 2449a74d4d80..c2649c7df14c 100644 --- a/trunk/drivers/gpu/drm/i915/intel_i2c.c +++ b/trunk/drivers/gpu/drm/i915/intel_i2c.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2006 Dave Airlie - * Copyright © 2006-2008,2010 Intel Corporation + * Copyright © 2006-2008 Intel Corporation * Jesse Barnes * * Permission is hereby granted, free of charge, to any person obtaining a @@ -24,9 +24,10 @@ * * Authors: * Eric Anholt - * Chris Wilson */ #include +#include +#include #include #include "drmP.h" #include "drm.h" @@ -34,106 +35,79 @@ #include "i915_drm.h" #include "i915_drv.h" -/* 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) +void intel_i2c_quirk_set(struct drm_device *dev, bool enable) { 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_priv->dev)) + if (!IS_PINEVIEW(dev)) return; - - val = I915_READ(DSPCLK_GATE_D); if (enable) - val |= DPCUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(DSPCLK_GATE_D, + I915_READ(DSPCLK_GATE_D) | DPCUNIT_CLOCK_GATE_DISABLE); else - val &= ~DPCUNIT_CLOCK_GATE_DISABLE; - I915_WRITE(DSPCLK_GATE_D, val); + I915_WRITE(DSPCLK_GATE_D, + I915_READ(DSPCLK_GATE_D) & (~DPCUNIT_CLOCK_GATE_DISABLE)); } -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; - - /* 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); +/* + * Intel GPIO access functions + */ - return reserved; -} +#define I2C_RISEFALL_TIME 20 static int get_clock(void *data) { - 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; + 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); } static int get_data(void *data) { - 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; + 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); } static void set_clock(void *data, int state_high) { - struct intel_gpio *gpio = data; - struct drm_i915_private *dev_priv = gpio->dev_priv; - u32 reserved = get_reserved(gpio); - u32 clock_bits; + 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); 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(gpio->reg, reserved | clock_bits); - POSTING_READ(gpio->reg); + I915_WRITE(chan->reg, reserved | clock_bits); + udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ } static void set_data(void *data, int state_high) { - struct intel_gpio *gpio = data; - struct drm_i915_private *dev_priv = gpio->dev_priv; - u32 reserved = get_reserved(gpio); - u32 data_bits; + 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); if (state_high) data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; @@ -141,312 +115,109 @@ 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(gpio->reg, reserved | data_bits); - POSTING_READ(gpio->reg); + I915_WRITE(chan->reg, reserved | data_bits); + udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ } -static struct i2c_adapter * -intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin) -{ - static const int map_pin_to_reg[] = { - 0, - GPIOB, - GPIOA, - GPIOC, - GPIOD, - GPIOE, - GPIOF, - }; - struct intel_gpio *gpio; - - 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) +/* 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) { - 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); - } - } + struct drm_i915_private *dev_priv = dev->dev_private; - 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; + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(PCH_GMBUS0, 0); + } else { + I915_WRITE(GMBUS0, 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_gmbus_setup - instantiate all Intel i2c GMBuses + * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg * @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. */ -int intel_setup_gmbus(struct drm_device *dev) +struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg, + const char *name) { - 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; - - dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS, - GFP_KERNEL); - if (dev_priv->gmbus == NULL) - return -ENOMEM; - - for (i = 0; i < GMBUS_NUM_PORTS; i++) { - struct intel_gmbus *bus = &dev_priv->gmbus[i]; - - bus->adapter.owner = THIS_MODULE; - bus->adapter.class = I2C_CLASS_DDC; - snprintf(bus->adapter.name, - I2C_NAME_SIZE, - "gmbus %s", - names[i]); - - bus->adapter.dev.parent = &dev->pdev->dev; - bus->adapter.algo_data = dev_priv; - - bus->adapter.algo = &gmbus_algorithm; - ret = i2c_add_adapter(&bus->adapter); - if (ret) - goto err; + struct intel_i2c_chan *chan; - /* 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; + chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL); + if (!chan) + goto out_free; -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; -} + 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; -void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed) -{ - struct intel_gmbus *bus = to_intel_gmbus(adapter); + intel_i2c_reset_gmbus(dev); - /* speed: - * 0x0 = 100 KHz - * 0x1 = 50 KHz - * 0x2 = 400 KHz - * 0x3 = 1000 Khz - */ - bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | (speed << 8); -} + /* 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); -void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit) -{ - struct intel_gmbus *bus = to_intel_gmbus(adapter); + return &chan->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; - } - } +out_free: + kfree(chan); + return NULL; } -void intel_teardown_gmbus(struct drm_device *dev) +/** + * 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) { - struct drm_i915_private *dev_priv = dev->dev_private; - int i; + struct intel_i2c_chan *chan; - if (dev_priv->gmbus == NULL) + if (!adapter) return; - 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; + chan = container_of(adapter, + struct intel_i2c_chan, + adapter); + i2c_del_adapter(&chan->adapter); + kfree(chan); } diff --git a/trunk/drivers/gpu/drm/i915/intel_lvds.c b/trunk/drivers/gpu/drm/i915/intel_lvds.c index f1a649990ea9..6ec39a86ed06 100644 --- a/trunk/drivers/gpu/drm/i915/intel_lvds.c +++ b/trunk/drivers/gpu/drm/i915/intel_lvds.c @@ -43,76 +43,102 @@ /* 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 *to_intel_lvds(struct drm_encoder *encoder) +static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder) { - return container_of(encoder, struct intel_lvds, base.base); + 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))); } -static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector) +/** + * Returns the maximum level of the backlight duty cycle field. + */ +static u32 intel_lvds_get_max_backlight(struct drm_device *dev) { - return container_of(intel_attached_encoder(connector), - struct intel_lvds, base); + 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; } /** * Sets the power state for the panel. */ -static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on) +static void intel_lvds_set_power(struct drm_device *dev, bool on) { - struct drm_device *dev = intel_lvds->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 ctl_reg, lvds_reg; + u32 ctl_reg, status_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); - I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); - intel_panel_set_backlight(dev, dev_priv->backlight_level); - } else { - dev_priv->backlight_level = intel_panel_get_backlight(dev); + POSTING_READ(lvds_reg); - 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, 1000, 0)) + DRM_ERROR("timed out waiting to enable LVDS pipe"); - 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; - } + intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); + } else { + intel_lvds_set_backlight(dev, 0); + + 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"); 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 intel_lvds *intel_lvds = to_intel_lvds(encoder); + struct drm_device *dev = encoder->dev; if (mode == DRM_MODE_DPMS_ON) - intel_lvds_set_power(intel_lvds, true); + intel_lvds_set_power(dev, true); else - intel_lvds_set_power(intel_lvds, false); + intel_lvds_set_power(dev, false); /* XXX: We never power down the LVDS pairs. */ } @@ -120,13 +146,16 @@ 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 intel_lvds *intel_lvds = intel_attached_lvds(connector); - struct drm_display_mode *fixed_mode = intel_lvds->fixed_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; - if (mode->hdisplay > fixed_mode->hdisplay) - return MODE_PANEL; - if (mode->vdisplay > fixed_mode->vdisplay) - return MODE_PANEL; + if (fixed_mode) { + if (mode->hdisplay > fixed_mode->hdisplay) + return MODE_PANEL; + if (mode->vdisplay > fixed_mode->vdisplay) + return MODE_PANEL; + } return MODE_OK; } @@ -194,12 +223,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 = to_intel_lvds(encoder); + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); struct drm_encoder *tmp_encoder; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; /* Should never happen!! */ - if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) { + if (!IS_I965G(dev) && intel_crtc->pipe == 0) { DRM_ERROR("Can't support LVDS on pipe A\n"); return false; } @@ -212,6 +241,9 @@ 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 @@ -219,7 +251,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(intel_lvds->fixed_mode, adjusted_mode); + intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode); if (HAS_PCH_SPLIT(dev)) { intel_pch_panel_fitting(dev, intel_lvds->fitting_mode, @@ -228,8 +260,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, } /* Make sure pre-965s set dither correctly */ - if (INTEL_INFO(dev)->gen < 4) { - if (dev_priv->lvds_dither) + if (!IS_I965G(dev)) { + if (dev_priv->panel_wants_dither || dev_priv->lvds_dither) pfit_control |= PANEL_8TO6_DITHER_ENABLE; } @@ -239,7 +271,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, goto out; /* 965+ wants fuzzy fitting */ - if (INTEL_INFO(dev)->gen >= 4) + if (IS_I965G(dev)) pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | PFIT_FILTER_FUZZY); @@ -265,7 +297,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, case DRM_MODE_SCALE_ASPECT: /* Scale but preserve the aspect ratio */ - if (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; @@ -324,7 +356,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 (INTEL_INFO(dev)->gen >= 4) + if (IS_I965G(dev)) pfit_control |= PFIT_SCALING_AUTO; else pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | @@ -337,12 +369,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, } out: - 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; - } + intel_lvds->pfit_control = pfit_control; + intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios; dev_priv->lvds_border_bits = border; /* @@ -358,60 +386,30 @@ static void intel_lvds_prepare(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); - - 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. - */ + u32 reg; - 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); - } + 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); + + intel_lvds_set_power(dev, false); } -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_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); - } + if (dev_priv->backlight_duty_cycle == 0) + dev_priv->backlight_duty_cycle = + intel_lvds_get_max_backlight(dev); - /* Always do a full power on as we do not know what state - * we were left in. - */ - intel_lvds_set_power(intel_lvds, true); + intel_lvds_set_power(dev, true); } static void intel_lvds_mode_set(struct drm_encoder *encoder, @@ -420,7 +418,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 = to_intel_lvds(encoder); + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); /* * The LVDS pin pair will already have been turned on in the @@ -431,23 +429,13 @@ 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; } /** @@ -477,22 +465,38 @@ 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_display_mode *mode; + 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); - if (intel_lvds->edid) { - drm_mode_connector_update_edid_property(connector, - intel_lvds->edid); - return drm_add_edid_modes(connector, intel_lvds->edid); + if (ret) + return ret; } - mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode); - if (mode == 0) - return 0; + /* 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; - drm_mode_probed_add(connector, mode); - return 1; + 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; + } + + return 0; } static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id) @@ -583,17 +587,18 @@ 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) { - struct drm_crtc *crtc = intel_lvds->base.base.crtc; + 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 (value == DRM_MODE_SCALE_NONE) { DRM_DEBUG_KMS("no scaling not supported\n"); - return -EINVAL; + return 0; } - if (intel_lvds->fitting_mode == value) { /* the LVDS scaling property is not changed */ return 0; @@ -623,7 +628,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_best_encoder, + .best_encoder = intel_attached_encoder, }; static const struct drm_connector_funcs intel_lvds_connector_funcs = { @@ -721,14 +726,16 @@ 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_display_mode *fixed_mode, - struct drm_connector *connector) + struct drm_connector *connector) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *scan; + struct drm_display_mode *scan, *panel_fixed_mode; int temp_downclock; - temp_downclock = fixed_mode->clock; + panel_fixed_mode = dev_priv->panel_fixed_mode; + temp_downclock = panel_fixed_mode->clock; + + mutex_lock(&dev->mode_config.mutex); list_for_each_entry(scan, &connector->probed_modes, head) { /* * If one mode has the same resolution with the fixed_panel @@ -737,14 +744,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 == 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->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->clock < temp_downclock) { /* * The downclock is already found. But we @@ -754,14 +761,17 @@ static void intel_find_lvds_downclock(struct drm_device *dev, } } } - if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) { + mutex_unlock(&dev->mode_config.mutex); + if (temp_downclock < panel_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", - fixed_mode->clock, temp_downclock); + "Normal clock %dKhz, downclock %dKhz\n", + panel_fixed_mode->clock, temp_downclock); } + return; } /* @@ -770,67 +780,38 @@ 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 bool lvds_is_present_in_vbt(struct drm_device *dev, - u8 *i2c_pin) +static int lvds_is_present_in_vbt(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int i; + struct child_device_config *p_child; + int i, ret; if (!dev_priv->child_dev_num) - return true; + return 1; + ret = 0; for (i = 0; i < dev_priv->child_dev_num; i++) { - 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. + 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. */ - if (child->device_type != DEVICE_TYPE_INT_LFP && - child->device_type != DEVICE_TYPE_LFP) + if (p_child->device_type != DEVICE_TYPE_INT_LFP && + p_child->device_type != DEVICE_TYPE_LFP) continue; - 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 (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. + /* The addin_offset should be checked. Only when it is + * non-zero, it is regarded as present. */ - if (dev_priv->opregion.vbt) - return true; + if (p_child->addin_offset) { + ret = 1; + break; + } } - - 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; + return ret; } /** @@ -851,15 +832,13 @@ void intel_lvds_init(struct drm_device *dev) struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; u32 lvds; - int pipe; - u8 pin; + int pipe, gpio = GPIOC; /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) return; - pin = GMBUS_PORT_PANEL; - if (!lvds_is_present_in_vbt(dev, &pin)) { + if (!lvds_is_present_in_vbt(dev)) { DRM_DEBUG_KMS("LVDS is not present in VBT\n"); return; } @@ -867,15 +846,11 @@ 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; } - } - - if (!intel_lvds_ddc_probe(dev, pin)) { - DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n"); - return; + gpio = PCH_GPIOC; } intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL); @@ -889,20 +864,16 @@ 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->base; + encoder = &intel_encoder->enc; 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->base, &intel_lvds_enc_funcs, + drm_encoder_init(dev, &intel_encoder->enc, &intel_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS); - intel_connector_attach_encoder(intel_connector, intel_encoder); + drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc); intel_encoder->type = INTEL_OUTPUT_LVDS; intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT); @@ -933,41 +904,43 @@ 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. */ - intel_lvds->edid = drm_get_edid(connector, - &dev_priv->gmbus[pin].adapter); + dev_priv->lvds_edid_good = true; - 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; - } + if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus)) + dev_priv->lvds_edid_good = false; list_for_each_entry(scan, &connector->probed_modes, head) { + mutex_lock(&dev->mode_config.mutex); if (scan->type & DRM_MODE_TYPE_PREFERRED) { - intel_lvds->fixed_mode = + dev_priv->panel_fixed_mode = drm_mode_duplicate(dev, scan); - intel_find_lvds_downclock(dev, - intel_lvds->fixed_mode, - connector); + mutex_unlock(&dev->mode_config.mutex); + intel_find_lvds_downclock(dev, connector); goto out; } + mutex_unlock(&dev->mode_config.mutex); } /* Failed to get EDID, what about VBT? */ if (dev_priv->lfp_lvds_vbt_mode) { - intel_lvds->fixed_mode = + mutex_lock(&dev->mode_config.mutex); + dev_priv->panel_fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); - if (intel_lvds->fixed_mode) { - intel_lvds->fixed_mode->type |= + mutex_unlock(&dev->mode_config.mutex); + if (dev_priv->panel_fixed_mode) { + dev_priv->panel_fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; goto out; } @@ -985,19 +958,19 @@ void intel_lvds_init(struct drm_device *dev) lvds = I915_READ(LVDS); pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; - crtc = intel_get_crtc_for_pipe(dev, pipe); + crtc = intel_get_crtc_from_pipe(dev, pipe); if (crtc && (lvds & LVDS_PORT_EN)) { - intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc); - if (intel_lvds->fixed_mode) { - intel_lvds->fixed_mode->type |= + dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc); + if (dev_priv->panel_fixed_mode) { + dev_priv->panel_fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; goto out; } } /* If we still don't have a mode after all that, give up. */ - if (!intel_lvds->fixed_mode) + if (!dev_priv->panel_fixed_mode) goto failed; out: @@ -1024,6 +997,8 @@ void intel_lvds_init(struct drm_device *dev) 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); diff --git a/trunk/drivers/gpu/drm/i915/intel_modes.c b/trunk/drivers/gpu/drm/i915/intel_modes.c index f70b7cf32bff..4b1fd3d9c73c 100644 --- a/trunk/drivers/gpu/drm/i915/intel_modes.c +++ b/trunk/drivers/gpu/drm/i915/intel_modes.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Dave Airlie - * Copyright (c) 2007, 2010 Intel Corporation + * Copyright (c) 2007 Intel Corporation * Jesse Barnes * * Permission is hereby granted, free of charge, to any person obtaining a @@ -34,11 +34,11 @@ * intel_ddc_probe * */ -bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus) +bool intel_ddc_probe(struct intel_encoder *intel_encoder) { - 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,7 +54,13 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus) } }; - return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 2) == 2; + 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; } /** @@ -70,7 +76,9 @@ 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); diff --git a/trunk/drivers/gpu/drm/i915/intel_overlay.c b/trunk/drivers/gpu/drm/i915/intel_overlay.c index 375316a8420e..1d306a458be6 100644 --- a/trunk/drivers/gpu/drm/i915/intel_overlay.c +++ b/trunk/drivers/gpu/drm/i915/intel_overlay.c @@ -170,143 +170,57 @@ struct overlay_registers { u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; }; -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 *); -}; +/* overlay flip addr flag */ +#define OFC_UPDATE 0x1 -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; +#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev)) +#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev)) - 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); - return regs; -} - -static void intel_overlay_unmap_regs(struct intel_overlay *overlay, - struct overlay_registers *regs) +static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay) { - if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev)) - io_mapping_unmap(regs); -} + drm_i915_private_t *dev_priv = overlay->dev->dev_private; + struct overlay_registers *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; + /* no recursive mappings */ + BUG_ON(overlay->virt_addr); - 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; + if (OVERLAY_NONPHYSICAL(overlay->dev)) { + regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + overlay->reg_bo->gtt_offset, + KM_USER0); - overlay->flip_tail = tail; - ret = i915_do_wait_request(dev, - overlay->last_flip_req, true, - &dev_priv->render_ring); - if (ret) - return ret; + if (!regs) { + DRM_ERROR("failed to map overlay regs in GTT\n"); + return NULL; + } + } else + regs = overlay->reg_bo->phys_obj->handle->vaddr; - overlay->last_flip_req = 0; - return 0; + return overlay->virt_addr = regs; } -/* Workaround for i830 bug where pipe a must be enable to change control regs */ -static int -i830_activate_pipe_a(struct drm_device *dev) +static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay) { - 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; - - /* most i8xx have pipe a forced on, so don't trust dpms mode */ - if (I915_READ(PIPEACONF) & PIPECONF_ENABLE) - return 0; - - 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"); + if (OVERLAY_NONPHYSICAL(overlay->dev)) + io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0); - 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; -} + overlay->virt_addr = NULL; -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); + return; } /* 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; - 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; - } + overlay->active = 1; + overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP; BEGIN_LP_RING(4); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); @@ -315,30 +229,32 @@ static int intel_overlay_on(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - ret = intel_overlay_do_wait_request(overlay, request, true, NULL); -out: - if (pipe_a_quirk) - i830_deactivate_pipe_a(dev); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); + if (overlay->last_flip_req == 0) + return -ENOMEM; - return ret; + 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 0; } /* overlay needs to be enabled in OCMD reg */ -static int intel_overlay_continue(struct intel_overlay *overlay, - bool load_polyphase_filter) +static void 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; @@ -353,132 +269,220 @@ static int intel_overlay_continue(struct intel_overlay *overlay, ADVANCE_LP_RING(); overlay->last_flip_req = - i915_add_request(dev, NULL, request, &dev_priv->render_ring); - return 0; + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); } -static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) +static int intel_overlay_wait_flip(struct intel_overlay *overlay) { - struct drm_gem_object *obj = &overlay->old_vid_bo->base; + struct drm_device *dev = overlay->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + u32 tmp; - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); + 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; - overlay->old_vid_bo = NULL; -} + tmp = I915_READ(ISR); -static void intel_overlay_off_tail(struct intel_overlay *overlay) -{ - struct drm_gem_object *obj; + if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT)) + return 0; + } + } - /* never have the overlay hw on without showing a frame */ - BUG_ON(!overlay->vid_bo); - obj = &overlay->vid_bo->base; + /* synchronous slowpath */ + overlay->hw_wedged = RELEASE_OLD_VID; - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - overlay->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(); - overlay->crtc->overlay = NULL; - overlay->crtc = NULL; - overlay->active = 0; + 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 0; } /* overlay needs to be disabled in OCMD reg */ -static int intel_overlay_off(struct intel_overlay *overlay, - bool interruptible) +static int intel_overlay_off(struct intel_overlay *overlay) { - struct drm_device *dev = overlay->dev; u32 flip_addr = overlay->flip_addr; - struct drm_i915_gem_request *request; + struct drm_device *dev = overlay->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; 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_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; + /* turn overlay off */ - OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); + 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_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); + OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - return intel_overlay_do_wait_request(overlay, request, interruptible, - intel_overlay_off_tail); + 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; } /* recover from an interruption due to a signal * We have to be careful not to repeat work forever an make forward progess. */ -static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, - bool interruptible) +int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, + int 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->last_flip_req == 0) - return 0; + 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; + } ret = i915_do_wait_request(dev, overlay->last_flip_req, - interruptible, &dev_priv->render_ring); - if (ret) + interruptible, &dev_priv->render_ring); + if (ret != 0) return ret; - if (overlay->flip_tail) - overlay->flip_tail(overlay); + 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); + } + 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 - */ + * via intel_overlay_(un)map_regs_atomic */ 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; - if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { - struct drm_i915_gem_request *request; - - /* 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_wait_flip(overlay); + if (ret != 0) + return ret; - ret = intel_overlay_do_wait_request(overlay, request, true, - intel_overlay_release_old_vid_tail); - if (ret) - return ret; - } + obj = &overlay->old_vid_bo->base; + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + overlay->old_vid_bo = NULL; - intel_overlay_release_old_vid_tail(overlay); return 0; } @@ -502,65 +506,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_GEN2(dev)) { - mask = 0x1f; - shift = 5; - } else { + if (IS_I9XX(dev)) { mask = 0x3f; shift = 6; + } else { + mask = 0x1f; + shift = 5; } ret = ((offset + width + mask) >> shift) - (offset >> shift); - if (!IS_GEN2(dev)) + if (IS_I9XX(dev)) ret <<= 1; ret -=1; return ret << 2; @@ -583,9 +587,7 @@ 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, @@ -595,8 +597,7 @@ 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) { @@ -629,31 +630,29 @@ 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); @@ -665,28 +664,22 @@ 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; - 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; + 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; } } @@ -696,48 +689,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; } -static int intel_overlay_do_put_image(struct intel_overlay *overlay, - struct drm_gem_object *new_bo, - struct put_image_params *params) +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; @@ -762,24 +755,24 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, goto out_unpin; if (!overlay->active) { - regs = intel_overlay_map_regs(overlay); + regs = intel_overlay_map_regs_atomic(overlay); if (!regs) { ret = -ENOMEM; goto out_unpin; } regs->OCONFIG = OCONF_CC_OUT_8BIT; - if (IS_GEN4(overlay->dev)) + if (IS_I965GM(overlay->dev)) regs->OCONFIG |= OCONF_CSC_MODE_BT709; regs->OCONFIG |= overlay->crtc->pipe == 0 ? OCONF_PIPE_A : OCONF_PIPE_B; - intel_overlay_unmap_regs(overlay, regs); + intel_overlay_unmap_regs_atomic(overlay); ret = intel_overlay_on(overlay); if (ret != 0) goto out_unpin; } - regs = intel_overlay_map_regs(overlay); + regs = intel_overlay_map_regs_atomic(overlay); if (!regs) { ret = -ENOMEM; goto out_unpin; @@ -795,7 +788,7 @@ static 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; @@ -806,9 +799,9 @@ static 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; @@ -822,11 +815,9 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, regs->OCMD = overlay_cmd_reg(params); - intel_overlay_unmap_regs(overlay, regs); + intel_overlay_unmap_regs_atomic(overlay); - ret = intel_overlay_continue(overlay, scale_changed); - if (ret) - goto out_unpin; + intel_overlay_continue(overlay, scale_changed); overlay->old_vid_bo = overlay->vid_bo; overlay->vid_bo = to_intel_bo(new_bo); @@ -838,19 +829,20 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, return ret; } -int intel_overlay_switch_off(struct intel_overlay *overlay, - bool interruptible) +int intel_overlay_switch_off(struct intel_overlay *overlay) { + 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)); - ret = intel_overlay_recover_from_interrupt(overlay, interruptible); - if (ret != 0) - return ret; + if (overlay->hw_wedged) { + ret = intel_overlay_recover_from_interrupt(overlay, 1); + if (ret != 0) + return ret; + } if (!overlay->active) return 0; @@ -859,29 +851,33 @@ int intel_overlay_switch_off(struct intel_overlay *overlay, if (ret != 0) return ret; - regs = intel_overlay_map_regs(overlay); + regs = intel_overlay_map_regs_atomic(overlay); regs->OCMD = 0; - intel_overlay_unmap_regs(overlay, regs); + intel_overlay_unmap_regs_atomic(overlay); - ret = intel_overlay_off(overlay, interruptible); + ret = intel_overlay_off(overlay); 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; + drm_i915_private_t *dev_priv = overlay->dev->dev_private; + u32 pipeconf; + int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF; - if (!crtc->active) + if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON) return -EINVAL; + pipeconf = I915_READ(pipeconf_reg); + /* can't use the overlay with double wide pipe */ - if (INTEL_INFO(overlay->dev)->gen < 4 && - (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE) + if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE) return -EINVAL; return 0; @@ -890,22 +886,20 @@ 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 pfit_control = I915_READ(PFIT_CONTROL); + drm_i915_private_t *dev_priv = dev->dev_private; u32 ratio; + u32 pfit_control = I915_READ(PFIT_CONTROL); /* XXX: This is not the same logic as in the xorg driver, but more in - * 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); + * 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; else - ratio = I915_READ(PFIT_PGM_RATIOS); - ratio >>= PFIT_VERT_SCALE_SHIFT; + ratio >>= PFIT_VERT_SCALE_SHIFT; } overlay->pfit_vscale_ratio = ratio; @@ -916,10 +910,12 @@ 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; @@ -944,57 +940,53 @@ 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); - u32 stride_mask, depth, tmp; + size_t 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 */ - return -EINVAL; - - case I915_OVERLAY_YUV_PACKED: - if (uv_vscale != 1) - return -EINVAL; - - 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) + case I915_OVERLAY_RGB: + /* not implemented */ return -EINVAL; - break; - - case I915_OVERLAY_YUV_PLANAR: - if (uv_vscale < 0 || uv_hscale < 0) + 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: return -EINVAL; - /* no offset restrictions for planar formats */ - break; - - default: - return -EINVAL; } if (rec->src_width % uv_hscale) @@ -1008,74 +1000,47 @@ static int check_overlay_src(struct drm_device *dev, if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) return -EINVAL; - if (IS_GEN4(dev) && rec->stride_Y < 512) + if (IS_I965G(dev) && rec->stride_Y < 512) return -EINVAL; tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ? - 4096 : 8192; - if (rec->stride_Y > tmp || rec->stride_UV > 2*1024) + 4 : 8; + if (rec->stride_Y > tmp*1024 || 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 / 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; + tmp /= 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) { @@ -1103,7 +1068,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, true); + ret = intel_overlay_switch_off(overlay); mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->mode_config.mutex); @@ -1116,7 +1081,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; @@ -1124,7 +1089,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; @@ -1133,13 +1098,15 @@ 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_recover_from_interrupt(overlay, true); - if (ret != 0) - goto out_unlock; + if (overlay->hw_wedged) { + ret = intel_overlay_recover_from_interrupt(overlay, 1); + if (ret != 0) + goto out_unlock; + } if (overlay->crtc != crtc) { struct drm_display_mode *mode = &crtc->base.mode; - ret = intel_overlay_switch_off(overlay, true); + ret = intel_overlay_switch_off(overlay); if (ret != 0) goto out_unlock; @@ -1150,9 +1117,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, overlay->crtc = crtc; crtc->overlay = overlay; - /* line too wide, i.e. one-line-mode */ - if (mode->hdisplay > 1024 && - intel_panel_fitter_pipe(dev) == crtc->pipe) { + if (intel_panel_fitter_pipe(dev) == crtc->pipe + /* and line to wide, i.e. one-line-mode */ + && mode->hdisplay > 1024) { overlay->pfit_active = 1; update_pfit_vscale_ratio(overlay); } else @@ -1165,10 +1132,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; @@ -1180,8 +1147,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; } @@ -1237,7 +1204,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; } @@ -1258,18 +1225,16 @@ 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; } @@ -1296,14 +1261,13 @@ 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_GEN2(dev)) { + if (IS_I9XX(dev)) { attrs->gamma0 = I915_READ(OGAMC0); attrs->gamma1 = I915_READ(OGAMC1); attrs->gamma2 = I915_READ(OGAMC2); @@ -1311,20 +1275,29 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, attrs->gamma4 = I915_READ(OGAMC4); attrs->gamma5 = I915_READ(OGAMC5); } + ret = 0; } else { - if (attrs->brightness < -128 || attrs->brightness > 127) + overlay->color_key = attrs->color_key; + if (attrs->brightness >= -128 && attrs->brightness <= 127) { + overlay->brightness = attrs->brightness; + } else { + ret = -EINVAL; goto out_unlock; - if (attrs->contrast > 255) + } + if (attrs->contrast <= 255) { + overlay->contrast = attrs->contrast; + } else { + ret = -EINVAL; goto out_unlock; - if (attrs->saturation > 1023) + } + if (attrs->saturation <= 1023) { + overlay->saturation = attrs->saturation; + } else { + ret = -EINVAL; goto out_unlock; + } - overlay->color_key = attrs->color_key; - overlay->brightness = attrs->brightness; - overlay->contrast = attrs->contrast; - overlay->saturation = attrs->saturation; - - regs = intel_overlay_map_regs(overlay); + regs = intel_overlay_map_regs_atomic(overlay); if (!regs) { ret = -ENOMEM; goto out_unlock; @@ -1332,11 +1305,13 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, update_reg_attrs(overlay, regs); - intel_overlay_unmap_regs(overlay, regs); + intel_overlay_unmap_regs_atomic(overlay); if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) { - if (IS_GEN2(dev)) + if (!IS_I9XX(dev)) { + ret = -EINVAL; goto out_unlock; + } if (overlay->active) { ret = -EBUSY; @@ -1344,7 +1319,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, } ret = check_gamma(attrs); - if (ret) + if (ret != 0) goto out_unlock; I915_WRITE(OGAMC0, attrs->gamma0); @@ -1354,9 +1329,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); @@ -1372,7 +1347,7 @@ void intel_setup_overlay(struct drm_device *dev) struct overlay_registers *regs; int ret; - if (!HAS_OVERLAY(dev)) + if (!OVERLAY_EXISTS(dev)) return; overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL); @@ -1385,28 +1360,22 @@ void intel_setup_overlay(struct drm_device *dev) goto out_free; overlay->reg_bo = to_intel_bo(reg_bo); - if (OVERLAY_NEEDS_PHYSICAL(dev)) { - ret = i915_gem_attach_phys_object(dev, reg_bo, - I915_GEM_PHYS_OVERLAY_REGS, - 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 { + 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; - - 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; + } else { + ret = i915_gem_attach_phys_object(dev, reg_bo, + I915_GEM_PHYS_OVERLAY_REGS, + 0); + 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; } /* init all values */ @@ -1415,22 +1384,21 @@ void intel_setup_overlay(struct drm_device *dev) overlay->contrast = 75; overlay->saturation = 146; - regs = intel_overlay_map_regs(overlay); + regs = intel_overlay_map_regs_atomic(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(overlay, regs); + intel_overlay_unmap_regs_atomic(overlay); 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: @@ -1440,23 +1408,18 @@ void intel_setup_overlay(struct drm_device *dev) void intel_cleanup_overlay(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; - - if (!dev_priv->overlay) - return; + drm_i915_private_t *dev_priv = dev->dev_private; - /* 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) { + /* 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); + kfree(dev_priv->overlay); + } } -#ifdef CONFIG_DEBUG_FS -#include - struct intel_overlay_error_state { struct overlay_registers regs; unsigned long base; @@ -1464,32 +1427,6 @@ 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) { @@ -1507,17 +1444,17 @@ intel_overlay_capture_error_state(struct drm_device *dev) error->dovsta = I915_READ(DOVSTA); error->isr = I915_READ(ISR); - if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) - error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr; - else + if (OVERLAY_NONPHYSICAL(overlay->dev)) error->base = (long) overlay->reg_bo->gtt_offset; + else + error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr; - regs = intel_overlay_map_regs_atomic(overlay, KM_IRQ0); + regs = intel_overlay_map_regs_atomic(overlay); if (!regs) goto err; memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); - intel_overlay_unmap_regs_atomic(overlay, KM_IRQ0, regs); + intel_overlay_unmap_regs_atomic(overlay); return error; @@ -1578,4 +1515,3 @@ intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_s P(UVSCALEV); #undef P } -#endif diff --git a/trunk/drivers/gpu/drm/i915/intel_panel.c b/trunk/drivers/gpu/drm/i915/intel_panel.c index 92ff8f385278..e7f5299d9d57 100644 --- a/trunk/drivers/gpu/drm/i915/intel_panel.c +++ b/trunk/drivers/gpu/drm/i915/intel_panel.c @@ -30,8 +30,6 @@ #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) @@ -111,110 +109,3 @@ intel_pch_panel_fitting(struct drm_device *dev, 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); -} diff --git a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c index d89b88791aac..cb3508f78bc3 100644 --- a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -32,7 +32,6 @@ #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) { @@ -50,9 +49,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; @@ -98,7 +97,7 @@ render_ring_flush(struct drm_device *dev, if ((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) cmd &= ~MI_NO_WRITE_FLUSH; - if (INTEL_INFO(dev)->gen < 4) { + if (!IS_I965G(dev)) { /* * On the 965, the sampler cache always gets flushed * and this bit is reserved. @@ -119,26 +118,38 @@ render_ring_flush(struct drm_device *dev, } } -static void ring_set_tail(struct drm_device *dev, - struct intel_ring_buffer *ring, - u32 value) +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) { drm_i915_private_t *dev_priv = dev->dev_private; - I915_WRITE_TAIL(ring, ring->tail); + return I915_READ(PRB0_TAIL) & TAIL_ADDR; } -u32 intel_ring_get_active_head(struct drm_device *dev, - struct intel_ring_buffer *ring) +static unsigned int render_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 = INTEL_INFO(dev)->gen >= 4 ? - RING_ACTHD(ring->mmio_base) : ACTHD; + u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : 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; @@ -146,57 +157,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_CTL(ring, 0); - I915_WRITE_HEAD(ring, 0); - ring->set_tail(dev, ring, 0); + I915_WRITE(ring->regs.ctl, 0); + I915_WRITE(ring->regs.head, 0); + I915_WRITE(ring->regs.tail, 0); /* Initialize the ring. */ - I915_WRITE_START(ring, obj_priv->gtt_offset); - head = I915_READ_HEAD(ring) & HEAD_ADDR; + I915_WRITE(ring->regs.start, obj_priv->gtt_offset); + head = ring->get_head(dev, ring); /* 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_CTL(ring), - I915_READ_HEAD(ring), - I915_READ_TAIL(ring), - I915_READ_START(ring)); + I915_READ(ring->regs.ctl), + I915_READ(ring->regs.head), + I915_READ(ring->regs.tail), + I915_READ(ring->regs.start)); - I915_WRITE_HEAD(ring, 0); + I915_WRITE(ring->regs.head, 0); DRM_ERROR("%s head forced to zero " "ctl %08x head %08x tail %08x start %08x\n", ring->name, - I915_READ_CTL(ring), - I915_READ_HEAD(ring), - I915_READ_TAIL(ring), - I915_READ_START(ring)); + I915_READ(ring->regs.ctl), + I915_READ(ring->regs.head), + I915_READ(ring->regs.tail), + I915_READ(ring->regs.start)); } - I915_WRITE_CTL(ring, + I915_WRITE(ring->regs.ctl, ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES) | RING_NO_REPORT | RING_VALID); - head = I915_READ_HEAD(ring) & HEAD_ADDR; + head = I915_READ(ring->regs.head) & 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_CTL(ring), - I915_READ_HEAD(ring), - I915_READ_TAIL(ring), - I915_READ_START(ring)); + I915_READ(ring->regs.ctl), + I915_READ(ring->regs.head), + I915_READ(ring->regs.tail), + I915_READ(ring->regs.start)); return -EIO; } if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_kernel_lost_context(dev); else { - ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; - ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; + ring->head = ring->get_head(dev, ring); + ring->tail = ring->get_tail(dev, ring); ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->size; @@ -205,13 +216,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 (INTEL_INFO(dev)->gen > 3) { + if (IS_I9XX(dev) && !IS_GEN3(dev)) { mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH; if (IS_GEN6(dev)) mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE; @@ -239,8 +250,9 @@ do { \ */ static u32 render_ring_add_request(struct drm_device *dev, - struct intel_ring_buffer *ring, - u32 flush_domains) + struct intel_ring_buffer *ring, + struct drm_file *file_priv, + u32 flush_domains) { drm_i915_private_t *dev_priv = dev->dev_private; u32 seqno; @@ -303,8 +315,8 @@ render_ring_add_request(struct drm_device *dev, } static u32 -render_ring_get_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) +render_ring_get_gem_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)) @@ -315,7 +327,7 @@ render_ring_get_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; @@ -332,7 +344,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; @@ -348,23 +360,21 @@ render_ring_put_user_irq(struct drm_device *dev, spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } -void intel_ring_setup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) +static void render_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(RING_HWS_PGA_GEN6(ring->mmio_base), - ring->status_page.gfx_addr); - I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); /* posting read */ + I915_WRITE(HWS_PGA_GEN6, ring->status_page.gfx_addr); + I915_READ(HWS_PGA_GEN6); /* posting read */ } else { - I915_WRITE(RING_HWS_PGA(ring->mmio_base), - ring->status_page.gfx_addr); - I915_READ(RING_HWS_PGA(ring->mmio_base)); /* posting read */ + I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); + I915_READ(HWS_PGA); /* posting read */ } } -static void +void bsd_ring_flush(struct drm_device *dev, struct intel_ring_buffer *ring, u32 invalidate_domains, @@ -376,16 +386,45 @@ 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, - u32 flush_domains) + struct intel_ring_buffer *ring, + struct drm_file *file_priv, + u32 flush_domains) { u32 seqno; @@ -404,32 +443,40 @@ 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_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) +bsd_ring_get_gem_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; @@ -444,10 +491,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; @@ -477,7 +524,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev, intel_ring_emit(dev, ring, 0); } else { intel_ring_begin(dev, ring, 4); - if (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); @@ -506,7 +553,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; @@ -526,7 +573,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; @@ -556,7 +603,7 @@ static int init_status_page(struct drm_device *dev, ring->status_page.obj = obj; memset(ring->status_page.page_addr, 0, PAGE_SIZE); - intel_ring_setup_status_page(dev, ring); + ring->setup_status_page(dev, ring); DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n", ring->name, ring->status_page.gfx_addr); @@ -570,17 +617,15 @@ static int init_status_page(struct drm_device *dev, 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); @@ -597,7 +642,7 @@ int intel_init_ring_buffer(struct drm_device *dev, ring->gem_object = obj; - ret = i915_gem_object_pin(obj, PAGE_SIZE); + ret = i915_gem_object_pin(obj, ring->alignment); if (ret) goto err_unref; @@ -623,12 +668,14 @@ 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 = I915_READ_HEAD(ring) & HEAD_ADDR; - ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; + ring->head = ring->get_head(dev, ring); + ring->tail = ring->get_tail(dev, ring); 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: @@ -644,7 +691,7 @@ int intel_init_ring_buffer(struct drm_device *dev, } 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; @@ -657,8 +704,8 @@ void intel_cleanup_ring_buffer(struct drm_device *dev, cleanup_status_page(dev, ring); } -static int intel_wrap_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring) +int intel_wrap_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring) { unsigned int *virt; int rem; @@ -684,15 +731,14 @@ static 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 = I915_READ_HEAD(ring) & HEAD_ADDR; + ring->head = ring->get_head(dev, ring); ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->size; @@ -714,8 +760,7 @@ 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)) @@ -727,16 +772,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->set_tail(dev, ring, ring->tail); + ring->advance_ring(dev, ring); } 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); @@ -748,136 +793,76 @@ void intel_fill_struct(struct drm_device *dev, intel_ring_advance(dev, ring); } -static const struct intel_ring_buffer render_ring = { +struct intel_ring_buffer render_ring = { .name = "render ring", - .id = RING_RENDER, - .mmio_base = RENDER_RING_BASE, + .regs = { + .ctl = PRB0_CTL, + .head = PRB0_HEAD, + .tail = PRB0_TAIL, + .start = PRB0_START + }, + .ring_flag = I915_EXEC_RENDER, .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, - .set_tail = ring_set_tail, + .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, .flush = render_ring_flush, .add_request = render_ring_add_request, - .get_seqno = render_ring_get_seqno, + .get_gem_seqno = render_ring_get_gem_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 */ -static const struct intel_ring_buffer bsd_ring = { +struct intel_ring_buffer bsd_ring = { .name = "bsd ring", - .id = RING_BSD, - .mmio_base = BSD_RING_BASE, + .regs = { + .ctl = BSD_RING_CTL, + .head = BSD_RING_HEAD, + .tail = BSD_RING_TAIL, + .start = BSD_RING_START + }, + .ring_flag = I915_EXEC_BSD, .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, - .set_tail = ring_set_tail, + .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, .flush = bsd_ring_flush, .add_request = bsd_ring_add_request, - .get_seqno = bsd_ring_get_seqno, + .get_gem_seqno = bsd_ring_get_gem_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); -} diff --git a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.h b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.h index 9725f783db20..525e7d3edda8 100644 --- a/trunk/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/trunk/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -7,31 +7,25 @@ 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; - enum intel_ring_id { - RING_RENDER = 0x1, - RING_BSD = 0x2, - } id; - u32 mmio_base; + struct ring_regs { + u32 ctl; + u32 head; + u32 tail; + u32 start; + } regs; + unsigned int ring_flag; 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; - int space; + unsigned int space; struct intel_hw_status_page status_page; u32 irq_gem_seqno; /* last seq seem at irq time */ @@ -41,22 +35,30 @@ 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); - void (*set_tail)(struct drm_device *dev, - struct intel_ring_buffer *ring, - u32 value); + 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 (*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_seqno)(struct drm_device *dev, - struct intel_ring_buffer *ring); + u32 (*get_gem_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, @@ -81,11 +83,6 @@ 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; }; @@ -99,13 +96,15 @@ 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); + struct intel_ring_buffer *ring, int n); +int intel_wrap_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring); 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, @@ -126,12 +125,7 @@ void intel_ring_advance(struct drm_device *dev, u32 intel_ring_get_seqno(struct drm_device *dev, struct intel_ring_buffer *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); +extern struct intel_ring_buffer render_ring; +extern struct intel_ring_buffer bsd_ring; #endif /* _INTEL_RINGBUFFER_H_ */ diff --git a/trunk/drivers/gpu/drm/i915/intel_sdvo.c b/trunk/drivers/gpu/drm/i915/intel_sdvo.c index a84224f37605..e8e902d614ed 100644 --- a/trunk/drivers/gpu/drm/i915/intel_sdvo.c +++ b/trunk/drivers/gpu/drm/i915/intel_sdvo.c @@ -65,11 +65,8 @@ 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; @@ -109,11 +106,15 @@ struct intel_sdvo { bool is_hdmi; /** - * This is set if we detect output of sdvo device as LVDS and - * have a valid fixed mode to use with the panel. + * This is set if we detect output of sdvo device as LVDS. */ bool is_lvds; + /** + * This is sdvo flags for input timing. + */ + uint8_t sdvo_flags; + /** * This is sdvo fixed pannel mode pointer */ @@ -128,8 +129,9 @@ struct intel_sdvo { /* DDC bus used by this SDVO encoder */ uint8_t ddc_bus; - /* Input timings for adjusted_mode */ - struct intel_sdvo_dtd input_dtd; + /* Mac mini hack -- use the same DDC as the analog connector */ + struct i2c_adapter *analog_ddc_bus; + }; struct intel_sdvo_connector { @@ -184,15 +186,9 @@ struct intel_sdvo_connector { u32 cur_dot_crawl, max_dot_crawl; }; -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) +static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) { - return container_of(intel_attached_encoder(connector), - struct intel_sdvo, base); + return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base); } static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector) @@ -217,7 +213,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.base.dev; + struct drm_device *dev = intel_sdvo->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 bval = val, cval = val; int i; @@ -249,29 +245,49 @@ 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, + .addr = intel_sdvo->slave_addr >> 1, .flags = 0, .len = 1, - .buf = &addr, + .buf = out_buf, }, { - .addr = intel_sdvo->slave_addr, + .addr = intel_sdvo->slave_addr >> 1, .flags = I2C_M_RD, .len = 1, - .buf = ch, + .buf = buf, } }; int ret; - if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2) + if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2) + { + *ch = buf[0]; 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 { @@ -416,6 +432,22 @@ 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", @@ -426,115 +458,54 @@ static const char *cmd_status_names[] = { "Scaling not supported" }; -static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, - const void *args, int args_len) +static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo, + void *response, int response_len, + u8 status) { - u8 buf[args_len*2 + 2], status; - struct i2c_msg msgs[args_len + 3]; - int i, ret; - - 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; - } + int i; - return true; + 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"); } static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, void *response, int response_len) { - u8 retry = 5; - u8 status; int i; + 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; + } - /* - * 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, + /* read the return status */ + if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, &status)) return false; - } while (status == SDVO_CMD_STATUS_PENDING && --retry); - 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; + intel_sdvo_debug_response(intel_sdvo, response, response_len, + status); + if (status != SDVO_CMD_STATUS_PENDING) + break; - /* 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]); + mdelay(50); } - DRM_LOG_KMS("\n"); - return true; -log_fail: - DRM_LOG_KMS("\n"); - return false; + return status == SDVO_CMD_STATUS_SUCCESS; } static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) @@ -547,17 +518,71 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) return 4; } -static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, - u8 ddc_bus) +/** + * 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) { - return intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_SET_CONTROL_BUS_SWITCH, - &ddc_bus, 1); + 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; } static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len) { - return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len); + if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len)) + return false; + + return intel_sdvo_read_response(intel_sdvo, NULL, 0); } static bool @@ -997,6 +1022,8 @@ 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; @@ -1008,12 +1035,14 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo, return false; if (!intel_sdvo_get_preferred_input_timing(intel_sdvo, - &intel_sdvo->input_dtd)) + &input_dtd)) return false; - intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd); + intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); + intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; drm_mode_set_crtcinfo(adjusted_mode, 0); + mode->clock = adjusted_mode->clock; return true; } @@ -1021,8 +1050,7 @@ 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 = to_intel_sdvo(encoder); - int multiplier; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); /* We need to construct preferred input timings based on our * output timings. To do that, we have to set the output @@ -1037,8 +1065,10 @@ 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, @@ -1047,10 +1077,9 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, } /* Make the CRTC code factor in the SDVO pixel multiplier. The - * SDVO device will factor out the multiplier during mode_set. + * SDVO device will be told of the multiplier during mode_set. */ - multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode); - intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); + adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); return true; } @@ -1063,12 +1092,11 @@ 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 = to_intel_sdvo(encoder); - u32 sdvox; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + u32 sdvox = 0; + int sdvo_pixel_multiply, rate; 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; @@ -1086,23 +1114,28 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, SDVO_CMD_SET_IN_OUT_MAP, &in_out, sizeof(in_out)); - /* Set the output timings to the screen */ - if (!intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output)) - return; + if (intel_sdvo->is_hdmi) { + if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) + return; + + sdvox |= SDVO_AUDIO_ENABLE; + } /* We have tried to get input timing in mode_fixup, and filled into - * adjusted_mode. + 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. */ - if (intel_sdvo->is_tv || intel_sdvo->is_lvds) { - input_dtd = intel_sdvo->input_dtd; - } else { + if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) { /* 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); } @@ -1110,18 +1143,31 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, if (!intel_sdvo_set_target_input(intel_sdvo)) return; - if (intel_sdvo->is_hdmi && - !intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) - return; + if (intel_sdvo->is_tv) { + if (!intel_sdvo_set_tv_format(intel_sdvo)) + return; + } - if (intel_sdvo->is_tv && - !intel_sdvo_set_tv_format(intel_sdvo)) - 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; + 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 - switch (pixel_multiplier) { - default: + sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); + switch (sdvo_pixel_multiply) { 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; @@ -1130,14 +1176,14 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, return; /* Set the SDVO control regs. */ - if (INTEL_INFO(dev)->gen >= 4) { - sdvox = SDVO_BORDER_ENABLE; + if (IS_I965G(dev)) { + 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; @@ -1150,18 +1196,16 @@ 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 (INTEL_INFO(dev)->gen >= 4) { + if (IS_I965G(dev)) { /* 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 |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT; + sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; } - if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL) + if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL) sdvox |= SDVO_STALL_SELECT; intel_sdvo_write_sdvox(intel_sdvo, sdvox); } @@ -1170,7 +1214,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 = to_intel_sdvo(encoder); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); u32 temp; @@ -1216,7 +1260,8 @@ 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 intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; @@ -1240,38 +1285,7 @@ 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) { - 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; + return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps)); } /* No use! */ @@ -1375,33 +1389,22 @@ 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 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)) + 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)) return connector; } } } - return NULL; } @@ -1421,66 +1424,65 @@ 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 intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); - enum drm_connector_status status; - struct edid *edid; + 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; - edid = intel_sdvo_get_edid(connector); + edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus); + /* This is only applied to SDVO cards with multiple outputs */ if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) { - u8 ddc, saved_ddc = intel_sdvo->ddc_bus; - + uint8_t saved_ddc, temp_ddc; + saved_ddc = intel_sdvo->ddc_bus; + temp_ddc = intel_sdvo->ddc_bus >> 1; /* * Don't use the 1 as the argument of DDC bus switch to get * the EDID. It is used for SDVO SPD ROM. */ - for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) { - intel_sdvo->ddc_bus = ddc; - edid = intel_sdvo_get_edid(connector); - if (edid) + 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; 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) - edid = intel_sdvo_get_analog_edid(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); - 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 (edid->input & DRM_EDID_INPUT_DIGITAL) { - status = connector_status_connected; + if (is_digital && need_digital) 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; - kfree(edid); - } + } else + status = connector_status_disconnected; + kfree(edid); + return status; } @@ -1488,12 +1490,13 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector, bool force) { uint16_t response; - struct intel_sdvo *intel_sdvo = intel_attached_sdvo(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 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 */ @@ -1502,9 +1505,7 @@ 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 [%x]\n", - response & 0xff, response >> 8, - intel_sdvo_connector->output_flag); + DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8); if (response == 0) return connector_status_disconnected; @@ -1537,10 +1538,12 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) { - struct edid *edid; + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + int num_modes; /* set the bus switch and get the modes */ - edid = intel_sdvo_get_edid(connector); + num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus); /* * Mac mini hack. On this device, the DVI-I connector shares one DDC @@ -1548,14 +1551,12 @@ 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 (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); + 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); } } @@ -1626,7 +1627,8 @@ struct drm_display_mode sdvo_tv_modes[] = { static void intel_sdvo_get_tv_modes(struct drm_connector *connector) { - struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_sdvo_sdtv_resolution_request tv_res; uint32_t reply = 0, format_map = 0; int i; @@ -1642,8 +1644,7 @@ 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)) @@ -1661,7 +1662,8 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) { - struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct drm_i915_private *dev_priv = connector->dev->dev_private; struct drm_display_mode *newmode; @@ -1670,7 +1672,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->i2c); + intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus); if (list_empty(&connector->probed_modes) == false) goto end; @@ -1691,10 +1693,6 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) 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; } @@ -1777,7 +1775,8 @@ intel_sdvo_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { - struct intel_sdvo *intel_sdvo = intel_attached_sdvo(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); uint16_t temp_value; uint8_t cmd; @@ -1880,8 +1879,9 @@ intel_sdvo_set_property(struct drm_connector *connector, done: - if (intel_sdvo->base.base.crtc) { - struct drm_crtc *crtc = intel_sdvo->base.base.crtc; + if (encoder->crtc) { + struct drm_crtc *crtc = encoder->crtc; + drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); } @@ -1909,18 +1909,20 @@ 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_best_encoder, + .best_encoder = intel_attached_encoder, }; static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) { - struct intel_sdvo *intel_sdvo = to_intel_sdvo(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); 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); } @@ -1988,39 +1990,54 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, intel_sdvo_guess_ddc_bus(sdvo); } -static void -intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, - struct intel_sdvo *sdvo, u32 reg) +static bool +intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device) { - struct sdvo_device_mapping *mapping; - u8 pin, speed; + 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); +} - if (IS_SDVOB(reg)) - mapping = &dev_priv->sdvo_mappings[0]; - else - mapping = &dev_priv->sdvo_mappings[1]; +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; - pin = GMBUS_PORT_DPB; - speed = GMBUS_RATE_1MHZ >> 8; - if (mapping->initialized) { - pin = mapping->i2c_pin; - speed = mapping->i2c_speed; + 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; } - sdvo->i2c = &dev_priv->gmbus[pin].adapter; - intel_gmbus_set_speed(sdvo->i2c, speed); - intel_gmbus_force_bit(sdvo->i2c, true); + return NULL; } -static bool -intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device) +static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int 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); + 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); } +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) { @@ -2059,29 +2076,26 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) } static void -intel_sdvo_connector_init(struct intel_sdvo_connector *connector, - struct intel_sdvo *encoder) +intel_sdvo_connector_init(struct drm_encoder *encoder, + struct drm_connector *connector) { - drm_connector_init(encoder->base.base.dev, - &connector->base.base, - &intel_sdvo_connector_funcs, - connector->base.base.connector_type); + drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs, + connector->connector_type); - drm_connector_helper_add(&connector->base.base, - &intel_sdvo_connector_helper_funcs); + drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); - connector->base.base.interlace_allowed = 0; - connector->base.base.doublescan_allowed = 0; - connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + connector->display_info.subpixel_order = SubPixelHorizontalRGB; - intel_connector_attach_encoder(&connector->base, &encoder->base); - drm_sysfs_connector_add(&connector->base.base); + drm_mode_connector_attach_encoder(connector, encoder); + drm_sysfs_connector_add(connector); } static bool intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_sdvo->base.base; + struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *intel_sdvo_connector; @@ -2116,7 +2130,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(intel_sdvo_connector, intel_sdvo); + intel_sdvo_connector_init(encoder, connector); return true; } @@ -2124,83 +2138,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.base; - struct drm_connector *connector; - struct intel_connector *intel_connector; - struct intel_sdvo_connector *intel_sdvo_connector; + struct drm_encoder *encoder = &intel_sdvo->base.enc; + 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(intel_sdvo_connector, intel_sdvo); + intel_sdvo_connector_init(encoder, connector); - 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(connector); + intel_sdvo_destroy_enhance_property(connector); + kfree(intel_sdvo_connector); return false; } static bool intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_sdvo->base.base; - struct drm_connector *connector; - struct intel_connector *intel_connector; - struct intel_sdvo_connector *intel_sdvo_connector; + struct drm_encoder *encoder = &intel_sdvo->base.enc; + 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(intel_sdvo_connector, - intel_sdvo); - return true; + intel_sdvo_connector_init(encoder, connector); + return true; } static bool intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_sdvo->base.base; - struct drm_connector *connector; - struct intel_connector *intel_connector; - struct intel_sdvo_connector *intel_sdvo_connector; + struct drm_encoder *encoder = &intel_sdvo->base.enc; + 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) @@ -2208,28 +2222,29 @@ 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(intel_sdvo_connector, intel_sdvo); - if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) + intel_sdvo_connector_init(encoder, connector); + if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) goto err; return true; err: - intel_sdvo_destroy(connector); + intel_sdvo_destroy_enhance_property(connector); + kfree(intel_sdvo_connector); return false; } @@ -2294,7 +2309,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.base.dev; + struct drm_device *dev = intel_sdvo->base.enc.dev; struct intel_sdvo_tv_format format; uint32_t format_map, i; @@ -2360,7 +2375,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.base.dev; + struct drm_device *dev = intel_sdvo->base.enc.dev; struct drm_connector *connector = &intel_sdvo_connector->base.base; uint16_t response, data_value[2]; @@ -2489,7 +2504,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.base.dev; + struct drm_device *dev = intel_sdvo->base.enc.dev; struct drm_connector *connector = &intel_sdvo_connector->base.base; uint16_t response, data_value[2]; @@ -2507,10 +2522,11 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, uint16_t response; } enhancements; - enhancements.response = 0; - intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, - &enhancements, sizeof(enhancements)); + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, + &enhancements, sizeof(enhancements))) + return false; + if (enhancements.response == 0) { DRM_DEBUG_KMS("No enhancement is supported\n"); return true; @@ -2522,43 +2538,7 @@ 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) @@ -2566,66 +2546,95 @@ 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); - intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1; - intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg); + 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; /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { - u8 byte; - - if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) { + if (!intel_sdvo_read_byte(intel_sdvo, i, &ch[i])) { DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n", IS_SDVOB(sdvo_reg) ? 'B' : 'C'); - goto err; + goto err_i2c; } } - if (IS_SDVOB(sdvo_reg)) + /* 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"); dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; - else + } 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"); 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; - drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); + /* 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); /* In default case sdvo lvds is false */ if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) - goto err; + goto err_enc; 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; + goto err_enc; } 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; + goto err_enc; if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo, &intel_sdvo->pixel_clock_min, &intel_sdvo->pixel_clock_max)) - goto err; + goto err_enc; DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " @@ -2645,9 +2654,16 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); return true; -err: - drm_encoder_cleanup(&intel_encoder->base); - i2c_del_adapter(&intel_sdvo->ddc); +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: kfree(intel_sdvo); return false; diff --git a/trunk/drivers/gpu/drm/i915/intel_tv.c b/trunk/drivers/gpu/drm/i915/intel_tv.c index 2f7681989316..4a117e318a73 100644 --- a/trunk/drivers/gpu/drm/i915/intel_tv.c +++ b/trunk/drivers/gpu/drm/i915/intel_tv.c @@ -48,7 +48,7 @@ struct intel_tv { struct intel_encoder base; int type; - const char *tv_format; + 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 { - const char *name; + char *name; int clock; int refresh; /* in millihertz (for precision) */ u32 oversample; @@ -900,14 +900,7 @@ static const struct tv_mode tv_modes[] = { static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder) { - 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); + return container_of(enc_to_intel_encoder(encoder), struct intel_tv, base); } static void @@ -929,7 +922,7 @@ intel_tv_dpms(struct drm_encoder *encoder, int mode) } static const struct tv_mode * -intel_tv_mode_lookup(const char *tv_format) +intel_tv_mode_lookup (char *tv_format) { int i; @@ -943,23 +936,22 @@ intel_tv_mode_lookup(const 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 intel_tv *intel_tv = intel_attached_tv(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); 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; } @@ -1139,7 +1131,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, color_conversion->av); } - if (INTEL_INFO(dev)->gen >= 4) + if (IS_I965G(dev)) I915_WRITE(TV_CLR_KNOBS, 0x00404000); else I915_WRITE(TV_CLR_KNOBS, 0x00606000); @@ -1165,12 +1157,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_GEN2(dev)) + if (!IS_I9XX(dev)) intel_wait_for_vblank(dev, intel_crtc->pipe); - I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE); + I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); /* Wait for vblank for the disable to take effect. */ - intel_wait_for_pipe_off(dev, intel_crtc->pipe); + intel_wait_for_vblank(dev, intel_crtc->pipe); /* Filter ctl must be set before TV_WIN_SIZE */ I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); @@ -1204,7 +1196,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, I915_READ(TV_DAC) & TV_DAC_SAVE); + I915_WRITE(TV_DAC, 0); I915_WRITE(TV_CTL, tv_ctl); } @@ -1236,13 +1228,15 @@ 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.base; + struct drm_encoder *encoder = &intel_tv->base.enc; 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; + int type = DRM_MODE_CONNECTOR_Unknown; + + tv_dac = I915_READ(TV_DAC); /* Disable TV interrupts around load detect or we'll recurse */ spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); @@ -1250,14 +1244,19 @@ intel_tv_detect_type (struct intel_tv *intel_tv) PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); - 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); + /* + * 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; tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; - - tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK); + tv_dac &= ~TVDAC_SENSE_MASK; + tv_dac &= ~DAC_A_MASK; + tv_dac &= ~DAC_B_MASK; + tv_dac &= ~DAC_C_MASK; tv_dac |= (TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL | TVDAC_B_SENSE_CTL | @@ -1266,40 +1265,37 @@ 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); - intel_wait_for_vblank(intel_tv->base.base.dev, - to_intel_crtc(intel_tv->base.base.crtc)->pipe); + 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); - 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"); - } + /* + * 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; } - 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 | @@ -1315,7 +1311,8 @@ intel_tv_detect_type (struct intel_tv *intel_tv) */ static void intel_tv_find_better_format(struct drm_connector *connector) { - struct intel_tv *intel_tv = intel_attached_tv(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); int i; @@ -1347,13 +1344,14 @@ static enum drm_connector_status intel_tv_detect(struct drm_connector *connector, bool force) { struct drm_display_mode mode; - struct intel_tv *intel_tv = intel_attached_tv(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); int type; mode = reported_modes[0]; drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); - if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) { + if (encoder->crtc && encoder->crtc->enabled) { type = intel_tv_detect_type(intel_tv); } else if (force) { struct drm_crtc *crtc; @@ -1377,10 +1375,11 @@ intel_tv_detect(struct drm_connector *connector, bool force) return connector_status_connected; } -static const struct input_res { - const char *name; +static struct input_res { + char *name; int w, h; -} input_res_table[] = { +} input_res_table[] = +{ {"640x480", 640, 480}, {"800x600", 800, 600}, {"1024x768", 1024, 768}, @@ -1397,7 +1396,8 @@ static void intel_tv_chose_preferred_modes(struct drm_connector *connector, struct drm_display_mode *mode_ptr) { - struct intel_tv *intel_tv = intel_attached_tv(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480) @@ -1422,14 +1422,15 @@ static int intel_tv_get_modes(struct drm_connector *connector) { struct drm_display_mode *mode_ptr; - struct intel_tv *intel_tv = intel_attached_tv(connector); + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); 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++) { - const struct input_res *input = &input_res_table[j]; + struct input_res *input = &input_res_table[j]; unsigned int hactive_s = input->w; unsigned int vactive_s = input->h; @@ -1487,8 +1488,9 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop uint64_t val) { struct drm_device *dev = connector->dev; - struct intel_tv *intel_tv = intel_attached_tv(connector); - struct drm_crtc *crtc = intel_tv->base.base.crtc; + struct drm_encoder *encoder = intel_attached_encoder(connector); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + struct drm_crtc *crtc = encoder->crtc; int ret = 0; bool changed = false; @@ -1553,7 +1555,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_best_encoder, + .best_encoder = intel_attached_encoder, }; static const struct drm_encoder_funcs intel_tv_enc_funcs = { @@ -1605,7 +1607,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[ARRAY_SIZE(tv_modes)]; + char **tv_format_names; int i, initial_mode = 0; if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) @@ -1659,15 +1661,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->base, &intel_tv_enc_funcs, + drm_encoder_init(dev, &intel_encoder->enc, &intel_tv_enc_funcs, DRM_MODE_ENCODER_TVDAC); - intel_connector_attach_encoder(intel_connector, intel_encoder); + drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc); 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->base.possible_crtcs = ((1 << 0) | (1 << 1)); - intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT); + intel_encoder->enc.possible_crtcs = ((1 << 0) | (1 << 1)); + intel_encoder->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT); intel_tv->type = DRM_MODE_CONNECTOR_Unknown; /* BIOS margin values */ @@ -1676,19 +1678,21 @@ 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 = tv_modes[initial_mode].name; + intel_tv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); - drm_encoder_helper_add(&intel_encoder->base, &intel_tv_helper_funcs); + drm_encoder_helper_add(&intel_encoder->enc, &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] = (char *)tv_modes[i].name; - drm_mode_create_tv_properties(dev, - ARRAY_SIZE(tv_modes), - tv_format_names); + tv_format_names[i] = 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); @@ -1704,5 +1708,6 @@ 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); } diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c b/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c index fc737037f751..87186a4bbf03 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -558,10 +558,8 @@ nouveau_connector_get_modes(struct drm_connector *connector) if (nv_encoder->dcb->type == OUTPUT_LVDS && (nv_encoder->dcb->lvdsconf.use_straps_for_mode || dev_priv->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) { - struct drm_display_mode mode; - - nouveau_bios_fp_mode(dev, &mode); - nv_connector->native_mode = drm_mode_duplicate(dev, &mode); + nv_connector->native_mode = drm_mode_create(dev); + nouveau_bios_fp_mode(dev, nv_connector->native_mode); } /* Find the native mode if this is a digital panel, if we didn't diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/trunk/drivers/gpu/drm/nouveau/nouveau_fbcon.c index d2047713dc59..dbd30b2e43fd 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -352,7 +352,6 @@ 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; } diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_gem.c b/trunk/drivers/gpu/drm/nouveau/nouveau_gem.c index 19620a6709f5..ead7b8fc53fc 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -167,9 +167,11 @@ 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; } diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_mem.c b/trunk/drivers/gpu/drm/nouveau/nouveau_mem.c index 9689d4147686..c14466ba69ba 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -355,7 +355,8 @@ nouveau_mem_reset_agp(struct drm_device *dev) /* First of all, disable fast writes, otherwise if it's * already enabled in the AGP bridge and we disable the card's * AGP controller we might be locking ourselves out of it. */ - if (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) { + if ((nv_rd32(dev, NV04_PBUS_PCI_NV_19) | + dev->agp->mode) & PCI_AGP_COMMAND_FW) { struct drm_agp_info info; struct drm_agp_mode mode; diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_notifier.c b/trunk/drivers/gpu/drm/nouveau/nouveau_notifier.c index 3c9964a8fbad..3ec181ff50ce 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -79,7 +79,6 @@ 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); } diff --git a/trunk/drivers/gpu/drm/radeon/atombios.h b/trunk/drivers/gpu/drm/radeon/atombios.h index fe359a239df3..1bc72c3190a9 100644 --- a/trunk/drivers/gpu/drm/radeon/atombios.h +++ b/trunk/drivers/gpu/drm/radeon/atombios.h @@ -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 diff --git a/trunk/drivers/gpu/drm/radeon/r600.c b/trunk/drivers/gpu/drm/radeon/r600.c index 7a04959ba0ee..afc18d87fdca 100644 --- a/trunk/drivers/gpu/drm/radeon/r600.c +++ b/trunk/drivers/gpu/drm/radeon/r600.c @@ -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 (scratch(0x%04X)=0x%08X)\n", + DRM_ERROR("radeon: ib test failed (sracth(0x%04X)=0x%08X)\n", scratch, tmp); r = -EINVAL; } @@ -3528,8 +3528,7 @@ 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) && - rdev->vram_scratch.ptr) { + if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) { void __iomem *ptr = (void *)rdev->vram_scratch.ptr; u32 tmp; diff --git a/trunk/drivers/gpu/drm/radeon/radeon_atombios.c b/trunk/drivers/gpu/drm/radeon/radeon_atombios.c index 68932ba7b8a4..ebae14c4b768 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_atombios.c @@ -317,15 +317,6 @@ 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) && diff --git a/trunk/drivers/gpu/drm/radeon/radeon_display.c b/trunk/drivers/gpu/drm/radeon/radeon_display.c index b92d2f2fcbed..127a395f70fb 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_display.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_display.c @@ -349,8 +349,6 @@ 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) @@ -843,9 +841,8 @@ 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); } diff --git a/trunk/drivers/gpu/drm/radeon/radeon_fb.c b/trunk/drivers/gpu/drm/radeon/radeon_fb.c index 9cdf6a35bc2c..c74a8b20d941 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_fb.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_fb.c @@ -94,10 +94,8 @@ 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); } @@ -327,6 +325,8 @@ 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,8 +338,14 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb } if (rfb->obj) { - radeonfb_destroy_pinned_object(rfb->obj); - rfb->obj = NULL; + 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); } drm_fb_helper_fini(&rfbdev->helper); drm_framebuffer_cleanup(&rfb->base); diff --git a/trunk/drivers/gpu/drm/radeon/radeon_gem.c b/trunk/drivers/gpu/drm/radeon/radeon_gem.c index d1e595d91723..c578f265b24c 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_gem.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_gem.c @@ -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; } diff --git a/trunk/drivers/gpu/drm/radeon/radeon_kms.c b/trunk/drivers/gpu/drm/radeon/radeon_kms.c index 8fbbe1c6ebbd..5eee3c41d124 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_kms.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_kms.c @@ -203,10 +203,6 @@ 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; } diff --git a/trunk/drivers/gpu/drm/ttm/ttm_bo_util.c b/trunk/drivers/gpu/drm/ttm/ttm_bo_util.c index 3451a82adba7..7cffb3e04232 100644 --- a/trunk/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/trunk/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -351,7 +351,6 @@ 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); diff --git a/trunk/drivers/gpu/drm/ttm/ttm_page_alloc.c b/trunk/drivers/gpu/drm/ttm/ttm_page_alloc.c index b1e02fffd3cc..ca904799f018 100644 --- a/trunk/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/trunk/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -69,7 +69,7 @@ struct ttm_page_pool { spinlock_t lock; bool fill_lock; struct list_head list; - gfp_t gfp_flags; + int 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, gfp_t gfp_flags, +static int ttm_alloc_new_pages(struct list_head *pages, int 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; - gfp_t gfp_flags = GFP_USER; + int 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) +void ttm_page_alloc_fini() { int i; diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index f2942b3c59c0..e645f44e4302 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -148,16 +148,13 @@ static struct pci_device_id vmw_pci_id_list[] = { {0, 0, 0} }; -static int enable_fbdev; +static char *vmw_devname = "vmwgfx"; 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"); @@ -195,6 +192,8 @@ 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"); @@ -207,36 +206,10 @@ 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); -} - -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; + vmw_kms_restore_vga(dev_priv); } -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; @@ -255,7 +228,6 @@ 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); @@ -272,8 +244,6 @@ 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); @@ -373,6 +343,17 @@ 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) { @@ -388,52 +369,26 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) goto out_no_device; } } - ret = vmw_kms_init(dev_priv); + ret = vmw_request_device(dev_priv); if (unlikely(ret != 0)) - goto out_no_kms; + goto out_no_device; + vmw_kms_init(dev_priv); vmw_overlay_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; - } - } + vmw_fb_init(dev_priv); 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_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: + if (dev_priv->capabilities & SVGA_CAP_IRQMASK) + drm_irq_uninstall(dev_priv->dev); + if (dev->devname == vmw_devname) + dev->devname = NULL; +out_no_irq: ttm_object_device_release(&dev_priv->tdev); out_err4: iounmap(dev_priv->mmio_virt); @@ -460,20 +415,19 @@ static int vmw_driver_unload(struct drm_device *dev) unregister_pm_notifier(&dev_priv->pm_nb); - 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_fb_close(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, @@ -546,7 +500,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_drv != cmd)) { + if (unlikely(ioctl->cmd != cmd)) { DRM_ERROR("Invalid command format, ioctl %d\n", nr - DRM_COMMAND_BASE); return -EINVAL; @@ -597,8 +551,6 @@ 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, @@ -610,7 +562,7 @@ static int vmw_master_create(struct drm_device *dev, if (unlikely(vmaster == NULL)) return -ENOMEM; - vmw_master_init(vmaster); + ttm_lock_init(&vmaster->lock); ttm_lock_set_kill(&vmaster->lock, true, SIGTERM); master->driver_priv = vmaster; @@ -637,16 +589,6 @@ 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); @@ -675,13 +617,7 @@ static int vmw_master_set(struct drm_device *dev, return 0; out_no_active_lock: - 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); - } + vmw_release_device(dev_priv); return ret; } @@ -701,7 +637,6 @@ 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"); @@ -710,23 +645,11 @@ 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); - if (dev_priv->enable_fb) - vmw_fb_on(dev_priv); + vmw_fb_on(dev_priv); } @@ -754,16 +677,15 @@ 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; } @@ -774,98 +696,21 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, * These might not be needed with the virtual SVGA device. */ -static int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state) +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; } -static int vmw_pci_resume(struct pci_dev *pdev) +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, @@ -877,7 +722,6 @@ 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), @@ -899,16 +743,15 @@ 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, - .driver = { - .pm = &vmw_pm_ops - } - }, + .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, .desc = VMWGFX_DRIVER_DESC, .date = VMWGFX_DRIVER_DATE, @@ -942,7 +785,3 @@ 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"); diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 9d55fa8cd0fe..429f917b60bf 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -39,9 +39,9 @@ #include "ttm/ttm_execbuf_util.h" #include "ttm/ttm_module.h" -#define VMWGFX_DRIVER_DATE "20100927" +#define VMWGFX_DRIVER_DATE "20100209" #define VMWGFX_DRIVER_MAJOR 1 -#define VMWGFX_DRIVER_MINOR 4 +#define VMWGFX_DRIVER_MINOR 2 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) @@ -151,8 +151,6 @@ 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 { @@ -279,7 +277,6 @@ struct vmw_private { bool stealth; bool is_opened; - bool enable_fb; /** * Master management. @@ -288,10 +285,6 @@ 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) @@ -326,9 +319,6 @@ 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 */ @@ -521,11 +511,6 @@ 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 diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index b27a9f2887d2..870967a97c15 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -144,13 +144,6 @@ 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; } @@ -212,9 +205,6 @@ 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); @@ -625,11 +615,6 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv, if (unlikely(ret != 0)) goto err_unlock; - if (bo->mem.mem_type == TTM_PL_VRAM && - bo->mem.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 */ diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 0fe31766e4cf..e6a1eb7ea954 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -106,7 +106,6 @@ 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; @@ -176,8 +175,6 @@ 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); diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 570d57775a58..1c7a316454d8 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -54,9 +54,6 @@ 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); diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 87c6e6156d7d..64d7f47df868 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -332,55 +332,18 @@ 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 *vfbs = + struct vmw_framebuffer_surface *vfb = vmw_framebuffer_to_vfbs(framebuffer); - struct vmw_master *vmaster = vmw_master(vfbs->master); - - 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); + cancel_delayed_work_sync(&vfb->d_work); drm_framebuffer_cleanup(framebuffer); - vmw_surface_unreference(&vfbs->surface); + vmw_surface_unreference(&vfb->surface); - kfree(vfbs); + kfree(framebuffer); } static void vmw_framebuffer_present_fs_callback(struct work_struct *work) @@ -399,12 +362,6 @@ 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; @@ -435,20 +392,17 @@ static void vmw_framebuffer_present_fs_callback(struct work_struct *work) 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; @@ -456,13 +410,6 @@ 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)) { @@ -478,7 +425,6 @@ 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; } @@ -496,7 +442,6 @@ 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; } @@ -516,7 +461,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; } @@ -526,57 +471,16 @@ static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { .create_handle = vmw_framebuffer_create_handle, }; -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) +int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, + struct vmw_surface *surface, + struct vmw_framebuffer **out, + unsigned width, unsigned height) { 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; @@ -594,22 +498,16 @@ static 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 = 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.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.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; @@ -646,25 +544,18 @@ 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; @@ -679,7 +570,6 @@ 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; } @@ -692,7 +582,6 @@ 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; } @@ -770,25 +659,16 @@ static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb) return vmw_dmabuf_from_vram(dev_priv, vfbd->buffer); } -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) +int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, + struct vmw_dma_buffer *dmabuf, + struct vmw_framebuffer **out, + unsigned width, unsigned height) { 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; @@ -805,11 +685,12 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, goto out_err3; } - 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; + /* 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.pin = vmw_framebuffer_dmabuf_pin; vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin; vfbd->buffer = dmabuf; @@ -838,25 +719,8 @@ 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) @@ -865,8 +729,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, file_priv, surface, - &vfb, mode_cmd); + ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, + mode_cmd->width, mode_cmd->height); /* vmw_user_surface_lookup takes one ref so does new_fb */ vmw_surface_unreference(&surface); @@ -887,7 +751,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, } ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, - mode_cmd); + mode_cmd->width, mode_cmd->height); /* vmw_user_dmabuf_lookup takes one ref so does new_fb */ vmw_dmabuf_unreference(&bo); @@ -1025,9 +889,6 @@ 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); @@ -1037,19 +898,7 @@ 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; } @@ -1135,15 +984,3 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, 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; -} diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index a01c47ddb5bc..7083b1a24df3 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -27,8 +27,6 @@ #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) \ @@ -427,9 +425,7 @@ 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, @@ -445,30 +441,22 @@ 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); - 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); - } + drm_mode_probed_add(connector, mode); - ldu->pref_mode = mode; + if (ldu->pref_mode) { + list_del_init(&ldu->pref_mode->head); + drm_mode_destroy(dev, ldu->pref_mode); } + + ldu->pref_mode = mode; } for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) { - 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)) + if (vmw_ldu_connector_builtin[i].hdisplay > max_width || + vmw_ldu_connector_builtin[i].vdisplay > max_height) continue; - mode = drm_mode_duplicate(dev, bmode); + mode = drm_mode_duplicate(dev, &vmw_ldu_connector_builtin[i]); if (!mode) return 0; mode->vrefresh = drm_mode_vrefresh(mode); @@ -548,10 +536,6 @@ 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; @@ -569,24 +553,23 @@ 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) { - 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); + 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); } - return ret; + return 0; } 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; diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index c8c40e9979db..5f2d5df01e5c 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -211,7 +211,6 @@ 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, @@ -248,7 +247,6 @@ 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; } @@ -408,7 +406,6 @@ 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) @@ -476,7 +473,6 @@ 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; } diff --git a/trunk/drivers/gpu/vga/vgaarb.c b/trunk/drivers/gpu/vga/vgaarb.c index f366f968155a..b87569e96b16 100644 --- a/trunk/drivers/gpu/vga/vgaarb.c +++ b/trunk/drivers/gpu/vga/vgaarb.c @@ -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); } -static void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace) +void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace) { struct vga_device *vgadev; unsigned long flags; diff --git a/trunk/drivers/hwmon/Kconfig b/trunk/drivers/hwmon/Kconfig index 97499d00615a..4d4d09bdec0a 100644 --- a/trunk/drivers/hwmon/Kconfig +++ b/trunk/drivers/hwmon/Kconfig @@ -409,7 +409,7 @@ config SENSORS_CORETEMP config SENSORS_PKGTEMP tristate "Intel processor package temperature sensor" - depends on X86 && EXPERIMENTAL + depends on X86 && PCI && EXPERIMENTAL help If you say yes here you get support for the package level temperature sensor inside your CPU. Check documentation/driver for details. diff --git a/trunk/drivers/hwmon/coretemp.c b/trunk/drivers/hwmon/coretemp.c index baa842a80b4b..de8111114f46 100644 --- a/trunk/drivers/hwmon/coretemp.c +++ b/trunk/drivers/hwmon/coretemp.c @@ -423,18 +423,9 @@ 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); - - /* - * 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; - } +#endif mutex_lock(&pdev_list_mutex); @@ -491,22 +482,14 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) static void coretemp_device_remove(unsigned int cpu) { - struct pdev_entry *p; - unsigned int i; - + struct pdev_entry *p, *n; mutex_lock(&pdev_list_mutex); - 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; + 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); + } } mutex_unlock(&pdev_list_mutex); } @@ -544,21 +527,30 @@ static int __init coretemp_init(void) if (err) goto exit; - for_each_online_cpu(i) - coretemp_device_add(i); - -#ifndef CONFIG_HOTPLUG_CPU + 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); + } + } if (list_empty(&pdev_list)) { err = -ENODEV; goto exit_driver_unreg; } -#endif register_hotcpu_notifier(&coretemp_cpu_notifier); return 0; -#ifndef CONFIG_HOTPLUG_CPU exit_driver_unreg: +#ifndef CONFIG_HOTPLUG_CPU platform_driver_unregister(&coretemp_driver); #endif exit: diff --git a/trunk/drivers/hwmon/lis3lv02d.c b/trunk/drivers/hwmon/lis3lv02d.c index fc591ae53107..6138f036b159 100644 --- a/trunk/drivers/hwmon/lis3lv02d.c +++ b/trunk/drivers/hwmon/lis3lv02d.c @@ -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.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev && + if (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->pdata && dev->whoami == WAI_8B) + if (dev->whoami == WAI_8B) thread_fn = lis302dl_interrupt_thread1_8b; else thread_fn = NULL; diff --git a/trunk/drivers/hwmon/pkgtemp.c b/trunk/drivers/hwmon/pkgtemp.c index f11903936c8b..74157fcda6ed 100644 --- a/trunk/drivers/hwmon/pkgtemp.c +++ b/trunk/drivers/hwmon/pkgtemp.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -223,7 +224,7 @@ static int __devinit pkgtemp_probe(struct platform_device *pdev) err = sysfs_create_group(&pdev->dev.kobj, &pkgtemp_group); if (err) - goto exit_dev; + goto exit_free; data->hwmon_dev = hwmon_device_register(&pdev->dev); if (IS_ERR(data->hwmon_dev)) { @@ -237,8 +238,6 @@ 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: @@ -251,7 +250,6 @@ 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; @@ -283,10 +281,9 @@ 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); - - if (!cpu_has(c, X86_FEATURE_PTS)) - return 0; +#endif mutex_lock(&pdev_list_mutex); @@ -342,18 +339,17 @@ static int __cpuinit pkgtemp_device_add(unsigned int cpu) #ifdef CONFIG_HOTPLUG_CPU static void pkgtemp_device_remove(unsigned int cpu) { - struct pdev_entry *p; + struct pdev_entry *p, *n; unsigned int i; int err; mutex_lock(&pdev_list_mutex); - list_for_each_entry(p, &pdev_list, list) { + list_for_each_entry_safe(p, n, &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) { @@ -362,7 +358,7 @@ static void pkgtemp_device_remove(unsigned int cpu) break; } } - return; + break; } mutex_unlock(&pdev_list_mutex); } @@ -403,6 +399,11 @@ 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; diff --git a/trunk/drivers/staging/ti-st/st.h b/trunk/drivers/staging/ti-st/st.h index 1b3060eb2921..9952579425b9 100644 --- a/trunk/drivers/staging/ti-st/st.h +++ b/trunk/drivers/staging/ti-st/st.h @@ -80,4 +80,5 @@ 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 */ diff --git a/trunk/drivers/staging/ti-st/st_core.c b/trunk/drivers/staging/ti-st/st_core.c index b85d8bfdf600..063c9b1db1ab 100644 --- a/trunk/drivers/staging/ti-st/st_core.c +++ b/trunk/drivers/staging/ti-st/st_core.c @@ -38,6 +38,7 @@ #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 */ @@ -580,7 +581,7 @@ long st_register(struct st_proto_s *new_proto) long err = 0; unsigned long flags = 0; - st_kim_ref(&st_gdata, 0); + st_kim_ref(&st_gdata); 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) { @@ -712,7 +713,7 @@ long st_unregister(enum proto_type type) pr_debug("%s: %d ", __func__, type); - st_kim_ref(&st_gdata, 0); + st_kim_ref(&st_gdata); if (type < ST_BT || type >= ST_MAX) { pr_err(" protocol %d not supported", type); return -EPROTONOSUPPORT; @@ -766,7 +767,7 @@ long st_write(struct sk_buff *skb) #endif long len; - st_kim_ref(&st_gdata, 0); + st_kim_ref(&st_gdata); if (unlikely(skb == NULL || st_gdata == NULL || st_gdata->tty == NULL)) { pr_err("data/tty unavailable to perform write"); @@ -817,7 +818,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, 0); + st_kim_ref(&st_gdata); st_gdata->tty = tty; tty->disc_data = st_gdata; diff --git a/trunk/drivers/staging/ti-st/st_core.h b/trunk/drivers/staging/ti-st/st_core.h index 8601320a679e..e0c32d149f5f 100644 --- a/trunk/drivers/staging/ti-st/st_core.h +++ b/trunk/drivers/staging/ti-st/st_core.h @@ -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 **, int); +void st_kim_ref(struct st_data_s **); #define GPS_STUB_TEST #ifdef GPS_STUB_TEST diff --git a/trunk/drivers/staging/ti-st/st_kim.c b/trunk/drivers/staging/ti-st/st_kim.c index 9e99463f76e8..b4a6c7fdc4e6 100644 --- a/trunk/drivers/staging/ti-st/st_kim.c +++ b/trunk/drivers/staging/ti-st/st_kim.c @@ -72,25 +72,10 @@ 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 @@ -368,7 +353,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(0); + kim_pdev = st_get_plat_device(); kim_gdata = dev_get_drvdata(&kim_pdev->dev); if (kim_gdata->gpios[type] == -1) { @@ -589,12 +574,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, int id) +void st_kim_ref(struct st_data_s **core_data) { struct platform_device *pdev; struct kim_data_s *kim_gdata; /* get kim_gdata reference from platform device */ - pdev = st_get_plat_device(id); + pdev = st_get_plat_device(); kim_gdata = dev_get_drvdata(&pdev->dev); *core_data = kim_gdata->core_data; } @@ -638,7 +623,6 @@ 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"); diff --git a/trunk/drivers/usb/core/Kconfig b/trunk/drivers/usb/core/Kconfig index 9eed5b52d9de..7e594449600e 100644 --- a/trunk/drivers/usb/core/Kconfig +++ b/trunk/drivers/usb/core/Kconfig @@ -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 (autosuspend) and wakeup" + bool "USB runtime power management (suspend/resume and wakeup)" depends on USB && PM_RUNTIME help If you say Y here, you can use driver calls or the sysfs - "power/control" file to enable or disable autosuspend for - individual USB peripherals (see + "power/level" file to suspend or resume individual USB + peripherals and to enable or disable autosuspend (see Documentation/usb/power-management.txt for more details). Also, USB "remote wakeup" signaling is supported, whereby some diff --git a/trunk/drivers/usb/core/file.c b/trunk/drivers/usb/core/file.c index 1e6ccef2cf0c..f06f5dbc8cdc 100644 --- a/trunk/drivers/usb/core/file.c +++ b/trunk/drivers/usb/core/file.c @@ -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; + int retval = -EINVAL; int minor_base = class_driver->minor_base; - int minor; + int minor = 0; char name[20]; char *temp; @@ -173,17 +173,12 @@ int usb_register_dev(struct usb_interface *intf, */ minor_base = 0; #endif + intf->minor = -1; - if (class_driver->fops == NULL) - return -EINVAL; - if (intf->minor >= 0) - return -EADDRINUSE; - - retval = init_usb_class(); - if (retval) - return retval; + dbg ("looking for a minor, starting at %d", minor_base); - dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base); + if (class_driver->fops == NULL) + goto exit; down_write(&minor_rwsem); for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) { @@ -191,12 +186,20 @@ int usb_register_dev(struct usb_interface *intf, continue; usb_minors[minor] = class_driver->fops; - intf->minor = minor; + + retval = 0; break; } up_write(&minor_rwsem); - if (intf->minor < 0) - return -EXFULL; + + if (retval) + goto exit; + + retval = init_usb_class(); + if (retval) + goto exit; + + intf->minor = minor; /* create a usb class device for this usb interface */ snprintf(name, sizeof(name), class_driver->name, minor - minor_base); @@ -210,11 +213,11 @@ int usb_register_dev(struct usb_interface *intf, "%s", temp); if (IS_ERR(intf->usb_dev)) { down_write(&minor_rwsem); - usb_minors[minor] = NULL; - intf->minor = -1; + usb_minors[intf->minor] = NULL; up_write(&minor_rwsem); retval = PTR_ERR(intf->usb_dev); } +exit: return retval; } EXPORT_SYMBOL_GPL(usb_register_dev); diff --git a/trunk/drivers/usb/core/message.c b/trunk/drivers/usb/core/message.c index 9f0ce7de0e36..844683e50383 100644 --- a/trunk/drivers/usb/core/message.c +++ b/trunk/drivers/usb/core/message.c @@ -1802,7 +1802,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) 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, diff --git a/trunk/drivers/usb/musb/cppi_dma.c b/trunk/drivers/usb/musb/cppi_dma.c index 5ab5bb89bae3..59dc3d351b60 100644 --- a/trunk/drivers/usb/musb/cppi_dma.c +++ b/trunk/drivers/usb/musb/cppi_dma.c @@ -322,7 +322,6 @@ 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; diff --git a/trunk/drivers/usb/musb/musb_gadget.c b/trunk/drivers/usb/musb/musb_gadget.c index d065e23f123e..6fca870e957e 100644 --- a/trunk/drivers/usb/musb/musb_gadget.c +++ b/trunk/drivers/usb/musb/musb_gadget.c @@ -300,11 +300,6 @@ 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); @@ -312,6 +307,11 @@ 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->actual, - request_size); + request->dma, + request->length); 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->actual, - request_size); + request->dma, + request->length); #endif } #endif @@ -501,14 +501,26 @@ void musb_g_tx(struct musb *musb, u8 epnum) request->zero = 0; } - 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; - } + /* ... 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; } } @@ -556,19 +568,11 @@ 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; + struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out; void __iomem *epio = musb->endpoints[epnum].regs; unsigned fifo_count = 0; - u16 len; + u16 len = musb_ep->packet_sz; 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) { @@ -643,8 +647,8 @@ static void rxstate(struct musb *musb, struct musb_request *req) */ csr |= MUSB_RXCSR_DMAENAB; - csr |= MUSB_RXCSR_AUTOCLEAR; #ifdef USE_MODE1 + csr |= MUSB_RXCSR_AUTOCLEAR; /* csr |= MUSB_RXCSR_DMAMODE; */ /* this special sequence (enabling and then @@ -659,11 +663,10 @@ 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 - request->actual, + transfer_size = min(request->length, channel->max_len); #else - transfer_size = min(request->length - request->actual, - (unsigned)len); + transfer_size = len; #endif if (transfer_size <= musb_ep->packet_sz) musb_ep->dma->desired_mode = 0; @@ -737,15 +740,9 @@ 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; + struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_out; 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); @@ -1084,7 +1081,7 @@ struct free_record { /* * Context: controller locked, IRQs blocked. */ -void musb_ep_restart(struct musb *musb, struct musb_request *req) +static 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", diff --git a/trunk/drivers/usb/musb/musb_gadget.h b/trunk/drivers/usb/musb/musb_gadget.h index 572b1da7f2dc..c8b140325d82 100644 --- a/trunk/drivers/usb/musb/musb_gadget.h +++ b/trunk/drivers/usb/musb/musb_gadget.h @@ -105,6 +105,4 @@ 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 */ diff --git a/trunk/drivers/usb/musb/musb_gadget_ep0.c b/trunk/drivers/usb/musb/musb_gadget_ep0.c index 6dd03f4c5f49..59bef8f3a358 100644 --- a/trunk/drivers/usb/musb/musb_gadget_ep0.c +++ b/trunk/drivers/usb/musb/musb_gadget_ep0.c @@ -261,7 +261,6 @@ __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; @@ -303,14 +302,6 @@ __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; diff --git a/trunk/drivers/usb/musb/musb_host.c b/trunk/drivers/usb/musb/musb_host.c index 9e65c47cc98b..877d20b1dff9 100644 --- a/trunk/drivers/usb/musb/musb_host.c +++ b/trunk/drivers/usb/musb/musb_host.c @@ -660,12 +660,6 @@ 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); diff --git a/trunk/fs/ocfs2/acl.c b/trunk/fs/ocfs2/acl.c index 391915093fe1..a76e0aa5cd3f 100644 --- a/trunk/fs/ocfs2/acl.c +++ b/trunk/fs/ocfs2/acl.c @@ -209,10 +209,7 @@ 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); diff --git a/trunk/fs/ocfs2/cluster/tcp.c b/trunk/fs/ocfs2/cluster/tcp.c index cbe2f057cc28..1361997cf205 100644 --- a/trunk/fs/ocfs2/cluster/tcp.c +++ b/trunk/fs/ocfs2/cluster/tcp.c @@ -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 = 0; + int ret; struct o2net_msg *msg = NULL; size_t veclen, caller_bytes = 0; struct kvec *vec = NULL; diff --git a/trunk/fs/ocfs2/dir.c b/trunk/fs/ocfs2/dir.c index c49f6de0e7ab..f04ebcfffc4a 100644 --- a/trunk/fs/ocfs2/dir.c +++ b/trunk/fs/ocfs2/dir.c @@ -3931,15 +3931,6 @@ 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], @@ -3948,14 +3939,15 @@ static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir, 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; - } + 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; } ocfs2_dx_dir_transfer_leaf(dir, split_hash, handle, tmp_dx_leaf, diff --git a/trunk/fs/ocfs2/dlm/dlmcommon.h b/trunk/fs/ocfs2/dlm/dlmcommon.h index 765298908f1d..4b6ae2c13b47 100644 --- a/trunk/fs/ocfs2/dlm/dlmcommon.h +++ b/trunk/fs/ocfs2/dlm/dlmcommon.h @@ -1030,7 +1030,6 @@ 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); diff --git a/trunk/fs/ocfs2/dlm/dlmdebug.c b/trunk/fs/ocfs2/dlm/dlmdebug.c index 901ca52bf86b..5efdd37dfe48 100644 --- a/trunk/fs/ocfs2/dlm/dlmdebug.c +++ b/trunk/fs/ocfs2/dlm/dlmdebug.c @@ -636,14 +636,8 @@ 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) @@ -666,7 +660,6 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos) } else dl = NULL; -bail: /* passed to seq_show */ return dl; } diff --git a/trunk/fs/ocfs2/dlm/dlmdomain.c b/trunk/fs/ocfs2/dlm/dlmdomain.c index 11a5c87fd7f7..153abb5abef0 100644 --- a/trunk/fs/ocfs2/dlm/dlmdomain.c +++ b/trunk/fs/ocfs2/dlm/dlmdomain.c @@ -693,7 +693,6 @@ 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); diff --git a/trunk/fs/ocfs2/dlm/dlmmaster.c b/trunk/fs/ocfs2/dlm/dlmmaster.c index f564b0e5f80d..ffb4c68dafa4 100644 --- a/trunk/fs/ocfs2/dlm/dlmmaster.c +++ b/trunk/fs/ocfs2/dlm/dlmmaster.c @@ -3433,43 +3433,3 @@ 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); -} diff --git a/trunk/fs/ocfs2/dlmglue.h b/trunk/fs/ocfs2/dlmglue.h index 1d596d8c4a4a..d1ce48e1b3d6 100644 --- a/trunk/fs/ocfs2/dlmglue.h +++ b/trunk/fs/ocfs2/dlmglue.h @@ -84,7 +84,6 @@ enum { OI_LS_PARENT, OI_LS_RENAME1, OI_LS_RENAME2, - OI_LS_REFLINK_TARGET, }; int ocfs2_dlm_init(struct ocfs2_super *osb); diff --git a/trunk/fs/ocfs2/ocfs2_fs.h b/trunk/fs/ocfs2/ocfs2_fs.h index fa31d05e41b7..33f1c9a8258d 100644 --- a/trunk/fs/ocfs2/ocfs2_fs.h +++ b/trunk/fs/ocfs2/ocfs2_fs.h @@ -235,31 +235,18 @@ #define OCFS2_HAS_REFCOUNT_FL (0x0010) /* Inode attributes, keep in sync with EXT2 */ -#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 */ +#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 */ /* * Extent record flags (e_node.leaf.flags) diff --git a/trunk/fs/ocfs2/ocfs2_ioctl.h b/trunk/fs/ocfs2/ocfs2_ioctl.h index 5d241505690b..2d3420af1a83 100644 --- a/trunk/fs/ocfs2/ocfs2_ioctl.h +++ b/trunk/fs/ocfs2/ocfs2_ioctl.h @@ -23,10 +23,10 @@ /* * ioctl commands */ -#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 +#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) /* * Space reservation / allocation / free ioctls and argument structure diff --git a/trunk/fs/ocfs2/refcounttree.c b/trunk/fs/ocfs2/refcounttree.c index efdd75607406..0afeda83120f 100644 --- a/trunk/fs/ocfs2/refcounttree.c +++ b/trunk/fs/ocfs2/refcounttree.c @@ -4201,9 +4201,8 @@ static int __ocfs2_reflink(struct dentry *old_dentry, goto out; } - mutex_lock_nested(&new_inode->i_mutex, I_MUTEX_CHILD); - ret = ocfs2_inode_lock_nested(new_inode, &new_bh, 1, - OI_LS_REFLINK_TARGET); + mutex_lock(&new_inode->i_mutex); + ret = ocfs2_inode_lock(new_inode, &new_bh, 1); if (ret) { mlog_errno(ret); goto out_unlock; diff --git a/trunk/fs/ocfs2/reservations.c b/trunk/fs/ocfs2/reservations.c index 3e78db361bc7..d8b6e4259b80 100644 --- a/trunk/fs/ocfs2/reservations.c +++ b/trunk/fs/ocfs2/reservations.c @@ -732,23 +732,25 @@ 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); - if (ocfs2_resv_empty(resv)) { - /* - * 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; + /* + * 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"); + /* * Try to get a window here. If it works, we must fall * through and test the bitmap . This avoids some diff --git a/trunk/fs/ocfs2/suballoc.c b/trunk/fs/ocfs2/suballoc.c index 849c2f0e0a0e..8a286f54dca1 100644 --- a/trunk/fs/ocfs2/suballoc.c +++ b/trunk/fs/ocfs2/suballoc.c @@ -357,7 +357,7 @@ int ocfs2_read_group_descriptor(struct inode *inode, struct ocfs2_dinode *di, static void ocfs2_bg_discontig_add_extent(struct ocfs2_super *osb, struct ocfs2_group_desc *bg, struct ocfs2_chain_list *cl, - u64 p_blkno, unsigned int clusters) + u64 p_blkno, u32 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_le16(clusters); + rec->e_leaf_clusters = cpu_to_le32(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)); diff --git a/trunk/fs/ocfs2/xattr.c b/trunk/fs/ocfs2/xattr.c index 06fa5e77c40e..d03469f61801 100644 --- a/trunk/fs/ocfs2/xattr.c +++ b/trunk/fs/ocfs2/xattr.c @@ -1286,11 +1286,13 @@ 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; } @@ -1314,10 +1316,8 @@ 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); diff --git a/trunk/include/drm/drmP.h b/trunk/include/drm/drmP.h index 274eaaa15c36..30e827aeba02 100644 --- a/trunk/include/drm/drmP.h +++ b/trunk/include/drm/drmP.h @@ -612,7 +612,7 @@ struct drm_gem_object { struct kref refcount; /** Handle count of this object. Each handle also holds a reference */ - atomic_t handle_count; /* number of handles on this object */ + struct kref handlecount; /** Related drm device */ struct drm_device *dev; @@ -1041,6 +1041,13 @@ 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 */ /*@} */ @@ -1151,7 +1158,6 @@ 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) */ @@ -1372,6 +1378,7 @@ 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); @@ -1412,11 +1419,12 @@ 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 drm_gem_object *obj); +void drm_gem_object_handle_free(struct kref *kref); 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); @@ -1439,12 +1447,8 @@ 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) { - struct drm_device *dev = obj->dev; - mutex_lock(&dev->struct_mutex); - kref_put(&obj->refcount, drm_gem_object_free); - mutex_unlock(&dev->struct_mutex); - } + if (obj != NULL) + kref_put(&obj->refcount, drm_gem_object_free_unlocked); } int drm_gem_handle_create(struct drm_file *file_priv, @@ -1455,7 +1459,7 @@ static inline void drm_gem_object_handle_reference(struct drm_gem_object *obj) { drm_gem_object_reference(obj); - atomic_inc(&obj->handle_count); + kref_get(&obj->handlecount); } static inline void @@ -1464,15 +1468,12 @@ 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 */ - if (atomic_dec_and_test(&obj->handle_count)) - drm_gem_object_handle_free(obj); + kref_put(&obj->handlecount, drm_gem_object_handle_free); drm_gem_object_unreference(obj); } @@ -1482,17 +1483,12 @@ 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 */ - - if (atomic_dec_and_test(&obj->handle_count)) - drm_gem_object_handle_free(obj); + kref_put(&obj->handlecount, drm_gem_object_handle_free); drm_gem_object_unreference_unlocked(obj); } diff --git a/trunk/include/drm/drm_crtc.h b/trunk/include/drm/drm_crtc.h index 15c4796fd467..3e5a51af757c 100644 --- a/trunk/include/drm/drm_crtc.h +++ b/trunk/include/drm/drm_crtc.h @@ -221,8 +221,7 @@ struct drm_framebuffer_funcs { * the semantics and arguments have a one to one mapping * on this function. */ - int (*dirty)(struct drm_framebuffer *framebuffer, - struct drm_file *file_priv, unsigned flags, + int (*dirty)(struct drm_framebuffer *framebuffer, unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips); }; diff --git a/trunk/include/drm/drm_pciids.h b/trunk/include/drm/drm_pciids.h index 883c1d439899..3a9940ef728b 100644 --- a/trunk/include/drm/drm_pciids.h +++ b/trunk/include/drm/drm_pciids.h @@ -85,6 +85,7 @@ {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}, \ @@ -102,7 +103,6 @@ {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/trunk/include/drm/intel-gtt.h b/trunk/include/drm/intel-gtt.h deleted file mode 100644 index d3c81946f613..000000000000 --- a/trunk/include/drm/intel-gtt.h +++ /dev/null @@ -1,18 +0,0 @@ -/* 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 - diff --git a/trunk/include/drm/vmwgfx_drm.h b/trunk/include/drm/vmwgfx_drm.h index 650e6bf6f69f..4d0842391edc 100644 --- a/trunk/include/drm/vmwgfx_drm.h +++ b/trunk/include/drm/vmwgfx_drm.h @@ -72,7 +72,6 @@ #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 diff --git a/trunk/mm/fremap.c b/trunk/mm/fremap.c index ec520c7b28df..46f5dacf90a2 100644 --- a/trunk/mm/fremap.c +++ b/trunk/mm/fremap.c @@ -125,6 +125,7 @@ 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; @@ -141,10 +142,6 @@ 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)) @@ -171,7 +168,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, if (!(vma->vm_flags & VM_CAN_NONLINEAR)) goto out; - if (start < vma->vm_start || start + size > vma->vm_end) + if (end <= start || start < vma->vm_start || end > vma->vm_end) goto out; /* Must set VM_NONLINEAR before any pages are populated. */ diff --git a/trunk/sound/pci/hda/patch_analog.c b/trunk/sound/pci/hda/patch_analog.c index 10bbbaf6ebc3..b697fd2a6f8b 100644 --- a/trunk/sound/pci/hda/patch_analog.c +++ b/trunk/sound/pci/hda/patch_analog.c @@ -3641,7 +3641,6 @@ 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), {} }; diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index a432e6efd19b..a1312a6c8af2 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -1594,22 +1594,12 @@ static void alc_auto_parse_digital(struct hda_codec *codec) } if (spec->autocfg.dig_in_pin) { - 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; - } - } + 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; } } diff --git a/trunk/sound/pci/oxygen/oxygen.c b/trunk/sound/pci/oxygen/oxygen.c index 6c0a11adb2a8..289cb4dacfc7 100644 --- a/trunk/sound/pci/oxygen/oxygen.c +++ b/trunk/sound/pci/oxygen/oxygen.c @@ -543,10 +543,6 @@ 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 || diff --git a/trunk/sound/pci/rme9652/hdsp.c b/trunk/sound/pci/rme9652/hdsp.c index d6fa7bfd9aa1..b92adef8e81e 100644 --- a/trunk/sound/pci/rme9652/hdsp.c +++ b/trunk/sound/pci/rme9652/hdsp.c @@ -4609,7 +4609,6 @@ 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); diff --git a/trunk/sound/pci/rme9652/hdspm.c b/trunk/sound/pci/rme9652/hdspm.c index 0c98ef9156d8..547b713d7204 100644 --- a/trunk/sound/pci/rme9652/hdspm.c +++ b/trunk/sound/pci/rme9652/hdspm.c @@ -4127,7 +4127,6 @@ 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); diff --git a/trunk/sound/soc/sh/migor.c b/trunk/sound/soc/sh/migor.c index 87e2b7fcbf17..b823a5c9b9bc 100644 --- a/trunk/sound/soc/sh/migor.c +++ b/trunk/sound/soc/sh/migor.c @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -41,12 +40,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) { @@ -181,13 +180,6 @@ 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) { @@ -208,15 +200,12 @@ 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); } diff --git a/trunk/sound/soc/soc-cache.c b/trunk/sound/soc/soc-cache.c index f6b0d2829ea9..adbc68ce9050 100644 --- a/trunk/sound/soc/soc-cache.c +++ b/trunk/sound/soc/soc-cache.c @@ -203,9 +203,8 @@ 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 < codec->reg_cache_size) - reg_cache[reg] = value; + if (!snd_soc_codec_volatile_register(codec, reg)) + reg_cache[reg] = value; if (codec->cache_only) { codec->cache_sync = 1;