]> nv-tegra.nvidia Code Review - linux-3.10.git/commitdiff
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Dec 2009 23:19:56 +0000 (15:19 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Dec 2009 23:19:56 +0000 (15:19 -0800)
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb:
  kgdb: Always process the whole breakpoint list on activate or deactivate
  kgdb: continue and warn on signal passing from gdb
  kgdb,x86: do not set kgdb_single_step on x86
  kgdb: allow for cpu switch when single stepping
  kgdb,i386: Fix corner case access to ss with NMI watch dog exception
  kgdb: Replace strstr() by strchr() for single-character needles
  kgdbts: Read buffer overflow
  kgdb: Read buffer overflow
  kgdb,x86: remove redundant test

263 files changed:
Documentation/filesystems/nilfs2.txt
arch/alpha/kernel/osf_sys.c
arch/arm/include/asm/mman.h
arch/arm/kernel/calls.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/sys_arm.c
arch/arm/mm/mmap.c
arch/avr32/include/asm/syscalls.h
arch/avr32/kernel/sys_avr32.c
arch/avr32/kernel/syscall-stubs.S
arch/blackfin/kernel/sys_bfin.c
arch/blackfin/mach-common/entry.S
arch/cris/kernel/sys_cris.c
arch/frv/kernel/sys_frv.c
arch/h8300/kernel/sys_h8300.c
arch/h8300/kernel/syscalls.S
arch/ia64/ia32/sys_ia32.c
arch/ia64/include/asm/xen/hypervisor.h
arch/ia64/kernel/sys_ia64.c
arch/ia64/pci/pci.c
arch/m32r/kernel/sys_m32r.c
arch/m32r/kernel/syscall_table.S
arch/m68k/kernel/sys_m68k.c
arch/m68knommu/kernel/sys_m68k.c
arch/m68knommu/kernel/syscalltable.S
arch/microblaze/kernel/sys_microblaze.c
arch/microblaze/kernel/syscall_table.S
arch/mips/kernel/linux32.c
arch/mips/kernel/syscall.c
arch/mn10300/include/asm/mman.h
arch/mn10300/kernel/entry.S
arch/mn10300/kernel/sys_mn10300.c
arch/parisc/kernel/sys_parisc.c
arch/powerpc/kernel/syscalls.c
arch/s390/kernel/compat_linux.c
arch/s390/kernel/sys_s390.c
arch/score/kernel/sys_score.c
arch/sh/kernel/sys_sh.c
arch/sh/mm/mmap.c
arch/sparc/include/asm/pci_64.h
arch/sparc/kernel/pci.c
arch/sparc/kernel/sys_sparc32.c
arch/sparc/kernel/sys_sparc_32.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/systbls.h
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/um/kernel/syscall.c
arch/um/sys-i386/shared/sysdep/syscalls.h
arch/x86/ia32/ia32entry.S
arch/x86/ia32/sys_ia32.c
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/sys_ia32.h
arch/x86/include/asm/syscalls.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/kernel/amd_iommu_init.c
arch/x86/kernel/sys_i386_32.c
arch/x86/kernel/sys_x86_64.c
arch/x86/kernel/syscall_table_32.S
arch/x86/pci/Makefile
arch/x86/pci/acpi.c
arch/x86/pci/amd_bus.c
arch/x86/pci/bus_numa.c [new file with mode: 0644]
arch/x86/pci/bus_numa.h [new file with mode: 0644]
arch/x86/pci/common.c
arch/x86/pci/early.c
arch/x86/pci/i386.c
arch/x86/pci/intel_bus.c [new file with mode: 0644]
arch/x86/pci/mmconfig-shared.c
arch/x86/pci/mmconfig_32.c
arch/x86/pci/mmconfig_64.c
arch/x86/xen/enlighten.c
arch/xtensa/include/asm/syscall.h
arch/xtensa/include/asm/unistd.h
arch/xtensa/kernel/syscall.c
drivers/acpi/Makefile
drivers/acpi/hest.c [new file with mode: 0644]
drivers/block/xen-blkfront.c
drivers/char/hvc_xen.c
drivers/gpu/drm/Makefile
drivers/gpu/drm/i2c/Makefile [new file with mode: 0644]
drivers/gpu/drm/i2c/ch7006_drv.c [new file with mode: 0644]
drivers/gpu/drm/i2c/ch7006_mode.c [new file with mode: 0644]
drivers/gpu/drm/i2c/ch7006_priv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/Kconfig [new file with mode: 0644]
drivers/gpu/drm/nouveau/Makefile [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_acpi.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_backlight.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_bios.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_bios.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_bo.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_calc.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_channel.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_connector.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_connector.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_crtc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_debugfs.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_display.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_dma.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_dma.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_dp.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_drv.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_drv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_encoder.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_fb.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_fbcon.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_fbcon.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_fence.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_gem.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_hw.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_hw.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_i2c.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_i2c.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_ioc32.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_irq.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_mem.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_notifier.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_object.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_reg.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_sgdma.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_state.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_ttm.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_crtc.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_cursor.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_dac.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_dfp.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_display.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_fb.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_fbcon.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_fifo.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_graph.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_instmem.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_mc.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_timer.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv04_tv.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv10_fb.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv10_fifo.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv10_graph.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv17_gpio.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv17_tv.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv17_tv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv17_tv_modes.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv20_graph.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv40_fb.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv40_fifo.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv40_graph.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv40_mc.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_crtc.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_cursor.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_dac.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_display.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_display.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_evo.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_fbcon.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_fifo.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_graph.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_instmem.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_mc.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_sor.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvreg.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/input/xen-kbdfront.c
drivers/net/xen-netfront.c
drivers/pci/Kconfig
drivers/pci/Makefile
drivers/pci/dmar.c
drivers/pci/hotplug/Makefile
drivers/pci/hotplug/acpi_pcihp.c
drivers/pci/hotplug/acpiphp.h
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/ibmphp_hpc.c
drivers/pci/hotplug/pci_hotplug_core.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_acpi.c
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pcihp_slot.c
drivers/pci/intel-iommu.c
drivers/pci/intr_remapping.c
drivers/pci/ioapic.c [new file with mode: 0644]
drivers/pci/iov.c
drivers/pci/pci-acpi.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aer_inject.c
drivers/pci/pcie/aer/aerdrv.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/aer/ecrc.c
drivers/pci/pcie/aspm.c
drivers/pci/pcie/portdrv.h
drivers/pci/pcie/portdrv_bus.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/search.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/pcmcia/cardbus.c
drivers/pnp/quirks.c
drivers/pnp/resource.c
drivers/pnp/support.c
drivers/pnp/system.c
drivers/staging/Kconfig
drivers/video/xen-fbfront.c
drivers/xen/balloon.c
drivers/xen/cpu_hotplug.c
drivers/xen/evtchn.c
drivers/xen/grant-table.c
drivers/xen/sys-hypervisor.c
drivers/xen/xenbus/xenbus_probe.c
drivers/xen/xenfs/super.c
fs/nilfs2/alloc.c
fs/nilfs2/alloc.h
fs/nilfs2/bmap.c
fs/nilfs2/btnode.c
fs/nilfs2/btnode.h
fs/nilfs2/btree.c
fs/nilfs2/btree.h
fs/nilfs2/cpfile.c
fs/nilfs2/cpfile.h
fs/nilfs2/dat.c
fs/nilfs2/dat.h
fs/nilfs2/dir.c
fs/nilfs2/gcdat.c
fs/nilfs2/gcinode.c
fs/nilfs2/ifile.c
fs/nilfs2/ifile.h
fs/nilfs2/inode.c
fs/nilfs2/mdt.c
fs/nilfs2/mdt.h
fs/nilfs2/namei.c
fs/nilfs2/recovery.c
fs/nilfs2/segbuf.c
fs/nilfs2/segbuf.h
fs/nilfs2/segment.c
fs/nilfs2/segment.h
fs/nilfs2/sufile.c
fs/nilfs2/sufile.h
fs/nilfs2/super.c
fs/nilfs2/the_nilfs.c
fs/nilfs2/the_nilfs.h
include/acpi/acpi_hest.h [new file with mode: 0644]
include/drm/Kbuild
include/drm/i2c/ch7006.h [new file with mode: 0644]
include/drm/nouveau_drm.h [new file with mode: 0644]
include/drm/ttm/ttm_bo_api.h
include/linux/nilfs2_fs.h
include/linux/pci.h
include/linux/pci_regs.h
include/linux/pcieport_if.h
include/linux/syscalls.h
include/xen/xen.h [new file with mode: 0644]
ipc/shm.c
kernel/resource.c
lib/vsprintf.c
mm/mmap.c
mm/mremap.c
mm/util.c

index 01539f4106763f8b9ad283d7e315a4b9c3639a73..4949fcaa6b6a94f6d8b42d483a86c9a5984e0420 100644 (file)
@@ -49,8 +49,7 @@ Mount options
 NILFS2 supports the following mount options:
 (*) == default
 
-barrier=on(*)          This enables/disables barriers. barrier=off disables
-                       it, barrier=on enables it.
+nobarrier              Disables barriers.
 errors=continue(*)     Keep going on a filesystem error.
 errors=remount-ro      Remount the filesystem read-only on an error.
 errors=panic           Panic and halt the machine if an error occurs.
@@ -71,6 +70,10 @@ order=strict         Apply strict in-order semantics that preserves sequence
                        blocks.  That means, it is guaranteed that no
                        overtaking of events occurs in the recovered file
                        system after a crash.
+norecovery             Disable recovery of the filesystem on mount.
+                       This disables every write access on the device for
+                       read-only mounts or snapshots.  This option will fail
+                       for r/w mounts on an unclean volume.
 
 NILFS2 usage
 ============
index 9a3334ae282e38345d177e060acc2021fdeda084..62619f25132f93018d3a7850dda6c91aee5d0eb2 100644 (file)
@@ -178,25 +178,18 @@ SYSCALL_DEFINE6(osf_mmap, unsigned long, addr, unsigned long, len,
                unsigned long, prot, unsigned long, flags, unsigned long, fd,
                unsigned long, off)
 {
-       struct file *file = NULL;
-       unsigned long ret = -EBADF;
+       unsigned long ret = -EINVAL;
 
 #if 0
        if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))
                printk("%s: unimplemented OSF mmap flags %04lx\n", 
                        current->comm, flags);
 #endif
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       down_write(&current->mm->mmap_sem);
-       ret = do_mmap(file, addr, len, prot, flags, off);
-       up_write(&current->mm->mmap_sem);
-       if (file)
-               fput(file);
+       if ((off + PAGE_ALIGN(len)) < off)
+               goto out;
+       if (off & ~PAGE_MASK)
+               goto out;
+       ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
  out:
        return ret;
 }
index 8eebf89f5ab17884a98543f3b37a3b710355083b..41f99c573b93c918843ccbcd50ea2640bcb5e3ac 100644 (file)
@@ -1 +1,4 @@
 #include <asm-generic/mman.h>
+
+#define arch_mmap_check(addr, len, flags) \
+       (((flags) & MAP_FIXED && (addr) < FIRST_USER_ADDRESS) ? -EINVAL : 0)
index f58c1156e779f4a7caf94ea238a757c26d64e795..9314a2d681f15a299e614842c37eb97f694dbd23 100644 (file)
 /* 160 */      CALL(sys_sched_get_priority_min)
                CALL(sys_sched_rr_get_interval)
                CALL(sys_nanosleep)
-               CALL(sys_arm_mremap)
+               CALL(sys_mremap)
                CALL(sys_setresuid16)
 /* 165 */      CALL(sys_getresuid16)
                CALL(sys_ni_syscall)            /* vm86 */
index f0fe95b7085d8020682b297915ba1910af476828..2c1db77d78487cbdfa95d660f3abfa8acf6e215b 100644 (file)
@@ -416,12 +416,12 @@ sys_mmap2:
                tst     r5, #PGOFF_MASK
                moveq   r5, r5, lsr #PAGE_SHIFT - 12
                streq   r5, [sp, #4]
-               beq     do_mmap2
+               beq     sys_mmap_pgoff
                mov     r0, #-EINVAL
                mov     pc, lr
 #else
                str     r5, [sp, #4]
-               b       do_mmap2
+               b       sys_mmap_pgoff
 #endif
 ENDPROC(sys_mmap2)
 
index 78ecaac652069217b965eca0cd336b40858698b2..ae4027bd01bd3f921d54d558a640d0ef9bbe8c23 100644 (file)
 #include <linux/ipc.h>
 #include <linux/uaccess.h>
 
-extern unsigned long do_mremap(unsigned long addr, unsigned long old_len,
-                              unsigned long new_len, unsigned long flags,
-                              unsigned long new_addr);
-
-/* common code for old and new mmaps */
-inline long do_mmap2(
-       unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       int error = -EINVAL;
-       struct file * file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       if (flags & MAP_FIXED && addr < FIRST_USER_ADDRESS)
-               goto out;
-
-       error = -EBADF;
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
 struct mmap_arg_struct {
        unsigned long addr;
        unsigned long len;
@@ -84,29 +49,11 @@ asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
        if (a.offset & ~PAGE_MASK)
                goto out;
 
-       error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
 out:
        return error;
 }
 
-asmlinkage unsigned long
-sys_arm_mremap(unsigned long addr, unsigned long old_len,
-              unsigned long new_len, unsigned long flags,
-              unsigned long new_addr)
-{
-       unsigned long ret = -EINVAL;
-
-       if (flags & MREMAP_FIXED && new_addr < FIRST_USER_ADDRESS)
-               goto out;
-
-       down_write(&current->mm->mmap_sem);
-       ret = do_mremap(addr, old_len, new_len, flags, new_addr);
-       up_write(&current->mm->mmap_sem);
-
-out:
-       return ret;
-}
-
 /*
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls.
index 2b7996401b0f9f602dfa2d809f86e40b57f79117..f5abc51c5a07ff24e047ef333c7dd47b942fc3a4 100644 (file)
@@ -54,7 +54,8 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
         * We enforce the MAP_FIXED case.
         */
        if (flags & MAP_FIXED) {
-               if (aliasing && flags & MAP_SHARED && addr & (SHMLBA - 1))
+               if (aliasing && flags & MAP_SHARED &&
+                   (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
                        return -EINVAL;
                return addr;
        }
index 483d666c27c092bd2289b970a51f2edc6396b182..66a197266637e07f898102903e609ae710f521f8 100644 (file)
@@ -29,10 +29,6 @@ asmlinkage int sys_sigaltstack(const stack_t __user *, stack_t __user *,
                               struct pt_regs *);
 asmlinkage int sys_rt_sigreturn(struct pt_regs *);
 
-/* kernel/sys_avr32.c */
-asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long,
-                         unsigned long, unsigned long, off_t);
-
 /* mm/cache.c */
 asmlinkage int sys_cacheflush(int, void __user *, size_t);
 
index 5d2daeaf356f73331489d5e21a8be7e440cb6a45..459349b5ed5aa9d74982f2079edeb205ecdbef90 100644 (file)
@@ -5,39 +5,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/mm.h>
 #include <linux/unistd.h>
 
-#include <asm/mman.h>
-#include <asm/uaccess.h>
-#include <asm/syscalls.h>
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-                         unsigned long prot, unsigned long flags,
-                         unsigned long fd, off_t offset)
-{
-       int error = -EBADF;
-       struct file *file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       return error;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, offset);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-       return error;
-}
-
 int kernel_execve(const char *file, char **argv, char **envp)
 {
        register long scno asm("r8") = __NR_execve;
index f7244cd02fbbf0b96fd31f56f40c47e14d61430b..0447a3e2ba64b773c108fb7f5db9935329fcbc21 100644 (file)
@@ -61,7 +61,7 @@ __sys_execve:
 __sys_mmap2:
        pushm   lr
        st.w    --sp, ARG6
-       call    sys_mmap2
+       call    sys_mmap_pgoff
        sub     sp, -4
        popm    pc
 
index afcef129d4e843fb3c81b27253356f55c76bbc50..2e7f8e10bf87109083f43f73411327ae5223f724 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/dma.h>
 
-/* common code for old and new mmaps */
-static inline long
-do_mmap2(unsigned long addr, unsigned long len,
-        unsigned long prot, unsigned long flags,
-        unsigned long fd, unsigned long pgoff)
-{
-       int error = -EBADF;
-       struct file *file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
- out:
-       return error;
-}
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-                         unsigned long prot, unsigned long flags,
-                         unsigned long fd, unsigned long pgoff)
-{
-       return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
 asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags)
 {
        return sram_alloc_with_lsl(size, flags);
index a50637a8b9bddb9c468c5615b2a0586f2224e03b..f3f8bb46b517d8f291633c8fda13195462731fe9 100644 (file)
@@ -1422,7 +1422,7 @@ ENTRY(_sys_call_table)
        .long _sys_ni_syscall   /* streams2 */
        .long _sys_vfork                /* 190 */
        .long _sys_getrlimit
-       .long _sys_mmap2
+       .long _sys_mmap_pgoff
        .long _sys_truncate64
        .long _sys_ftruncate64
        .long _sys_stat64       /* 195 */
index 2ad962c7e88ebaddcbc11ed7a3a88f3e2e900385..c2bbb1ac98a964b9ffaa2ae8454d8becda607712 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/segment.h>
 
-/* common code for old and new mmaps */
-static inline long
-do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
-        unsigned long flags, unsigned long fd, unsigned long pgoff)
-{
-        int error = -EBADF;
-        struct file * file = NULL;
-
-        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-        if (!(flags & MAP_ANONYMOUS)) {
-                file = fget(fd);
-                if (!file)
-                        goto out;
-        }
-
-        down_write(&current->mm->mmap_sem);
-        error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-        up_write(&current->mm->mmap_sem);
-
-        if (file)
-                fput(file);
-out:
-        return error;
-}
-
 asmlinkage unsigned long old_mmap(unsigned long __user *args)
 {        
        unsigned long buffer[6];
@@ -63,7 +38,7 @@ asmlinkage unsigned long old_mmap(unsigned long __user *args)
        if (buffer[5] & ~PAGE_MASK) /* verify that offset is on page boundary */
                goto out;
 
-       err = do_mmap2(buffer[0], buffer[1], buffer[2], buffer[3],
+       err = sys_mmap_pgoff(buffer[0], buffer[1], buffer[2], buffer[3],
                        buffer[4], buffer[5] >> PAGE_SHIFT);
 out:
        return err;
@@ -73,7 +48,8 @@ asmlinkage long
 sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
           unsigned long flags, unsigned long fd, unsigned long pgoff)
 {
-        return do_mmap2(addr, len, prot, flags, fd, pgoff);
+       /* bug(?): 8Kb pages here */
+        return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
 }
 
 /*
index 2b6b5289cdccefbd2d5029d5da4e62ebdc989803..1d3d4c9e25218e13341ed77d3cc43e3e4f8586a6 100644 (file)
@@ -31,9 +31,6 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
                          unsigned long prot, unsigned long flags,
                          unsigned long fd, unsigned long pgoff)
 {
-       int error = -EBADF;
-       struct file * file = NULL;
-
        /* As with sparc32, make sure the shift for mmap2 is constant
           (12), no matter what PAGE_SIZE we have.... */
 
@@ -41,69 +38,10 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
           trying to map something we can't */
        if (pgoff & ((1 << (PAGE_SHIFT - 12)) - 1))
                return -EINVAL;
-       pgoff >>= PAGE_SHIFT - 12;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
-#if 0 /* DAVIDM - do we want this */
-struct mmap_arg_struct64 {
-       __u32 addr;
-       __u32 len;
-       __u32 prot;
-       __u32 flags;
-       __u64 offset; /* 64 bits */
-       __u32 fd;
-};
-
-asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg)
-{
-       int error = -EFAULT;
-       struct file * file = NULL;
-       struct mmap_arg_struct64 a;
-       unsigned long pgoff;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-
-       if ((long)a.offset & ~PAGE_MASK)
-               return -EINVAL;
-
-       pgoff = a.offset >> PAGE_SHIFT;
-       if ((a.offset >> PAGE_SHIFT) != pgoff)
-               return -EINVAL;
-
-       if (!(a.flags & MAP_ANONYMOUS)) {
-               error = -EBADF;
-               file = fget(a.fd);
-               if (!file)
-                       goto out;
-       }
-       a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-       if (file)
-               fput(file);
-out:
-       return error;
+       return sys_mmap_pgoff(addr, len, prot, flags, fd,
+                             pgoff >> (PAGE_SHIFT - 12));
 }
-#endif
 
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
index 8cb5d73a0e357cbc530b6d2a408c7a5b8065009b..b5969db0ca10fbe401dd5977b86482b59ba21b0e 100644 (file)
 #include <asm/traps.h>
 #include <asm/unistd.h>
 
-/* common code for old and new mmaps */
-static inline long do_mmap2(
-       unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       int error = -EBADF;
-       struct file * file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
 /*
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
@@ -87,57 +54,11 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg)
        if (a.offset & ~PAGE_MASK)
                goto out;
 
-       a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
-out:
-       return error;
-}
-
-#if 0 /* DAVIDM - do we want this */
-struct mmap_arg_struct64 {
-       __u32 addr;
-       __u32 len;
-       __u32 prot;
-       __u32 flags;
-       __u64 offset; /* 64 bits */
-       __u32 fd;
-};
-
-asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg)
-{
-       int error = -EFAULT;
-       struct file * file = NULL;
-       struct mmap_arg_struct64 a;
-       unsigned long pgoff;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-
-       if ((long)a.offset & ~PAGE_MASK)
-               return -EINVAL;
-
-       pgoff = a.offset >> PAGE_SHIFT;
-       if ((a.offset >> PAGE_SHIFT) != pgoff)
-               return -EINVAL;
-
-       if (!(a.flags & MAP_ANONYMOUS)) {
-               error = -EBADF;
-               file = fget(a.fd);
-               if (!file)
-                       goto out;
-       }
-       a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-       if (file)
-               fput(file);
+       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
+                              a.offset >> PAGE_SHIFT);
 out:
        return error;
 }
-#endif
 
 struct sel_arg_struct {
        unsigned long n;
index 4eb67faac6337878717224f9d39d292bc5712846..2d69881eda6ade4e9666500aeb110f7776d209a1 100644 (file)
@@ -206,7 +206,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_ni_syscall)       /* streams2 */
        .long SYMBOL_NAME(sys_vfork)            /* 190 */
        .long SYMBOL_NAME(sys_getrlimit)
-       .long SYMBOL_NAME(sys_mmap2)
+       .long SYMBOL_NAME(sys_mmap_pgoff)
        .long SYMBOL_NAME(sys_truncate64)
        .long SYMBOL_NAME(sys_ftruncate64)
        .long SYMBOL_NAME(sys_stat64)           /* 195 */
index 429ec968c9ee62178ffcc8c3afe1005510695eb1..045b746b98081e493b3ea85244cf10113c83126a 100644 (file)
@@ -858,6 +858,9 @@ ia32_do_mmap (struct file *file, unsigned long addr, unsigned long len, int prot
 
        prot = get_prot32(prot);
 
+       if (flags & MAP_HUGETLB)
+               return -ENOMEM;
+
 #if PAGE_SHIFT > IA32_PAGE_SHIFT
        mutex_lock(&ia32_mmap_mutex);
        {
index 88afb54501e48feba6c24d6f25c7f5967b308c89..67455c2ed2b12d85acbaf1087da08d4e57739f76 100644 (file)
 #include <xen/interface/xen.h>
 #include <xen/interface/version.h>     /* to compile feature.c */
 #include <xen/features.h>              /* to comiple xen-netfront.c */
+#include <xen/xen.h>
 #include <asm/xen/hypercall.h>
 
-/* xen_domain_type is set before executing any C code by early_xen_setup */
-enum xen_domain_type {
-       XEN_NATIVE,     /* running on bare hardware */
-       XEN_PV_DOMAIN,  /* running in a PV domain */
-       XEN_HVM_DOMAIN, /* running in a Xen hvm domain*/
-};
-
-#ifdef CONFIG_XEN
-extern enum xen_domain_type xen_domain_type;
-#else
-#define xen_domain_type                XEN_NATIVE
-#endif
-
-#define xen_domain()           (xen_domain_type != XEN_NATIVE)
-#define xen_pv_domain()                (xen_domain() &&                        \
-                                xen_domain_type == XEN_PV_DOMAIN)
-#define xen_hvm_domain()       (xen_domain() &&                        \
-                                xen_domain_type == XEN_HVM_DOMAIN)
-
-#ifdef CONFIG_XEN_DOM0
-#define xen_initial_domain()   (xen_pv_domain() &&                     \
-                                (xen_start_info->flags & SIF_INITDOMAIN))
-#else
-#define xen_initial_domain()   (0)
-#endif
-
-
 #ifdef CONFIG_XEN
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
index 92ed83f34036f0b52cccc36a529bb48bdbd5127d..609d50056a6c7bd9fba2d46b757960b3e8893388 100644 (file)
@@ -100,51 +100,7 @@ sys_getpagesize (void)
 asmlinkage unsigned long
 ia64_brk (unsigned long brk)
 {
-       unsigned long rlim, retval, newbrk, oldbrk;
-       struct mm_struct *mm = current->mm;
-
-       /*
-        * Most of this replicates the code in sys_brk() except for an additional safety
-        * check and the clearing of r8.  However, we can't call sys_brk() because we need
-        * to acquire the mmap_sem before we can do the test...
-        */
-       down_write(&mm->mmap_sem);
-
-       if (brk < mm->end_code)
-               goto out;
-       newbrk = PAGE_ALIGN(brk);
-       oldbrk = PAGE_ALIGN(mm->brk);
-       if (oldbrk == newbrk)
-               goto set_brk;
-
-       /* Always allow shrinking brk. */
-       if (brk <= mm->brk) {
-               if (!do_munmap(mm, newbrk, oldbrk-newbrk))
-                       goto set_brk;
-               goto out;
-       }
-
-       /* Check against unimplemented/unmapped addresses: */
-       if ((newbrk - oldbrk) > RGN_MAP_LIMIT || REGION_OFFSET(newbrk) > RGN_MAP_LIMIT)
-               goto out;
-
-       /* Check against rlimit.. */
-       rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
-       if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim)
-               goto out;
-
-       /* Check against existing mmap mappings. */
-       if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
-               goto out;
-
-       /* Ok, looks good - let it rip. */
-       if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)
-               goto out;
-set_brk:
-       mm->brk = brk;
-out:
-       retval = mm->brk;
-       up_write(&mm->mmap_sem);
+       unsigned long retval = sys_brk(brk);
        force_successful_syscall_return();
        return retval;
 }
@@ -185,39 +141,6 @@ int ia64_mmap_check(unsigned long addr, unsigned long len,
        return 0;
 }
 
-static inline unsigned long
-do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff)
-{
-       struct file *file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       return -EBADF;
-
-               if (!file->f_op || !file->f_op->mmap) {
-                       addr = -ENODEV;
-                       goto out;
-               }
-       }
-
-       /* Careful about overflows.. */
-       len = PAGE_ALIGN(len);
-       if (!len || len > TASK_SIZE) {
-               addr = -EINVAL;
-               goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-out:   if (file)
-               fput(file);
-       return addr;
-}
-
 /*
  * mmap2() is like mmap() except that the offset is expressed in units
  * of PAGE_SIZE (instead of bytes).  This allows to mmap2() (pieces
@@ -226,7 +149,7 @@ out:        if (file)
 asmlinkage unsigned long
 sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, long pgoff)
 {
-       addr = do_mmap2(addr, len, prot, flags, fd, pgoff);
+       addr = sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
        if (!IS_ERR((void *) addr))
                force_successful_syscall_return();
        return addr;
@@ -238,7 +161,7 @@ sys_mmap (unsigned long addr, unsigned long len, int prot, int flags, int fd, lo
        if (offset_in_page(off) != 0)
                return -EINVAL;
 
-       addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
+       addr = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
        if (!IS_ERR((void *) addr))
                force_successful_syscall_return();
        return addr;
index c0fca2c1c858372493675695f9a5341200c139ae..df639db779f95192a71d93d5895113080b1bf41a 100644 (file)
@@ -131,6 +131,7 @@ alloc_pci_controller (int seg)
 }
 
 struct pci_root_info {
+       struct acpi_device *bridge;
        struct pci_controller *controller;
        char *name;
 };
@@ -297,9 +298,20 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
        window->offset = offset;
 
        if (insert_resource(root, &window->resource)) {
-               printk(KERN_ERR "alloc 0x%llx-0x%llx from %s for %s failed\n",
-                       window->resource.start, window->resource.end,
-                       root->name, info->name);
+               dev_err(&info->bridge->dev,
+                       "can't allocate host bridge window %pR\n",
+                       &window->resource);
+       } else {
+               if (offset)
+                       dev_info(&info->bridge->dev, "host bridge window %pR "
+                                "(PCI address [%#llx-%#llx])\n",
+                                &window->resource,
+                                window->resource.start - offset,
+                                window->resource.end - offset);
+               else
+                       dev_info(&info->bridge->dev,
+                                "host bridge window %pR\n",
+                                &window->resource);
        }
 
        return AE_OK;
@@ -319,8 +331,9 @@ pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
                    (res->end - res->start < 16))
                        continue;
                if (j >= PCI_BUS_NUM_RESOURCES) {
-                       printk("Ignoring range [%#llx-%#llx] (%lx)\n",
-                                       res->start, res->end, res->flags);
+                       dev_warn(&bus->dev,
+                                "ignoring host bridge window %pR (no space)\n",
+                                res);
                        continue;
                }
                bus->resource[j++] = res;
@@ -364,6 +377,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
                        goto out3;
 
                sprintf(name, "PCI Bus %04x:%02x", domain, bus);
+               info.bridge = device;
                info.controller = controller;
                info.name = name;
                acpi_walk_resources(device->handle, METHOD_NAME__CRS,
@@ -720,9 +734,6 @@ int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
        return ret;
 }
 
-/* It's defined in drivers/pci/pci.c */
-extern u8 pci_cache_line_size;
-
 /**
  * set_pci_cacheline_size - determine cacheline size for PCI devices
  *
@@ -731,7 +742,7 @@ extern u8 pci_cache_line_size;
  *
  * Code mostly taken from arch/ia64/kernel/palinfo.c:cache_info().
  */
-static void __init set_pci_cacheline_size(void)
+static void __init set_pci_dfl_cacheline_size(void)
 {
        unsigned long levels, unique_caches;
        long status;
@@ -751,7 +762,7 @@ static void __init set_pci_cacheline_size(void)
                        "(status=%ld)\n", __func__, status);
                return;
        }
-       pci_cache_line_size = (1 << cci.pcci_line_size) / 4;
+       pci_dfl_cache_line_size = (1 << cci.pcci_line_size) / 4;
 }
 
 u64 ia64_dma_get_required_mask(struct device *dev)
@@ -782,7 +793,7 @@ EXPORT_SYMBOL_GPL(dma_get_required_mask);
 
 static int __init pcibios_init(void)
 {
-       set_pci_cacheline_size();
+       set_pci_dfl_cacheline_size();
        return 0;
 }
 
index 305ac852bbed417dda77de7a9b100c6a401bc75d..d3c865c5a6bab95d1a79a9ca078e5bafceb3a2c5 100644 (file)
@@ -76,30 +76,6 @@ asmlinkage int sys_tas(int __user *addr)
        return oldval;
 }
 
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       int error = -EBADF;
-       struct file *file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
index aa3bf4cfab37cd8b0f999ba5211baeef6ebae3c3..60536e271233c20a1401dc7ee09a70e9251f0d48 100644 (file)
@@ -191,7 +191,7 @@ ENTRY(sys_call_table)
        .long sys_ni_syscall            /* streams2 */
        .long sys_vfork                 /* 190 */
        .long sys_getrlimit
-       .long sys_mmap2
+       .long sys_mmap_pgoff
        .long sys_truncate64
        .long sys_ftruncate64
        .long sys_stat64                /* 195 */
index 7deb402bfc751c9ba7a77f13afdd2c904b02a7ae..218f441de667c6f5fb35de5d5caaefdeeb6f84fb 100644 (file)
 #include <asm/page.h>
 #include <asm/unistd.h>
 
-/* common code for old and new mmaps */
-static inline long do_mmap2(
-       unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       int error = -EBADF;
-       struct file * file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags,
        unsigned long fd, unsigned long pgoff)
 {
-       return do_mmap2(addr, len, prot, flags, fd, pgoff);
+       /*
+        * This is wrong for sun3 - there PAGE_SIZE is 8Kb,
+        * so we need to shift the argument down by 1; m68k mmap64(3)
+        * (in libc) expects the last argument of mmap2 in 4Kb units.
+        */
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
 }
 
 /*
@@ -90,57 +69,11 @@ asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
        if (a.offset & ~PAGE_MASK)
                goto out;
 
-       a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
-out:
-       return error;
-}
-
-#if 0
-struct mmap_arg_struct64 {
-       __u32 addr;
-       __u32 len;
-       __u32 prot;
-       __u32 flags;
-       __u64 offset; /* 64 bits */
-       __u32 fd;
-};
-
-asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg)
-{
-       int error = -EFAULT;
-       struct file * file = NULL;
-       struct mmap_arg_struct64 a;
-       unsigned long pgoff;
-
-       if (copy_from_user(&a, arg, sizeof(a)))
-               return -EFAULT;
-
-       if ((long)a.offset & ~PAGE_MASK)
-               return -EINVAL;
-
-       pgoff = a.offset >> PAGE_SHIFT;
-       if ((a.offset >> PAGE_SHIFT) != pgoff)
-               return -EINVAL;
-
-       if (!(a.flags & MAP_ANONYMOUS)) {
-               error = -EBADF;
-               file = fget(a.fd);
-               if (!file)
-                       goto out;
-       }
-       a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-       if (file)
-               fput(file);
+       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
+                              a.offset >> PAGE_SHIFT);
 out:
        return error;
 }
-#endif
 
 struct sel_arg_struct {
        unsigned long n;
index efdd090778a371d57ff749561a799e263755fc67..b67cbc735a9b13d7e0ca3d52fdef01b3ff944d09 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/unistd.h>
 
-/* common code for old and new mmaps */
-static inline long do_mmap2(
-       unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       int error = -EBADF;
-       struct file * file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
 /*
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
@@ -88,9 +55,8 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg)
        if (a.offset & ~PAGE_MASK)
                goto out;
 
-       a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
+                               a.offset >> PAGE_SHIFT);
 out:
        return error;
 }
index 23535cc415aea014accf7f726b225cd18a67a9e5..486837efa3d788d5196f77130675880d23a43a0d 100644 (file)
@@ -210,7 +210,7 @@ ENTRY(sys_call_table)
        .long sys_ni_syscall    /* streams2 */
        .long sys_vfork         /* 190 */
        .long sys_getrlimit
-       .long sys_mmap2
+       .long sys_mmap_pgoff
        .long sys_truncate64
        .long sys_ftruncate64
        .long sys_stat64        /* 195 */
index 07cabed4b947fafbc4cab9d89201c2ba42aebfdf..9f3c205fb75b71c47086f21f9e80863b6dcd14df 100644 (file)
@@ -62,46 +62,14 @@ out:
        return error;
 }
 
-asmlinkage long
-sys_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       struct file *file = NULL;
-       int ret = -EBADF;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file) {
-                       printk(KERN_INFO "no fd in mmap\r\n");
-                       goto out;
-               }
-       }
-
-       down_write(&current->mm->mmap_sem);
-       ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-       if (file)
-               fput(file);
-out:
-       return ret;
-}
-
 asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
                        unsigned long prot, unsigned long flags,
                        unsigned long fd, off_t pgoff)
 {
-       int err = -EINVAL;
-
-       if (pgoff & ~PAGE_MASK) {
-               printk(KERN_INFO "no pagemask in mmap\r\n");
-               goto out;
-       }
+       if (pgoff & ~PAGE_MASK)
+               return -EINVAL;
 
-       err = sys_mmap2(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT);
-out:
-       return err;
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT);
 }
 
 /*
index c1ab1dc10898b70e5ef6c9204dae740979c7d3e3..b96f365ea6b1aaf46d5d9c1026f8ae9fbac7afa1 100644 (file)
@@ -196,7 +196,7 @@ ENTRY(sys_call_table)
        .long sys_ni_syscall            /* reserved for streams2 */
        .long sys_vfork         /* 190 */
        .long sys_getrlimit
-       .long sys_mmap2                 /* mmap2 */
+       .long sys_mmap_pgoff            /* mmap2 */
        .long sys_truncate64
        .long sys_ftruncate64
        .long sys_stat64                /* 195 */
index 1a2793efdc4e2c45160f3ff71eca72082d180df9..f042563c924f66f9da2ef3a88f4e75032f55871f 100644 (file)
@@ -67,28 +67,13 @@ SYSCALL_DEFINE6(32_mmap2, unsigned long, addr, unsigned long, len,
        unsigned long, prot, unsigned long, flags, unsigned long, fd,
        unsigned long, pgoff)
 {
-       struct file * file = NULL;
        unsigned long error;
 
        error = -EINVAL;
        if (pgoff & (~PAGE_MASK >> 12))
                goto out;
-       pgoff >>= PAGE_SHIFT-12;
-
-       if (!(flags & MAP_ANONYMOUS)) {
-               error = -EBADF;
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-       if (file)
-               fput(file);
-
+       error = sys_mmap_pgoff(addr, len, prot, flags, fd,
+                              pgoff >> (PAGE_SHIFT-12));
 out:
        return error;
 }
index fe0d7980560368056e187dcc9f852b3218a08951..3f7f466190b481e62b7df738b10ef96477f1c059 100644 (file)
@@ -93,7 +93,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
                 * We do not accept a shared mapping if it would violate
                 * cache aliasing constraints.
                 */
-               if ((flags & MAP_SHARED) && (addr & shm_align_mask))
+               if ((flags & MAP_SHARED) &&
+                   ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
                        return -EINVAL;
                return addr;
        }
@@ -129,31 +130,6 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
        }
 }
 
-/* common code for old and new mmaps */
-static inline unsigned long
-do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
-        unsigned long flags, unsigned long fd, unsigned long pgoff)
-{
-       unsigned long error = -EBADF;
-       struct file * file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
 SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
        unsigned long, prot, unsigned long, flags, unsigned long,
        fd, off_t, offset)
@@ -164,7 +140,7 @@ SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
        if (offset & ~PAGE_MASK)
                goto out;
 
-       result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+       result = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
 
 out:
        return result;
@@ -177,7 +153,7 @@ SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
        if (pgoff & (~PAGE_MASK >> 12))
                return -EINVAL;
 
-       return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
 }
 
 save_static_function(sys_fork);
index 8eebf89f5ab17884a98543f3b37a3b710355083b..db5c53da73ced573d66176a58d8e7b73580b5ae2 100644 (file)
@@ -1 +1,6 @@
 #include <asm-generic/mman.h>
+
+#define MIN_MAP_ADDR   PAGE_SIZE       /* minimum fixed mmap address */
+
+#define arch_mmap_check(addr, len, flags) \
+       (((flags) & MAP_FIXED && (addr) < MIN_MAP_ADDR) ? -EINVAL : 0)
index a94e7ea3faa69e634f50b4e7d2db6db0916b7a2f..c9ee6c009d795aa1fde9c44b2bc56b5a5f1beba5 100644 (file)
@@ -578,7 +578,7 @@ ENTRY(sys_call_table)
        .long sys_ni_syscall    /* reserved for streams2 */
        .long sys_vfork         /* 190 */
        .long sys_getrlimit
-       .long sys_mmap2
+       .long sys_mmap_pgoff
        .long sys_truncate64
        .long sys_ftruncate64
        .long sys_stat64        /* 195 */
index 8ca5af00334cd1f30567f7c74218040aed7750e6..17cc6ce04e840f136cd18e2a569e957697c10cd2 100644 (file)
 
 #include <asm/uaccess.h>
 
-#define MIN_MAP_ADDR   PAGE_SIZE       /* minimum fixed mmap address */
-
-/*
- * memory mapping syscall
- */
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-                         unsigned long prot, unsigned long flags,
-                         unsigned long fd, unsigned long pgoff)
-{
-       struct file *file = NULL;
-       long error = -EINVAL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       if (flags & MAP_FIXED && addr < MIN_MAP_ADDR)
-               goto out;
-
-       error = -EBADF;
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
 asmlinkage long old_mmap(unsigned long addr, unsigned long len,
                         unsigned long prot, unsigned long flags,
                         unsigned long fd, unsigned long offset)
 {
        if (offset & ~PAGE_MASK)
                return -EINVAL;
-       return sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
 }
 
 struct sel_arg_struct {
index 71b31957c8f13805c5a8da1c93c6061bf562f2a7..9147391afb03ef0590ae7a9167919c408dbd82e7 100644 (file)
@@ -110,37 +110,14 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
        return addr;
 }
 
-static unsigned long do_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags, unsigned long fd,
-       unsigned long pgoff)
-{
-       struct file * file = NULL;
-       unsigned long error = -EBADF;
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file != NULL)
-               fput(file);
-out:
-       return error;
-}
-
 asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags, unsigned long fd,
        unsigned long pgoff)
 {
        /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
           we have. */
-       return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12));
+       return sys_mmap_pgoff(addr, len, prot, flags, fd,
+                             pgoff >> (PAGE_SHIFT - 12));
 }
 
 asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
@@ -148,7 +125,8 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
                unsigned long offset)
 {
        if (!(offset & ~PAGE_MASK)) {
-               return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+               return sys_mmap_pgoff(addr, len, prot, flags, fd,
+                                       offset >> PAGE_SHIFT);
        } else {
                return -EINVAL;
        }
index c04832c4a02e3965834a48adbaad9450e76ef378..3370e62e43d4eabe6e20d6ce5c9c2aa9522fc5cd 100644 (file)
@@ -140,7 +140,6 @@ static inline unsigned long do_mmap2(unsigned long addr, size_t len,
                        unsigned long prot, unsigned long flags,
                        unsigned long fd, unsigned long off, int shift)
 {
-       struct file * file = NULL;
        unsigned long ret = -EINVAL;
 
        if (!arch_validate_prot(prot))
@@ -151,20 +150,8 @@ static inline unsigned long do_mmap2(unsigned long addr, size_t len,
                        goto out;
                off >>= shift;
        }
-               
-       ret = -EBADF;
-       if (!(flags & MAP_ANONYMOUS)) {
-               if (!(file = fget(fd)))
-                       goto out;
-       }
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-       down_write(&current->mm->mmap_sem);
-       ret = do_mmap_pgoff(file, addr, len, prot, flags, off);
-       up_write(&current->mm->mmap_sem);
-       if (file)
-               fput(file);
+       ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off);
 out:
        return ret;
 }
index 25c31d681402f1c43e140232dd8c7cbfa6166a0f..22c9e557bb22b9f79b275fe3707f27cb133e6c8c 100644 (file)
@@ -624,38 +624,6 @@ struct mmap_arg_struct_emu31 {
        u32     offset;
 };
 
-/* common code for old and new mmaps */
-static inline long do_mmap2(
-       unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       struct file * file = NULL;
-       unsigned long error = -EBADF;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) {
-               /* Result is out of bounds.  */
-               do_munmap(current->mm, addr, len);
-               error = -ENOMEM;
-       }
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:    
-       return error;
-}
-
-
 asmlinkage unsigned long
 old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
 {
@@ -669,7 +637,8 @@ old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
        if (a.offset & ~PAGE_MASK)
                goto out;
 
-       error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); 
+       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
+                              a.offset >> PAGE_SHIFT);
 out:
        return error;
 }
@@ -682,7 +651,7 @@ sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
 
        if (copy_from_user(&a, arg, sizeof(a)))
                goto out;
-       error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
 out:
        return error;
 }
index e9d94f61d5002639645e59cd45683acc2c52038a..86a74c9c9e63c2b7d377ee7c725d7381377ae0a3 100644 (file)
 #include <asm/uaccess.h>
 #include "entry.h"
 
-/* common code for old and new mmaps */
-static inline long do_mmap2(
-       unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       long error = -EBADF;
-       struct file * file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
 /*
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls. Linux for S/390 isn't able to handle more than 5
@@ -81,7 +55,7 @@ SYSCALL_DEFINE1(mmap2, struct mmap_arg_struct __user *, arg)
 
        if (copy_from_user(&a, arg, sizeof(a)))
                goto out;
-       error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
 out:
        return error;
 }
@@ -98,7 +72,7 @@ SYSCALL_DEFINE1(s390_old_mmap, struct mmap_arg_struct __user *, arg)
        if (a.offset & ~PAGE_MASK)
                goto out;
 
-       error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+       error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
 out:
        return error;
 }
index 00124946986615ff8dc133dfc298f2fd2a80b34c..856ed68a58e6103efd22d0496cb2884438f8cfa0 100644 (file)
@@ -36,34 +36,16 @@ asmlinkage long
 sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
          unsigned long flags, unsigned long fd, unsigned long pgoff)
 {
-       int error = -EBADF;
-       struct file *file = NULL;
-
-       if (pgoff & (~PAGE_MASK >> 12))
-               return -EINVAL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       return error;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-
-       return error;
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
 }
 
 asmlinkage long
 sys_mmap(unsigned long addr, unsigned long len, unsigned long prot,
-       unsigned long flags, unsigned long fd, off_t pgoff)
+       unsigned long flags, unsigned long fd, off_t offset)
 {
-       return sys_mmap2(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT);
+       if (unlikely(offset & ~PAGE_MASK))
+               return -EINVAL;
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
 }
 
 asmlinkage long
index 8aa5d1ceaf14b225934d4ec8e0860bbfcdf298ef..71399cde03b52c3cca26612075d7ebae4e2c1a68 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/cachectl.h>
 
-static inline long
-do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
-        unsigned long flags, int fd, unsigned long pgoff)
-{
-       int error = -EBADF;
-       struct file *file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
 asmlinkage int old_mmap(unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags,
        int fd, unsigned long off)
 {
        if (off & ~PAGE_MASK)
                return -EINVAL;
-       return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT);
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, off>>PAGE_SHIFT);
 }
 
 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
@@ -74,7 +50,7 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
 
        pgoff >>= PAGE_SHIFT - 12;
 
-       return do_mmap2(addr, len, prot, flags, fd, pgoff);
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
 }
 
 /*
index d2984fa42d3d0ee69fce3a3e0a7e4fa24323c835..afeb710ec5c35d06926717a7f666f373ea366887 100644 (file)
@@ -54,7 +54,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
                /* We do not accept a shared mapping if it would violate
                 * cache aliasing constraints.
                 */
-               if ((flags & MAP_SHARED) && (addr & shm_align_mask))
+               if ((flags & MAP_SHARED) &&
+                   ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
                        return -EINVAL;
                return addr;
        }
index b63e51c3c3ee2fdb959b13f5e0fd9511bc344d09..b0576df6ec832ab6996436a6a554dbb2dcd62257 100644 (file)
@@ -16,8 +16,6 @@
 
 #define PCI_IRQ_NONE           0xffffffff
 
-#define PCI_CACHE_LINE_BYTES   64
-
 static inline void pcibios_set_master(struct pci_dev *dev)
 {
        /* No special bus mastering setup handling */
index c68648662802a122932ccece24ad31c250ddb77c..b85374f7cf945f3d4760dbd6fe739455ea52b33b 100644 (file)
@@ -1081,3 +1081,10 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar,
        *start = rp->start - offset;
        *end = rp->end - offset;
 }
+
+static int __init pcibios_init(void)
+{
+       pci_dfl_cache_line_size = 64 >> 2;
+       return 0;
+}
+subsys_initcall(pcibios_init);
index 00abe87e5b51af8c5a5a059893ef7196b7d77883..dc0ac197e7e294310a1a2d5f15ddbf455b0394a2 100644 (file)
@@ -564,28 +564,6 @@ asmlinkage long sparc32_open(const char __user *filename,
        return do_sys_open(AT_FDCWD, filename, flags, mode);
 }
 
-extern unsigned long do_mremap(unsigned long addr,
-       unsigned long old_len, unsigned long new_len,
-       unsigned long flags, unsigned long new_addr);
-                
-asmlinkage unsigned long sys32_mremap(unsigned long addr,
-       unsigned long old_len, unsigned long new_len,
-       unsigned long flags, u32 __new_addr)
-{
-       unsigned long ret = -EINVAL;
-       unsigned long new_addr = __new_addr;
-
-       if (unlikely(sparc_mmap_check(addr, old_len)))
-               goto out;
-       if (unlikely(sparc_mmap_check(new_addr, new_len)))
-               goto out;
-       down_write(&current->mm->mmap_sem);
-       ret = do_mremap(addr, old_len, new_len, flags, new_addr);
-       up_write(&current->mm->mmap_sem);
-out:
-       return ret;       
-}
-
 long sys32_lookup_dcookie(unsigned long cookie_high,
                          unsigned long cookie_low,
                          char __user *buf, size_t len)
index 03035c852a43f8e751f5bb8ba16e3f767c9bc9fb..3a82e65d8db2072b9f4b3d9a2edb9faf55c263a7 100644 (file)
@@ -45,7 +45,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
                /* We do not accept a shared mapping if it would violate
                 * cache aliasing constraints.
                 */
-               if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
+               if ((flags & MAP_SHARED) &&
+                   ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)))
                        return -EINVAL;
                return addr;
        }
@@ -79,15 +80,6 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
        }
 }
 
-asmlinkage unsigned long sparc_brk(unsigned long brk)
-{
-       if(ARCH_SUN4C) {
-               if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000))
-                       return current->mm->brk;
-       }
-       return sys_brk(brk);
-}
-
 /*
  * sys_pipe() is the normal C calling standard for creating
  * a pipe. It's not the way unix traditionally does this, though.
@@ -234,31 +226,6 @@ int sparc_mmap_check(unsigned long addr, unsigned long len)
 }
 
 /* Linux version of mmap */
-static unsigned long do_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags, unsigned long fd,
-       unsigned long pgoff)
-{
-       struct file * file = NULL;
-       unsigned long retval = -EBADF;
-
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       len = PAGE_ALIGN(len);
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-       down_write(&current->mm->mmap_sem);
-       retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return retval;
-}
 
 asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags, unsigned long fd,
@@ -266,14 +233,16 @@ asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
 {
        /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
           we have. */
-       return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12));
+       return sys_mmap_pgoff(addr, len, prot, flags, fd,
+                             pgoff >> (PAGE_SHIFT - 12));
 }
 
 asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags, unsigned long fd,
        unsigned long off)
 {
-       return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
+       /* no alignment check? */
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
 }
 
 long sparc_remap_file_pages(unsigned long start, unsigned long size,
@@ -287,27 +256,6 @@ long sparc_remap_file_pages(unsigned long start, unsigned long size,
                                    (pgoff >> (PAGE_SHIFT - 12)), flags);
 }
 
-extern unsigned long do_mremap(unsigned long addr,
-       unsigned long old_len, unsigned long new_len,
-       unsigned long flags, unsigned long new_addr);
-                
-asmlinkage unsigned long sparc_mremap(unsigned long addr,
-       unsigned long old_len, unsigned long new_len,
-       unsigned long flags, unsigned long new_addr)
-{
-       unsigned long ret = -EINVAL;
-
-       if (unlikely(sparc_mmap_check(addr, old_len)))
-               goto out;
-       if (unlikely(sparc_mmap_check(new_addr, new_len)))
-               goto out;
-       down_write(&current->mm->mmap_sem);
-       ret = do_mremap(addr, old_len, new_len, flags, new_addr);
-       up_write(&current->mm->mmap_sem);
-out:
-       return ret;       
-}
-
 /* we come to here via sys_nis_syscall so it can setup the regs argument */
 asmlinkage unsigned long
 c_sys_nis_syscall (struct pt_regs *regs)
index e2d102447a43e5c57f8cb64a136763795ddf192b..cfa0e19abe3bd62b2e0f64f2b5b5d15499b0b9c9 100644 (file)
@@ -317,10 +317,14 @@ bottomup:
 unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
        unsigned long align_goal, addr = -ENOMEM;
+       unsigned long (*get_area)(struct file *, unsigned long,
+                                 unsigned long, unsigned long, unsigned long);
+
+       get_area = current->mm->get_unmapped_area;
 
        if (flags & MAP_FIXED) {
                /* Ok, don't mess with it. */
-               return get_unmapped_area(NULL, orig_addr, len, pgoff, flags);
+               return get_area(NULL, orig_addr, len, pgoff, flags);
        }
        flags &= ~MAP_SHARED;
 
@@ -333,7 +337,7 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u
                align_goal = (64UL * 1024);
 
        do {
-               addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags);
+               addr = get_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags);
                if (!(addr & ~PAGE_MASK)) {
                        addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL);
                        break;
@@ -351,7 +355,7 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u
         * be obtained.
         */
        if (addr & ~PAGE_MASK)
-               addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags);
+               addr = get_area(NULL, orig_addr, len, pgoff, flags);
 
        return addr;
 }
@@ -399,18 +403,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        }
 }
 
-SYSCALL_DEFINE1(sparc_brk, unsigned long, brk)
-{
-       /* People could try to be nasty and use ta 0x6d in 32bit programs */
-       if (test_thread_flag(TIF_32BIT) && brk >= STACK_TOP32)
-               return current->mm->brk;
-
-       if (unlikely(straddles_64bit_va_hole(current->mm->brk, brk)))
-               return current->mm->brk;
-
-       return sys_brk(brk);
-}
-                                                                
 /*
  * sys_pipe() is the normal C calling standard for creating
  * a pipe. It's not the way unix traditionally does this, though.
@@ -568,23 +560,13 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
                unsigned long, prot, unsigned long, flags, unsigned long, fd,
                unsigned long, off)
 {
-       struct file * file = NULL;
-       unsigned long retval = -EBADF;
-
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       len = PAGE_ALIGN(len);
+       unsigned long retval = -EINVAL;
 
-       down_write(&current->mm->mmap_sem);
-       retval = do_mmap(file, addr, len, prot, flags, off);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
+       if ((off + PAGE_ALIGN(len)) < off)
+               goto out;
+       if (off & ~PAGE_MASK)
+               goto out;
+       retval = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
 out:
        return retval;
 }
@@ -614,12 +596,6 @@ SYSCALL_DEFINE5(64_mremap, unsigned long, addr,    unsigned long, old_len,
 
        if (test_thread_flag(TIF_32BIT))
                goto out;
-       if (unlikely(new_len >= VA_EXCLUDE_START))
-               goto out;
-       if (unlikely(sparc_mmap_check(addr, old_len)))
-               goto out;
-       if (unlikely(sparc_mmap_check(new_addr, new_len)))
-               goto out;
 
        down_write(&current->mm->mmap_sem);
        ret = do_mremap(addr, old_len, new_len, flags, new_addr);
index a63c5d2d984917e242441d8b85f856f109f07661..d2f999ae2b85a04495d31ab2c77ad91924342f5a 100644 (file)
@@ -9,7 +9,6 @@
 struct new_utsname;
 
 extern asmlinkage unsigned long sys_getpagesize(void);
-extern asmlinkage unsigned long sparc_brk(unsigned long brk);
 extern asmlinkage long sparc_pipe(struct pt_regs *regs);
 extern asmlinkage long sys_ipc(unsigned int call, int first,
                               unsigned long second,
index ceb1530f8aa66c00b4b016beb836f6cb14d2e85d..801fc8e5a0e87cf20fc58550b4f603a6e4085723 100644 (file)
@@ -19,7 +19,7 @@ sys_call_table:
 /*0*/  .long sys_restart_syscall, sys_exit, sys_fork, sys_read, sys_write
 /*5*/  .long sys_open, sys_close, sys_wait4, sys_creat, sys_link
 /*10*/  .long sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod
-/*15*/ .long sys_chmod, sys_lchown16, sparc_brk, sys_nis_syscall, sys_lseek
+/*15*/ .long sys_chmod, sys_lchown16, sys_brk, sys_nis_syscall, sys_lseek
 /*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16
 /*25*/ .long sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause
 /*30*/ .long sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice
@@ -67,7 +67,7 @@ sys_call_table:
 /*235*/        .long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
 /*240*/        .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 /*245*/        .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/        .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+/*250*/        .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
 /*255*/        .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep
 /*260*/        .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
 /*265*/        .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy
index cc8e7862e95a9b7da663d1b5c831929392b52554..e575b46bd7a9ebd84eb29578ef0e04952d07fff2 100644 (file)
@@ -21,7 +21,7 @@ sys_call_table32:
 /*0*/  .word sys_restart_syscall, sys32_exit, sys_fork, sys_read, sys_write
 /*5*/  .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys_link
 /*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod
-/*15*/ .word sys_chmod, sys_lchown16, sys_sparc_brk, sys32_perfctr, sys32_lseek
+/*15*/ .word sys_chmod, sys_lchown16, sys_brk, sys32_perfctr, sys32_lseek
 /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16
 /*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_pause
 /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice
@@ -68,7 +68,7 @@ sys_call_table32:
        .word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall
 /*240*/        .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler
        .word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
-/*250*/        .word sys32_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl
+/*250*/        .word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl
        .word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep
 /*260*/        .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun
        .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy
@@ -96,7 +96,7 @@ sys_call_table:
 /*0*/  .word sys_restart_syscall, sparc_exit, sys_fork, sys_read, sys_write
 /*5*/  .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
 /*10*/  .word sys_unlink, sys_nis_syscall, sys_chdir, sys_chown, sys_mknod
-/*15*/ .word sys_chmod, sys_lchown, sys_sparc_brk, sys_perfctr, sys_lseek
+/*15*/ .word sys_chmod, sys_lchown, sys_brk, sys_perfctr, sys_lseek
 /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
 /*25*/ .word sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall
 /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
index a4625c7b2bf990a78dc49f5785b48393dba00baf..cccab850c27ec221a5bf6d13a9e155a580c40a40 100644 (file)
@@ -8,6 +8,7 @@
 #include "linux/mm.h"
 #include "linux/sched.h"
 #include "linux/utsname.h"
+#include "linux/syscalls.h"
 #include "asm/current.h"
 #include "asm/mman.h"
 #include "asm/uaccess.h"
@@ -37,31 +38,6 @@ long sys_vfork(void)
        return ret;
 }
 
-/* common code for old and new mmaps */
-long sys_mmap2(unsigned long addr, unsigned long len,
-              unsigned long prot, unsigned long flags,
-              unsigned long fd, unsigned long pgoff)
-{
-       long error = -EBADF;
-       struct file * file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
- out:
-       return error;
-}
-
 long old_mmap(unsigned long addr, unsigned long len,
              unsigned long prot, unsigned long flags,
              unsigned long fd, unsigned long offset)
@@ -70,7 +46,7 @@ long old_mmap(unsigned long addr, unsigned long len,
        if (offset & ~PAGE_MASK)
                goto out;
 
-       err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+       err = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
  out:
        return err;
 }
index 905698197e35fc2f4fd612b0495bd846d3253a65..e7787679e3174b2cd891a27f8a9a380f0a390be7 100644 (file)
@@ -20,7 +20,3 @@ extern syscall_handler_t *sys_call_table[];
 #define EXECUTE_SYSCALL(syscall, regs) \
        ((long (*)(struct syscall_args)) \
         (*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
-
-extern long sys_mmap2(unsigned long addr, unsigned long len,
-                     unsigned long prot, unsigned long flags,
-                     unsigned long fd, unsigned long pgoff);
index 4eefdca9832b4430931907096cf9f616e820f87f..53147ad85b967018e2f164de0cca11c00e04dbf9 100644 (file)
@@ -696,7 +696,7 @@ ia32_sys_call_table:
        .quad quiet_ni_syscall          /* streams2 */
        .quad stub32_vfork            /* 190 */
        .quad compat_sys_getrlimit
-       .quad sys32_mmap2
+       .quad sys_mmap_pgoff
        .quad sys32_truncate64
        .quad sys32_ftruncate64
        .quad sys32_stat64              /* 195 */
index df82c0e48dedff5c7ac9ac8d89ea96be2599e3af..422572c7792389d0174fbc2933aba31d34111d88 100644 (file)
@@ -155,9 +155,6 @@ struct mmap_arg_struct {
 asmlinkage long sys32_mmap(struct mmap_arg_struct __user *arg)
 {
        struct mmap_arg_struct a;
-       struct file *file = NULL;
-       unsigned long retval;
-       struct mm_struct *mm ;
 
        if (copy_from_user(&a, arg, sizeof(a)))
                return -EFAULT;
@@ -165,22 +162,8 @@ asmlinkage long sys32_mmap(struct mmap_arg_struct __user *arg)
        if (a.offset & ~PAGE_MASK)
                return -EINVAL;
 
-       if (!(a.flags & MAP_ANONYMOUS)) {
-               file = fget(a.fd);
-               if (!file)
-                       return -EBADF;
-       }
-
-       mm = current->mm;
-       down_write(&mm->mmap_sem);
-       retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags,
+       return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
                               a.offset>>PAGE_SHIFT);
-       if (file)
-               fput(file);
-
-       up_write(&mm->mmap_sem);
-
-       return retval;
 }
 
 asmlinkage long sys32_mprotect(unsigned long start, size_t len,
@@ -483,30 +466,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd,
        return ret;
 }
 
-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
-                           unsigned long prot, unsigned long flags,
-                           unsigned long fd, unsigned long pgoff)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long error;
-       struct file *file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       return -EBADF;
-       }
-
-       down_write(&mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&mm->mmap_sem);
-
-       if (file)
-               fput(file);
-       return error;
-}
-
 asmlinkage long sys32_olduname(struct oldold_utsname __user *name)
 {
        char *arch = "x86_64";
index b399988eee3a3105e60be5fe760089d6cf57d3f0..b4bf9a942ed0810418613f75b156e328fc0fd5d9 100644 (file)
@@ -118,11 +118,27 @@ extern int __init pcibios_init(void);
 
 /* pci-mmconfig.c */
 
+/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
+#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
+
+struct pci_mmcfg_region {
+       struct list_head list;
+       struct resource res;
+       u64 address;
+       char __iomem *virt;
+       u16 segment;
+       u8 start_bus;
+       u8 end_bus;
+       char name[PCI_MMCFG_RESOURCE_NAME_LEN];
+};
+
 extern int __init pci_mmcfg_arch_init(void);
 extern void __init pci_mmcfg_arch_free(void);
+extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
+
+extern struct list_head pci_mmcfg_list;
 
-extern struct acpi_mcfg_allocation *pci_mmcfg_config;
-extern int pci_mmcfg_config_num;
+#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
 
 /*
  * AMD Fam10h CPUs are buggy, and cannot access MMIO config space
index 9af9decb38c35fd1a109839e096701a549dd258d..4a5a089e1c6273c7d7a633a5be1b3e64c7e9a6db 100644 (file)
@@ -57,9 +57,6 @@ asmlinkage long sys32_pwrite(unsigned int, char __user *, u32, u32, u32);
 asmlinkage long sys32_personality(unsigned long);
 asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32);
 
-asmlinkage long sys32_mmap2(unsigned long, unsigned long, unsigned long,
-                           unsigned long, unsigned long, unsigned long);
-
 struct oldold_utsname;
 struct old_utsname;
 asmlinkage long sys32_olduname(struct oldold_utsname __user *);
index 372b76edd63f69053c76bcf7501eb71c35bb8f93..1bb6e395881c3fb43dec70cad2aac7ac7aeb3b4e 100644 (file)
@@ -55,8 +55,6 @@ struct sel_arg_struct;
 struct oldold_utsname;
 struct old_utsname;
 
-asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long,
-                         unsigned long, unsigned long, unsigned long);
 asmlinkage int old_mmap(struct mmap_arg_struct __user *);
 asmlinkage int old_select(struct sel_arg_struct __user *);
 asmlinkage int sys_ipc(uint, int, int, int, void __user *, long);
index d5b7e90c0edfd3ca1bf7d05e3f4c4e642f8e6fb7..396ff4cc8ed480b7bc306f63091b88f6dda00442 100644 (file)
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
 
-enum xen_domain_type {
-       XEN_NATIVE,             /* running on bare hardware    */
-       XEN_PV_DOMAIN,          /* running in a PV domain      */
-       XEN_HVM_DOMAIN,         /* running in a Xen hvm domain */
-};
-
-#ifdef CONFIG_XEN
-extern enum xen_domain_type xen_domain_type;
-#else
-#define xen_domain_type                XEN_NATIVE
-#endif
-
-#define xen_domain()           (xen_domain_type != XEN_NATIVE)
-#define xen_pv_domain()                (xen_domain() &&                        \
-                                xen_domain_type == XEN_PV_DOMAIN)
-#define xen_hvm_domain()       (xen_domain() &&                        \
-                                xen_domain_type == XEN_HVM_DOMAIN)
-
-#ifdef CONFIG_XEN_DOM0
-#include <xen/interface/xen.h>
-
-#define xen_initial_domain()   (xen_pv_domain() && \
-                                xen_start_info->flags & SIF_INITDOMAIN)
-#else  /* !CONFIG_XEN_DOM0 */
-#define xen_initial_domain()   (0)
-#endif /* CONFIG_XEN_DOM0 */
-
 #endif /* _ASM_X86_XEN_HYPERVISOR_H */
index 7ffc39965233ce570a7b734f12636ce05e403d1e..9c4a6f7475525469760ca7cc43ad98d7e842c8f2 100644 (file)
@@ -1336,6 +1336,9 @@ void __init amd_iommu_detect(void)
                iommu_detected = 1;
                amd_iommu_detected = 1;
                x86_init.iommu.iommu_init = amd_iommu_init;
+
+               /* Make sure ACS will be enabled */
+               pci_request_acs();
        }
 }
 
index 1884a8d12bfaf130d99d7f9602268c5a7048271d..dee1ff7cba581829b6540b436dbbff4b5958ff4f 100644 (file)
 
 #include <asm/syscalls.h>
 
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-                         unsigned long prot, unsigned long flags,
-                         unsigned long fd, unsigned long pgoff)
-{
-       int error = -EBADF;
-       struct file *file = NULL;
-       struct mm_struct *mm = current->mm;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
 /*
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls. Linux/i386 didn't use to be able to handle more than
@@ -77,7 +52,7 @@ asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
        if (a.offset & ~PAGE_MASK)
                goto out;
 
-       err = sys_mmap2(a.addr, a.len, a.prot, a.flags,
+       err = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags,
                        a.fd, a.offset >> PAGE_SHIFT);
 out:
        return err;
index 45e00eb09c3a7037692656cee85fe8d8c2e396fe..8aa2057efd12618aa20874b8a71fc40527cc6819 100644 (file)
@@ -23,26 +23,11 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
                unsigned long, fd, unsigned long, off)
 {
        long error;
-       struct file *file;
-
        error = -EINVAL;
        if (off & ~PAGE_MASK)
                goto out;
 
-       error = -EBADF;
-       file = NULL;
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
+       error = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
 out:
        return error;
 }
index 70c2125d55b97c5a4e0bd9b25ae6f2cfe9374e14..15228b5d3eb7bf6c75954095f1c73677bc096ca7 100644 (file)
@@ -191,7 +191,7 @@ ENTRY(sys_call_table)
        .long sys_ni_syscall    /* reserved for streams2 */
        .long ptregs_vfork      /* 190 */
        .long sys_getrlimit
-       .long sys_mmap2
+       .long sys_mmap_pgoff
        .long sys_truncate64
        .long sys_ftruncate64
        .long sys_stat64        /* 195 */
index d49202e740eaf5a224897e4991c9eec951657918..564b008a51c7abdee986f03c1ccfe3a09894a93a 100644 (file)
@@ -15,3 +15,8 @@ obj-$(CONFIG_X86_NUMAQ)               += numaq_32.o
 
 obj-y                          += common.o early.o
 obj-y                          += amd_bus.o
+obj-$(CONFIG_X86_64)           += bus_numa.o intel_bus.o
+
+ifeq ($(CONFIG_PCI_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
index 1014eb4bfc37ac15cec9e3b24b3f980a1a52e7d9..959e548a7039e81a85cdd0e7eb114a86f91a05c5 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/pci_x86.h>
 
 struct pci_root_info {
+       struct acpi_device *bridge;
        char *name;
        unsigned int res_num;
        struct resource *res;
@@ -58,6 +59,30 @@ bus_has_transparent_bridge(struct pci_bus *bus)
        return false;
 }
 
+static void
+align_resource(struct acpi_device *bridge, struct resource *res)
+{
+       int align = (res->flags & IORESOURCE_MEM) ? 16 : 4;
+
+       /*
+        * Host bridge windows are not BARs, but the decoders on the PCI side
+        * that claim this address space have starting alignment and length
+        * constraints, so fix any obvious BIOS goofs.
+        */
+       if (!IS_ALIGNED(res->start, align)) {
+               dev_printk(KERN_DEBUG, &bridge->dev,
+                          "host bridge window %pR invalid; "
+                          "aligning start to %d-byte boundary\n", res, align);
+               res->start &= ~(align - 1);
+       }
+       if (!IS_ALIGNED(res->end + 1, align)) {
+               dev_printk(KERN_DEBUG, &bridge->dev,
+                          "host bridge window %pR invalid; "
+                          "aligning end to %d-byte boundary\n", res, align);
+               res->end = ALIGN(res->end, align) - 1;
+       }
+}
+
 static acpi_status
 setup_resource(struct acpi_resource *acpi_res, void *data)
 {
@@ -91,11 +116,12 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
        start = addr.minimum + addr.translation_offset;
        end = start + addr.address_length - 1;
        if (info->res_num >= max_root_bus_resources) {
-               printk(KERN_WARNING "PCI: Failed to allocate 0x%lx-0x%lx "
-                       "from %s for %s due to _CRS returning more than "
-                       "%d resource descriptors\n", (unsigned long) start,
-                       (unsigned long) end, root->name, info->name,
-                       max_root_bus_resources);
+               if (pci_probe & PCI_USE__CRS)
+                       printk(KERN_WARNING "PCI: Failed to allocate "
+                              "0x%lx-0x%lx from %s for %s due to _CRS "
+                              "returning more than %d resource descriptors\n",
+                              (unsigned long) start, (unsigned long) end,
+                              root->name, info->name, max_root_bus_resources);
                return AE_OK;
        }
 
@@ -105,14 +131,28 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
        res->start = start;
        res->end = end;
        res->child = NULL;
+       align_resource(info->bridge, res);
+
+       if (!(pci_probe & PCI_USE__CRS)) {
+               dev_printk(KERN_DEBUG, &info->bridge->dev,
+                          "host bridge window %pR (ignored)\n", res);
+               return AE_OK;
+       }
 
        if (insert_resource(root, res)) {
-               printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx "
-                       "from %s for %s\n", (unsigned long) res->start,
-                       (unsigned long) res->end, root->name, info->name);
+               dev_err(&info->bridge->dev,
+                       "can't allocate host bridge window %pR\n", res);
        } else {
                info->bus->resource[info->res_num] = res;
                info->res_num++;
+               if (addr.translation_offset)
+                       dev_info(&info->bridge->dev, "host bridge window %pR "
+                                "(PCI address [%#llx-%#llx])\n",
+                                res, res->start - addr.translation_offset,
+                                res->end - addr.translation_offset);
+               else
+                       dev_info(&info->bridge->dev,
+                                "host bridge window %pR\n", res);
        }
        return AE_OK;
 }
@@ -124,6 +164,12 @@ get_current_resources(struct acpi_device *device, int busnum,
        struct pci_root_info info;
        size_t size;
 
+       if (!(pci_probe & PCI_USE__CRS))
+               dev_info(&device->dev,
+                        "ignoring host bridge windows from ACPI; "
+                        "boot with \"pci=use_crs\" to use them\n");
+
+       info.bridge = device;
        info.bus = bus;
        info.res_num = 0;
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
@@ -163,8 +209,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
 #endif
 
        if (domain && !pci_domains_supported) {
-               printk(KERN_WARNING "PCI: Multiple domains not supported "
-                      "(dom %d, bus %d)\n", domain, busnum);
+               printk(KERN_WARNING "pci_bus %04x:%02x: "
+                      "ignored (multiple domains not supported)\n",
+                      domain, busnum);
                return NULL;
        }
 
@@ -188,7 +235,8 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
         */
        sd = kzalloc(sizeof(*sd), GFP_KERNEL);
        if (!sd) {
-               printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+               printk(KERN_WARNING "pci_bus %04x:%02x: "
+                      "ignored (out of memory)\n", domain, busnum);
                return NULL;
        }
 
@@ -209,9 +257,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
        } else {
                bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd);
                if (bus) {
-                       if (pci_probe & PCI_USE__CRS)
-                               get_current_resources(device, busnum, domain,
-                                                       bus);
+                       get_current_resources(device, busnum, domain, bus);
                        bus->subordinate = pci_scan_child_bus(bus);
                }
        }
index 572ee9782f2afdf75ca1af76ae172ce01ec9a3a8..95ecbd495955094ac22c7502fe992ea2af7ad444 100644 (file)
@@ -6,10 +6,10 @@
 
 #ifdef CONFIG_X86_64
 #include <asm/pci-direct.h>
-#include <asm/mpspec.h>
-#include <linux/cpumask.h>
 #endif
 
+#include "bus_numa.h"
+
 /*
  * This discovers the pcibus <-> node mapping on AMD K8.
  * also get peer root bus resource for io,mmio
 
 #ifdef CONFIG_X86_64
 
-/*
- * sub bus (transparent) will use entres from 3 to store extra from root,
- * so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES?
- */
-#define RES_NUM 16
-struct pci_root_info {
-       char name[12];
-       unsigned int res_num;
-       struct resource res[RES_NUM];
-       int bus_min;
-       int bus_max;
-       int node;
-       int link;
-};
-
-/* 4 at this time, it may become to 32 */
-#define PCI_ROOT_NR 4
-static int pci_root_num;
-static struct pci_root_info pci_root_info[PCI_ROOT_NR];
-
-void x86_pci_root_bus_res_quirks(struct pci_bus *b)
-{
-       int i;
-       int j;
-       struct pci_root_info *info;
-
-       /* don't go for it if _CRS is used already */
-       if (b->resource[0] != &ioport_resource ||
-           b->resource[1] != &iomem_resource)
-               return;
-
-       /* if only one root bus, don't need to anything */
-       if (pci_root_num < 2)
-               return;
-
-       for (i = 0; i < pci_root_num; i++) {
-               if (pci_root_info[i].bus_min == b->number)
-                       break;
-       }
-
-       if (i == pci_root_num)
-               return;
-
-       printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n",
-                       b->number);
-
-       info = &pci_root_info[i];
-       for (j = 0; j < info->res_num; j++) {
-               struct resource *res;
-               struct resource *root;
-
-               res = &info->res[j];
-               b->resource[j] = res;
-               if (res->flags & IORESOURCE_IO)
-                       root = &ioport_resource;
-               else
-                       root = &iomem_resource;
-               insert_resource(root, res);
-       }
-}
-
 #define RANGE_NUM 16
 
 struct res_range {
@@ -130,52 +69,6 @@ static void __init update_range(struct res_range *range, size_t start,
        }
 }
 
-static void __init update_res(struct pci_root_info *info, size_t start,
-                             size_t end, unsigned long flags, int merge)
-{
-       int i;
-       struct resource *res;
-
-       if (!merge)
-               goto addit;
-
-       /* try to merge it with old one */
-       for (i = 0; i < info->res_num; i++) {
-               size_t final_start, final_end;
-               size_t common_start, common_end;
-
-               res = &info->res[i];
-               if (res->flags != flags)
-                       continue;
-
-               common_start = max((size_t)res->start, start);
-               common_end = min((size_t)res->end, end);
-               if (common_start > common_end + 1)
-                       continue;
-
-               final_start = min((size_t)res->start, start);
-               final_end = max((size_t)res->end, end);
-
-               res->start = final_start;
-               res->end = final_end;
-               return;
-       }
-
-addit:
-
-       /* need to add that */
-       if (info->res_num >= RES_NUM)
-               return;
-
-       res = &info->res[info->res_num];
-       res->name = info->name;
-       res->flags = flags;
-       res->start = start;
-       res->end = end;
-       res->child = NULL;
-       info->res_num++;
-}
-
 struct pci_hostbridge_probe {
        u32 bus;
        u32 slot;
@@ -230,7 +123,6 @@ static int __init early_fill_mp_bus_info(void)
        int j;
        unsigned bus;
        unsigned slot;
-       int found;
        int node;
        int link;
        int def_node;
@@ -247,7 +139,7 @@ static int __init early_fill_mp_bus_info(void)
        if (!early_pci_allowed())
                return -1;
 
-       found = 0;
+       found_all_numa_early = 0;
        for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
                u32 id;
                u16 device;
@@ -261,12 +153,12 @@ static int __init early_fill_mp_bus_info(void)
                device = (id>>16) & 0xffff;
                if (pci_probes[i].vendor == vendor &&
                    pci_probes[i].device == device) {
-                       found = 1;
+                       found_all_numa_early = 1;
                        break;
                }
        }
 
-       if (!found)
+       if (!found_all_numa_early)
                return 0;
 
        pci_root_num = 0;
@@ -488,7 +380,7 @@ static int __init early_fill_mp_bus_info(void)
                info = &pci_root_info[i];
                res_num = info->res_num;
                busnum = info->bus_min;
-               printk(KERN_DEBUG "bus: [%02x,%02x] on node %x link %x\n",
+               printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n",
                       info->bus_min, info->bus_max, info->node, info->link);
                for (j = 0; j < res_num; j++) {
                        res = &info->res[j];
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
new file mode 100644 (file)
index 0000000..145df00
--- /dev/null
@@ -0,0 +1,101 @@
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include "bus_numa.h"
+
+int pci_root_num;
+struct pci_root_info pci_root_info[PCI_ROOT_NR];
+int found_all_numa_early;
+
+void x86_pci_root_bus_res_quirks(struct pci_bus *b)
+{
+       int i;
+       int j;
+       struct pci_root_info *info;
+
+       /* don't go for it if _CRS is used already */
+       if (b->resource[0] != &ioport_resource ||
+           b->resource[1] != &iomem_resource)
+               return;
+
+       if (!pci_root_num)
+               return;
+
+       /* for amd, if only one root bus, don't need to do anything */
+       if (pci_root_num < 2 && found_all_numa_early)
+               return;
+
+       for (i = 0; i < pci_root_num; i++) {
+               if (pci_root_info[i].bus_min == b->number)
+                       break;
+       }
+
+       if (i == pci_root_num)
+               return;
+
+       printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n",
+                       b->number);
+
+       info = &pci_root_info[i];
+       for (j = 0; j < info->res_num; j++) {
+               struct resource *res;
+               struct resource *root;
+
+               res = &info->res[j];
+               b->resource[j] = res;
+               if (res->flags & IORESOURCE_IO)
+                       root = &ioport_resource;
+               else
+                       root = &iomem_resource;
+               insert_resource(root, res);
+       }
+}
+
+void __init update_res(struct pci_root_info *info, size_t start,
+                             size_t end, unsigned long flags, int merge)
+{
+       int i;
+       struct resource *res;
+
+       if (start > end)
+               return;
+
+       if (!merge)
+               goto addit;
+
+       /* try to merge it with old one */
+       for (i = 0; i < info->res_num; i++) {
+               size_t final_start, final_end;
+               size_t common_start, common_end;
+
+               res = &info->res[i];
+               if (res->flags != flags)
+                       continue;
+
+               common_start = max((size_t)res->start, start);
+               common_end = min((size_t)res->end, end);
+               if (common_start > common_end + 1)
+                       continue;
+
+               final_start = min((size_t)res->start, start);
+               final_end = max((size_t)res->end, end);
+
+               res->start = final_start;
+               res->end = final_end;
+               return;
+       }
+
+addit:
+
+       /* need to add that */
+       if (info->res_num >= RES_NUM)
+               return;
+
+       res = &info->res[info->res_num];
+       res->name = info->name;
+       res->flags = flags;
+       res->start = start;
+       res->end = end;
+       res->child = NULL;
+       info->res_num++;
+}
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h
new file mode 100644 (file)
index 0000000..adbc23f
--- /dev/null
@@ -0,0 +1,27 @@
+#ifdef CONFIG_X86_64
+
+/*
+ * sub bus (transparent) will use entres from 3 to store extra from
+ * root, so need to make sure we have enough slot there, Should we
+ * increase PCI_BUS_NUM_RESOURCES?
+ */
+#define RES_NUM 16
+struct pci_root_info {
+       char name[12];
+       unsigned int res_num;
+       struct resource res[RES_NUM];
+       int bus_min;
+       int bus_max;
+       int node;
+       int link;
+};
+
+/* 4 at this time, it may become to 32 */
+#define PCI_ROOT_NR 4
+extern int pci_root_num;
+extern struct pci_root_info pci_root_info[PCI_ROOT_NR];
+extern int found_all_numa_early;
+
+extern void update_res(struct pci_root_info *info, size_t start,
+                             size_t end, unsigned long flags, int merge);
+#endif
index 1331fcf261433b72c9d0a4620326a3898f1761fa..d2552c68e94d9670a7086c2eca1258a453c1a516 100644 (file)
@@ -410,8 +410,6 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
        return bus;
 }
 
-extern u8 pci_cache_line_size;
-
 int __init pcibios_init(void)
 {
        struct cpuinfo_x86 *c = &boot_cpu_data;
@@ -422,15 +420,19 @@ int __init pcibios_init(void)
        }
 
        /*
-        * Assume PCI cacheline size of 32 bytes for all x86s except K7/K8
-        * and P4. It's also good for 386/486s (which actually have 16)
+        * Set PCI cacheline size to that of the CPU if the CPU has reported it.
+        * (For older CPUs that don't support cpuid, we se it to 32 bytes
+        * It's also good for 386/486s (which actually have 16)
         * as quite a few PCI devices do not support smaller values.
         */
-       pci_cache_line_size = 32 >> 2;
-       if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
-               pci_cache_line_size = 64 >> 2;  /* K7 & K8 */
-       else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
-               pci_cache_line_size = 128 >> 2; /* P4 */
+       if (c->x86_clflush_size > 0) {
+               pci_dfl_cache_line_size = c->x86_clflush_size >> 2;
+               printk(KERN_DEBUG "PCI: pci_cache_line_size set to %d bytes\n",
+                       pci_dfl_cache_line_size << 2);
+       } else {
+               pci_dfl_cache_line_size = 32 >> 2;
+               printk(KERN_DEBUG "PCI: Unknown cacheline size. Setting to 32 bytes\n");
+       }
 
        pcibios_resource_survey();
 
index aaf26ae58cd5cadb73ae168cd7f46edf9cc2b4f3..d1067d539bee2da24fb260ac64b2162ecf63d17b 100644 (file)
@@ -12,8 +12,6 @@ u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset)
        u32 v;
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
        v = inl(0xcfc);
-       if (v != 0xffffffff)
-               pr_debug("%x reading 4 from %x: %x\n", slot, offset, v);
        return v;
 }
 
@@ -22,7 +20,6 @@ u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset)
        u8 v;
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
        v = inb(0xcfc + (offset&3));
-       pr_debug("%x reading 1 from %x: %x\n", slot, offset, v);
        return v;
 }
 
@@ -31,28 +28,24 @@ u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset)
        u16 v;
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
        v = inw(0xcfc + (offset&2));
-       pr_debug("%x reading 2 from %x: %x\n", slot, offset, v);
        return v;
 }
 
 void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset,
                                    u32 val)
 {
-       pr_debug("%x writing to %x: %x\n", slot, offset, val);
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
        outl(val, 0xcfc);
 }
 
 void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val)
 {
-       pr_debug("%x writing to %x: %x\n", slot, offset, val);
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
        outb(val, 0xcfc + (offset&3));
 }
 
 void write_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset, u16 val)
 {
-       pr_debug("%x writing to %x: %x\n", slot, offset, val);
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
        outw(val, 0xcfc + (offset&2));
 }
index b22d13b0c71d0f538cd25f2643490d0bf2fa86a3..5dc9e8c63fcdedb26a096d48efcf2392cd8f8209 100644 (file)
@@ -129,7 +129,9 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
                                        continue;
                                if (!r->start ||
                                    pci_claim_resource(dev, idx) < 0) {
-                                       dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx);
+                                       dev_info(&dev->dev,
+                                                "can't reserve window %pR\n",
+                                                r);
                                        /*
                                         * Something is wrong with the region.
                                         * Invalidate the resource to prevent
@@ -144,16 +146,29 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
        }
 }
 
+struct pci_check_idx_range {
+       int start;
+       int end;
+};
+
 static void __init pcibios_allocate_resources(int pass)
 {
        struct pci_dev *dev = NULL;
-       int idx, disabled;
+       int idx, disabled, i;
        u16 command;
        struct resource *r;
 
+       struct pci_check_idx_range idx_range[] = {
+               { PCI_STD_RESOURCES, PCI_STD_RESOURCE_END },
+#ifdef CONFIG_PCI_IOV
+               { PCI_IOV_RESOURCES, PCI_IOV_RESOURCE_END },
+#endif
+       };
+
        for_each_pci_dev(dev) {
                pci_read_config_word(dev, PCI_COMMAND, &command);
-               for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) {
+               for (i = 0; i < ARRAY_SIZE(idx_range); i++)
+               for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) {
                        r = &dev->resource[idx];
                        if (r->parent)          /* Already allocated */
                                continue;
@@ -164,12 +179,12 @@ static void __init pcibios_allocate_resources(int pass)
                        else
                                disabled = !(command & PCI_COMMAND_MEMORY);
                        if (pass == disabled) {
-                               dev_dbg(&dev->dev, "resource %#08llx-%#08llx (f=%lx, d=%d, p=%d)\n",
-                                       (unsigned long long) r->start,
-                                       (unsigned long long) r->end,
-                                       r->flags, disabled, pass);
+                               dev_dbg(&dev->dev,
+                                       "BAR %d: reserving %pr (d=%d, p=%d)\n",
+                                       idx, r, disabled, pass);
                                if (pci_claim_resource(dev, idx) < 0) {
-                                       dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx);
+                                       dev_info(&dev->dev,
+                                                "can't reserve %pR\n", r);
                                        /* We'll assign a new address later */
                                        r->end -= r->start;
                                        r->start = 0;
@@ -182,7 +197,7 @@ static void __init pcibios_allocate_resources(int pass)
                                /* Turn the ROM off, leave the resource region,
                                 * but keep it unregistered. */
                                u32 reg;
-                               dev_dbg(&dev->dev, "disabling ROM\n");
+                               dev_dbg(&dev->dev, "disabling ROM %pR\n", r);
                                r->flags &= ~IORESOURCE_ROM_ENABLE;
                                pci_read_config_dword(dev,
                                                dev->rom_base_reg, &reg);
@@ -282,6 +297,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                return -EINVAL;
 
        prot = pgprot_val(vma->vm_page_prot);
+
+       /*
+        * Return error if pat is not enabled and write_combine is requested.
+        * Caller can followup with UC MINUS request and add a WC mtrr if there
+        * is a free mtrr slot.
+        */
+       if (!pat_enabled && write_combine)
+               return -EINVAL;
+
        if (pat_enabled && write_combine)
                prot |= _PAGE_CACHE_WC;
        else if (pat_enabled || boot_cpu_data.x86 > 3)
diff --git a/arch/x86/pci/intel_bus.c b/arch/x86/pci/intel_bus.c
new file mode 100644 (file)
index 0000000..b7a55dc
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * to read io range from IOH pci conf, need to do it after mmconfig is there
+ */
+
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/pci_x86.h>
+
+#include "bus_numa.h"
+
+static inline void print_ioh_resources(struct pci_root_info *info)
+{
+       int res_num;
+       int busnum;
+       int i;
+
+       printk(KERN_DEBUG "IOH bus: [%02x, %02x]\n",
+                       info->bus_min, info->bus_max);
+       res_num = info->res_num;
+       busnum = info->bus_min;
+       for (i = 0; i < res_num; i++) {
+               struct resource *res;
+
+               res = &info->res[i];
+               printk(KERN_DEBUG "IOH bus: %02x index %x %s: [%llx, %llx]\n",
+                       busnum, i,
+                       (res->flags & IORESOURCE_IO) ? "io port" :
+                                                       "mmio",
+                       res->start, res->end);
+       }
+}
+
+#define IOH_LIO                        0x108
+#define IOH_LMMIOL             0x10c
+#define IOH_LMMIOH             0x110
+#define IOH_LMMIOH_BASEU       0x114
+#define IOH_LMMIOH_LIMITU      0x118
+#define IOH_LCFGBUS            0x11c
+
+static void __devinit pci_root_bus_res(struct pci_dev *dev)
+{
+       u16 word;
+       u32 dword;
+       struct pci_root_info *info;
+       u16 io_base, io_end;
+       u32 mmiol_base, mmiol_end;
+       u64 mmioh_base, mmioh_end;
+       int bus_base, bus_end;
+
+       if (pci_root_num >= PCI_ROOT_NR) {
+               printk(KERN_DEBUG "intel_bus.c: PCI_ROOT_NR is too small\n");
+               return;
+       }
+
+       info = &pci_root_info[pci_root_num];
+       pci_root_num++;
+
+       pci_read_config_word(dev, IOH_LCFGBUS, &word);
+       bus_base = (word & 0xff);
+       bus_end = (word & 0xff00) >> 8;
+       sprintf(info->name, "PCI Bus #%02x", bus_base);
+       info->bus_min = bus_base;
+       info->bus_max = bus_end;
+
+       pci_read_config_word(dev, IOH_LIO, &word);
+       io_base = (word & 0xf0) << (12 - 4);
+       io_end = (word & 0xf000) | 0xfff;
+       update_res(info, io_base, io_end, IORESOURCE_IO, 0);
+
+       pci_read_config_dword(dev, IOH_LMMIOL, &dword);
+       mmiol_base = (dword & 0xff00) << (24 - 8);
+       mmiol_end = (dword & 0xff000000) | 0xffffff;
+       update_res(info, mmiol_base, mmiol_end, IORESOURCE_MEM, 0);
+
+       pci_read_config_dword(dev, IOH_LMMIOH, &dword);
+       mmioh_base = ((u64)(dword & 0xfc00)) << (26 - 10);
+       mmioh_end = ((u64)(dword & 0xfc000000) | 0x3ffffff);
+       pci_read_config_dword(dev, IOH_LMMIOH_BASEU, &dword);
+       mmioh_base |= ((u64)(dword & 0x7ffff)) << 32;
+       pci_read_config_dword(dev, IOH_LMMIOH_LIMITU, &dword);
+       mmioh_end |= ((u64)(dword & 0x7ffff)) << 32;
+       update_res(info, mmioh_base, mmioh_end, IORESOURCE_MEM, 0);
+
+       print_ioh_resources(info);
+}
+
+/* intel IOH */
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, pci_root_bus_res);
index 602c172d3bd5a5c44685893071b32b2d8827c023..b19d1e54201ee95a80d8123e9ba26716811c52fe 100644 (file)
 #include <linux/acpi.h>
 #include <linux/sfi_acpi.h>
 #include <linux/bitmap.h>
-#include <linux/sort.h>
+#include <linux/dmi.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 #include <asm/acpi.h>
 
 #define PREFIX "PCI: "
 
-/* aperture is up to 256MB but BIOS may reserve less */
-#define MMCONFIG_APER_MIN      (2 * 1024*1024)
-#define MMCONFIG_APER_MAX      (256 * 1024*1024)
-
 /* Indicate if the mmcfg resources have been placed into the resource table. */
 static int __initdata pci_mmcfg_resources_inserted;
 
-static __init int extend_mmcfg(int num)
+LIST_HEAD(pci_mmcfg_list);
+
+static __init void pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
 {
-       struct acpi_mcfg_allocation *new;
-       int new_num = pci_mmcfg_config_num + num;
+       if (cfg->res.parent)
+               release_resource(&cfg->res);
+       list_del(&cfg->list);
+       kfree(cfg);
+}
 
-       new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL);
-       if (!new)
-               return -1;
+static __init void free_all_mmcfg(void)
+{
+       struct pci_mmcfg_region *cfg, *tmp;
 
-       if (pci_mmcfg_config) {
-               memcpy(new, pci_mmcfg_config,
-                        sizeof(pci_mmcfg_config[0]) * new_num);
-               kfree(pci_mmcfg_config);
+       pci_mmcfg_arch_free();
+       list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list)
+               pci_mmconfig_remove(cfg);
+}
+
+static __init void list_add_sorted(struct pci_mmcfg_region *new)
+{
+       struct pci_mmcfg_region *cfg;
+
+       /* keep list sorted by segment and starting bus number */
+       list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+               if (cfg->segment > new->segment ||
+                   (cfg->segment == new->segment &&
+                    cfg->start_bus >= new->start_bus)) {
+                       list_add_tail(&new->list, &cfg->list);
+                       return;
+               }
        }
-       pci_mmcfg_config = new;
+       list_add_tail(&new->list, &pci_mmcfg_list);
+}
 
-       return 0;
+static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+                                                       int end, u64 addr)
+{
+       struct pci_mmcfg_region *new;
+       int num_buses;
+       struct resource *res;
+
+       if (addr == 0)
+               return NULL;
+
+       new = kzalloc(sizeof(*new), GFP_KERNEL);
+       if (!new)
+               return NULL;
+
+       new->address = addr;
+       new->segment = segment;
+       new->start_bus = start;
+       new->end_bus = end;
+
+       list_add_sorted(new);
+
+       num_buses = end - start + 1;
+       res = &new->res;
+       res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
+       res->end = addr + PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
+       res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+       snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
+                "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
+       res->name = new->name;
+
+       printk(KERN_INFO PREFIX "MMCONFIG for domain %04x [bus %02x-%02x] at "
+              "%pR (base %#lx)\n", segment, start, end, &new->res,
+              (unsigned long) addr);
+
+       return new;
 }
 
-static __init void fill_one_mmcfg(u64 addr, int segment, int start, int end)
+struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
 {
-       int i = pci_mmcfg_config_num;
+       struct pci_mmcfg_region *cfg;
 
-       pci_mmcfg_config_num++;
-       pci_mmcfg_config[i].address = addr;
-       pci_mmcfg_config[i].pci_segment = segment;
-       pci_mmcfg_config[i].start_bus_number = start;
-       pci_mmcfg_config[i].end_bus_number = end;
+       list_for_each_entry(cfg, &pci_mmcfg_list, list)
+               if (cfg->segment == segment &&
+                   cfg->start_bus <= bus && bus <= cfg->end_bus)
+                       return cfg;
+
+       return NULL;
 }
 
 static const char __init *pci_mmcfg_e7520(void)
@@ -68,11 +118,9 @@ static const char __init *pci_mmcfg_e7520(void)
        if (win == 0x0000 || win == 0xf000)
                return NULL;
 
-       if (extend_mmcfg(1) == -1)
+       if (pci_mmconfig_add(0, 0, 255, win << 16) == NULL)
                return NULL;
 
-       fill_one_mmcfg(win << 16, 0, 0, 255);
-
        return "Intel Corporation E7520 Memory Controller Hub";
 }
 
@@ -114,11 +162,9 @@ static const char __init *pci_mmcfg_intel_945(void)
        if ((pciexbar & mask) >= 0xf0000000U)
                return NULL;
 
-       if (extend_mmcfg(1) == -1)
+       if (pci_mmconfig_add(0, 0, (len >> 20) - 1, pciexbar & mask) == NULL)
                return NULL;
 
-       fill_one_mmcfg(pciexbar & mask, 0, 0, (len >> 20) - 1);
-
        return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
 }
 
@@ -127,7 +173,7 @@ static const char __init *pci_mmcfg_amd_fam10h(void)
        u32 low, high, address;
        u64 base, msr;
        int i;
-       unsigned segnbits = 0, busnbits;
+       unsigned segnbits = 0, busnbits, end_bus;
 
        if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
                return NULL;
@@ -161,11 +207,13 @@ static const char __init *pci_mmcfg_amd_fam10h(void)
                busnbits = 8;
        }
 
-       if (extend_mmcfg(1 << segnbits) == -1)
-               return NULL;
-
+       end_bus = (1 << busnbits) - 1;
        for (i = 0; i < (1 << segnbits); i++)
-               fill_one_mmcfg(base + (1<<28) * i, i, 0, (1 << busnbits) - 1);
+               if (pci_mmconfig_add(i, 0, end_bus,
+                                    base + (1<<28) * i) == NULL) {
+                       free_all_mmcfg();
+                       return NULL;
+               }
 
        return "AMD Family 10h NB";
 }
@@ -190,7 +238,7 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void)
        /*
         * do check if amd fam10h already took over
         */
-       if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked)
+       if (!acpi_disabled || !list_empty(&pci_mmcfg_list) || mcp55_checked)
                return NULL;
 
        mcp55_checked = true;
@@ -213,16 +261,14 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void)
                if (!(extcfg & extcfg_enable_mask))
                        continue;
 
-               if (extend_mmcfg(1) == -1)
-                       continue;
-
                size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift;
                base = extcfg & extcfg_base_mask[size_index];
                /* base could > 4G */
                base <<= extcfg_base_lshift;
                start = (extcfg & extcfg_start_mask) >> extcfg_start_shift;
                end = start + extcfg_sizebus[size_index] - 1;
-               fill_one_mmcfg(base, 0, start, end);
+               if (pci_mmconfig_add(0, start, end, base) == NULL)
+                       continue;
                mcp55_mmconf_found++;
        }
 
@@ -253,45 +299,27 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
          0x0369, pci_mmcfg_nvidia_mcp55 },
 };
 
-static int __init cmp_mmcfg(const void *x1, const void *x2)
-{
-       const typeof(pci_mmcfg_config[0]) *m1 = x1;
-       const typeof(pci_mmcfg_config[0]) *m2 = x2;
-       int start1, start2;
-
-       start1 = m1->start_bus_number;
-       start2 = m2->start_bus_number;
-
-       return start1 - start2;
-}
-
 static void __init pci_mmcfg_check_end_bus_number(void)
 {
-       int i;
-       typeof(pci_mmcfg_config[0]) *cfg, *cfgx;
-
-       /* sort them at first */
-       sort(pci_mmcfg_config, pci_mmcfg_config_num,
-                sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL);
+       struct pci_mmcfg_region *cfg, *cfgx;
 
        /* last one*/
-       if (pci_mmcfg_config_num > 0) {
-               i = pci_mmcfg_config_num - 1;
-               cfg = &pci_mmcfg_config[i];
-               if (cfg->end_bus_number < cfg->start_bus_number)
-                       cfg->end_bus_number = 255;
-       }
+       cfg = list_entry(pci_mmcfg_list.prev, typeof(*cfg), list);
+       if (cfg)
+               if (cfg->end_bus < cfg->start_bus)
+                       cfg->end_bus = 255;
 
-       /* don't overlap please */
-       for (i = 0; i < pci_mmcfg_config_num - 1; i++) {
-               cfg = &pci_mmcfg_config[i];
-               cfgx = &pci_mmcfg_config[i+1];
+       if (list_is_singular(&pci_mmcfg_list))
+               return;
 
-               if (cfg->end_bus_number < cfg->start_bus_number)
-                       cfg->end_bus_number = 255;
+       /* don't overlap please */
+       list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+               if (cfg->end_bus < cfg->start_bus)
+                       cfg->end_bus = 255;
 
-               if (cfg->end_bus_number >= cfgx->start_bus_number)
-                       cfg->end_bus_number = cfgx->start_bus_number - 1;
+               cfgx = list_entry(cfg->list.next, typeof(*cfg), list);
+               if (cfg != cfgx && cfg->end_bus >= cfgx->start_bus)
+                       cfg->end_bus = cfgx->start_bus - 1;
        }
 }
 
@@ -306,8 +334,7 @@ static int __init pci_mmcfg_check_hostbridge(void)
        if (!raw_pci_ops)
                return 0;
 
-       pci_mmcfg_config_num = 0;
-       pci_mmcfg_config = NULL;
+       free_all_mmcfg();
 
        for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
                bus =  pci_mmcfg_probes[i].bus;
@@ -322,45 +349,22 @@ static int __init pci_mmcfg_check_hostbridge(void)
                        name = pci_mmcfg_probes[i].probe();
 
                if (name)
-                       printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n",
+                       printk(KERN_INFO PREFIX "%s with MMCONFIG support\n",
                               name);
        }
 
        /* some end_bus_number is crazy, fix it */
        pci_mmcfg_check_end_bus_number();
 
-       return pci_mmcfg_config_num != 0;
+       return !list_empty(&pci_mmcfg_list);
 }
 
 static void __init pci_mmcfg_insert_resources(void)
 {
-#define PCI_MMCFG_RESOURCE_NAME_LEN 24
-       int i;
-       struct resource *res;
-       char *names;
-       unsigned num_buses;
-
-       res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
-                       pci_mmcfg_config_num, GFP_KERNEL);
-       if (!res) {
-               printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
-               return;
-       }
+       struct pci_mmcfg_region *cfg;
 
-       names = (void *)&res[pci_mmcfg_config_num];
-       for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
-               struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
-               num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
-               res->name = names;
-               snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN,
-                        "PCI MMCONFIG %u [%02x-%02x]", cfg->pci_segment,
-                        cfg->start_bus_number, cfg->end_bus_number);
-               res->start = cfg->address + (cfg->start_bus_number << 20);
-               res->end = res->start + (num_buses << 20) - 1;
-               res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-               insert_resource(&iomem_resource, res);
-               names += PCI_MMCFG_RESOURCE_NAME_LEN;
-       }
+       list_for_each_entry(cfg, &pci_mmcfg_list, list)
+               insert_resource(&iomem_resource, &cfg->res);
 
        /* Mark that the resources have been inserted. */
        pci_mmcfg_resources_inserted = 1;
@@ -437,11 +441,12 @@ static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
 typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
 
 static int __init is_mmconf_reserved(check_reserved_t is_reserved,
-               u64 addr, u64 size, int i,
-               typeof(pci_mmcfg_config[0]) *cfg, int with_e820)
+                                   struct pci_mmcfg_region *cfg, int with_e820)
 {
+       u64 addr = cfg->res.start;
+       u64 size = resource_size(&cfg->res);
        u64 old_size = size;
-       int valid = 0;
+       int valid = 0, num_buses;
 
        while (!is_reserved(addr, addr + size, E820_RESERVED)) {
                size >>= 1;
@@ -450,19 +455,25 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved,
        }
 
        if (size >= (16UL<<20) || size == old_size) {
-               printk(KERN_NOTICE
-                      "PCI: MCFG area at %Lx reserved in %s\n",
-                       addr, with_e820?"E820":"ACPI motherboard resources");
+               printk(KERN_INFO PREFIX "MMCONFIG at %pR reserved in %s\n",
+                      &cfg->res,
+                      with_e820 ? "E820" : "ACPI motherboard resources");
                valid = 1;
 
                if (old_size != size) {
-                       /* update end_bus_number */
-                       cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1);
-                       printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx "
-                              "segment %hu buses %u - %u\n",
-                              i, (unsigned long)cfg->address, cfg->pci_segment,
-                              (unsigned int)cfg->start_bus_number,
-                              (unsigned int)cfg->end_bus_number);
+                       /* update end_bus */
+                       cfg->end_bus = cfg->start_bus + ((size>>20) - 1);
+                       num_buses = cfg->end_bus - cfg->start_bus + 1;
+                       cfg->res.end = cfg->res.start +
+                           PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
+                       snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN,
+                                "PCI MMCONFIG %04x [bus %02x-%02x]",
+                                cfg->segment, cfg->start_bus, cfg->end_bus);
+                       printk(KERN_INFO PREFIX
+                              "MMCONFIG for %04x [bus%02x-%02x] "
+                              "at %pR (base %#lx) (size reduced!)\n",
+                              cfg->segment, cfg->start_bus, cfg->end_bus,
+                              &cfg->res, (unsigned long) cfg->address);
                }
        }
 
@@ -471,45 +482,26 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved,
 
 static void __init pci_mmcfg_reject_broken(int early)
 {
-       typeof(pci_mmcfg_config[0]) *cfg;
-       int i;
+       struct pci_mmcfg_region *cfg;
 
-       if ((pci_mmcfg_config_num == 0) ||
-           (pci_mmcfg_config == NULL) ||
-           (pci_mmcfg_config[0].address == 0))
-               return;
-
-       for (i = 0; i < pci_mmcfg_config_num; i++) {
+       list_for_each_entry(cfg, &pci_mmcfg_list, list) {
                int valid = 0;
-               u64 addr, size;
-
-               cfg = &pci_mmcfg_config[i];
-               addr = cfg->start_bus_number;
-               addr <<= 20;
-               addr += cfg->address;
-               size = cfg->end_bus_number + 1 - cfg->start_bus_number;
-               size <<= 20;
-               printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
-                      "segment %hu buses %u - %u\n",
-                      i, (unsigned long)cfg->address, cfg->pci_segment,
-                      (unsigned int)cfg->start_bus_number,
-                      (unsigned int)cfg->end_bus_number);
 
                if (!early && !acpi_disabled)
-                       valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0);
+                       valid = is_mmconf_reserved(is_acpi_reserved, cfg, 0);
 
                if (valid)
                        continue;
 
                if (!early)
-                       printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
-                              " reserved in ACPI motherboard resources\n",
-                              cfg->address);
+                       printk(KERN_ERR FW_BUG PREFIX
+                              "MMCONFIG at %pR not reserved in "
+                              "ACPI motherboard resources\n", &cfg->res);
 
                /* Don't try to do this check unless configuration
                   type 1 is available. how about type 2 ?*/
                if (raw_pci_ops)
-                       valid = is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1);
+                       valid = is_mmconf_reserved(e820_all_mapped, cfg, 1);
 
                if (!valid)
                        goto reject;
@@ -518,34 +510,41 @@ static void __init pci_mmcfg_reject_broken(int early)
        return;
 
 reject:
-       printk(KERN_INFO "PCI: Not using MMCONFIG.\n");
-       pci_mmcfg_arch_free();
-       kfree(pci_mmcfg_config);
-       pci_mmcfg_config = NULL;
-       pci_mmcfg_config_num = 0;
+       printk(KERN_INFO PREFIX "not using MMCONFIG\n");
+       free_all_mmcfg();
 }
 
 static int __initdata known_bridge;
 
-static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
+static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
+                                       struct acpi_mcfg_allocation *cfg)
+{
+       int year;
 
-/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
-struct acpi_mcfg_allocation *pci_mmcfg_config;
-int pci_mmcfg_config_num;
+       if (cfg->address < 0xFFFFFFFF)
+               return 0;
 
-static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
-{
        if (!strcmp(mcfg->header.oem_id, "SGI"))
-               acpi_mcfg_64bit_base_addr = TRUE;
+               return 0;
 
-       return 0;
+       if (mcfg->header.revision >= 1) {
+               if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
+                   year >= 2010)
+                       return 0;
+       }
+
+       printk(KERN_ERR PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
+              "is above 4GB, ignored\n", cfg->pci_segment,
+              cfg->start_bus_number, cfg->end_bus_number, cfg->address);
+       return -EINVAL;
 }
 
 static int __init pci_parse_mcfg(struct acpi_table_header *header)
 {
        struct acpi_table_mcfg *mcfg;
+       struct acpi_mcfg_allocation *cfg_table, *cfg;
        unsigned long i;
-       int config_size;
+       int entries;
 
        if (!header)
                return -EINVAL;
@@ -553,38 +552,33 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header)
        mcfg = (struct acpi_table_mcfg *)header;
 
        /* how many config structures do we have */
-       pci_mmcfg_config_num = 0;
+       free_all_mmcfg();
+       entries = 0;
        i = header->length - sizeof(struct acpi_table_mcfg);
        while (i >= sizeof(struct acpi_mcfg_allocation)) {
-               ++pci_mmcfg_config_num;
+               entries++;
                i -= sizeof(struct acpi_mcfg_allocation);
        };
-       if (pci_mmcfg_config_num == 0) {
+       if (entries == 0) {
                printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
                return -ENODEV;
        }
 
-       config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
-       pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL);
-       if (!pci_mmcfg_config) {
-               printk(KERN_WARNING PREFIX
-                      "No memory for MCFG config tables\n");
-               return -ENOMEM;
-       }
-
-       memcpy(pci_mmcfg_config, &mcfg[1], config_size);
-
-       acpi_mcfg_oem_check(mcfg);
-
-       for (i = 0; i < pci_mmcfg_config_num; ++i) {
-               if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) &&
-                   !acpi_mcfg_64bit_base_addr) {
-                       printk(KERN_ERR PREFIX
-                              "MMCONFIG not in low 4GB of memory\n");
-                       kfree(pci_mmcfg_config);
-                       pci_mmcfg_config_num = 0;
+       cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
+       for (i = 0; i < entries; i++) {
+               cfg = &cfg_table[i];
+               if (acpi_mcfg_check_entry(mcfg, cfg)) {
+                       free_all_mmcfg();
                        return -ENODEV;
                }
+
+               if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
+                                  cfg->end_bus_number, cfg->address) == NULL) {
+                       printk(KERN_WARNING PREFIX
+                              "no memory for MCFG entries\n");
+                       free_all_mmcfg();
+                       return -ENOMEM;
+               }
        }
 
        return 0;
@@ -614,9 +608,7 @@ static void __init __pci_mmcfg_init(int early)
 
        pci_mmcfg_reject_broken(early);
 
-       if ((pci_mmcfg_config_num == 0) ||
-           (pci_mmcfg_config == NULL) ||
-           (pci_mmcfg_config[0].address == 0))
+       if (list_empty(&pci_mmcfg_list))
                return;
 
        if (pci_mmcfg_arch_init())
@@ -648,9 +640,7 @@ static int __init pci_mmcfg_late_insert_resources(void)
         */
        if ((pci_mmcfg_resources_inserted == 1) ||
            (pci_probe & PCI_PROBE_MMCONF) == 0 ||
-           (pci_mmcfg_config_num == 0) ||
-           (pci_mmcfg_config == NULL) ||
-           (pci_mmcfg_config[0].address == 0))
+           list_empty(&pci_mmcfg_list))
                return 1;
 
        /*
index f10a7e94a84c51d9b87a041a19b3c7b89b283d8b..90d5fd476ed4fe3a093b514f095ca3d237023f54 100644 (file)
@@ -27,18 +27,10 @@ static int mmcfg_last_accessed_cpu;
  */
 static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
 {
-       struct acpi_mcfg_allocation *cfg;
-       int cfg_num;
-
-       for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
-               cfg = &pci_mmcfg_config[cfg_num];
-               if (cfg->pci_segment == seg &&
-                   (cfg->start_bus_number <= bus) &&
-                   (cfg->end_bus_number >= bus))
-                       return cfg->address;
-       }
+       struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
 
-       /* Fall back to type 0 */
+       if (cfg)
+               return cfg->address;
        return 0;
 }
 
@@ -47,7 +39,7 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
  */
 static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
 {
-       u32 dev_base = base | (bus << 20) | (devfn << 12);
+       u32 dev_base = base | PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12);
        int cpu = smp_processor_id();
        if (dev_base != mmcfg_last_accessed_device ||
            cpu != mmcfg_last_accessed_cpu) {
index 94349f8b2f964b969f7cc576ad92a50cfac75049..e783841bd1d7c42ea8ca4607d884ffe1e65ba97f 100644 (file)
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
-/* Static virtual mapping of the MMCONFIG aperture */
-struct mmcfg_virt {
-       struct acpi_mcfg_allocation *cfg;
-       char __iomem *virt;
-};
-static struct mmcfg_virt *pci_mmcfg_virt;
-
-static char __iomem *get_virt(unsigned int seg, unsigned bus)
-{
-       struct acpi_mcfg_allocation *cfg;
-       int cfg_num;
-
-       for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
-               cfg = pci_mmcfg_virt[cfg_num].cfg;
-               if (cfg->pci_segment == seg &&
-                   (cfg->start_bus_number <= bus) &&
-                   (cfg->end_bus_number >= bus))
-                       return pci_mmcfg_virt[cfg_num].virt;
-       }
-
-       /* Fall back to type 0 */
-       return NULL;
-}
+#define PREFIX "PCI: "
 
 static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
 {
-       char __iomem *addr;
+       struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
 
-       addr = get_virt(seg, bus);
-       if (!addr)
-               return NULL;
-       return addr + ((bus << 20) | (devfn << 12));
+       if (cfg && cfg->virt)
+               return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12));
+       return NULL;
 }
 
 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
@@ -109,42 +86,30 @@ static struct pci_raw_ops pci_mmcfg = {
        .write =        pci_mmcfg_write,
 };
 
-static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
+static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg)
 {
        void __iomem *addr;
        u64 start, size;
+       int num_buses;
 
-       start = cfg->start_bus_number;
-       start <<= 20;
-       start += cfg->address;
-       size = cfg->end_bus_number + 1 - cfg->start_bus_number;
-       size <<= 20;
+       start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
+       num_buses = cfg->end_bus - cfg->start_bus + 1;
+       size = PCI_MMCFG_BUS_OFFSET(num_buses);
        addr = ioremap_nocache(start, size);
-       if (addr) {
-               printk(KERN_INFO "PCI: Using MMCONFIG at %Lx - %Lx\n",
-                      start, start + size - 1);
-               addr -= cfg->start_bus_number << 20;
-       }
+       if (addr)
+               addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
        return addr;
 }
 
 int __init pci_mmcfg_arch_init(void)
 {
-       int i;
-       pci_mmcfg_virt = kzalloc(sizeof(*pci_mmcfg_virt) *
-                                pci_mmcfg_config_num, GFP_KERNEL);
-       if (pci_mmcfg_virt == NULL) {
-               printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
-               return 0;
-       }
+       struct pci_mmcfg_region *cfg;
 
-       for (i = 0; i < pci_mmcfg_config_num; ++i) {
-               pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
-               pci_mmcfg_virt[i].virt = mcfg_ioremap(&pci_mmcfg_config[i]);
-               if (!pci_mmcfg_virt[i].virt) {
-                       printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
-                                       "segment %d\n",
-                               pci_mmcfg_config[i].pci_segment);
+       list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+               cfg->virt = mcfg_ioremap(cfg);
+               if (!cfg->virt) {
+                       printk(KERN_ERR PREFIX "can't map MMCONFIG at %pR\n",
+                              &cfg->res);
                        pci_mmcfg_arch_free();
                        return 0;
                }
@@ -155,19 +120,12 @@ int __init pci_mmcfg_arch_init(void)
 
 void __init pci_mmcfg_arch_free(void)
 {
-       int i;
-
-       if (pci_mmcfg_virt == NULL)
-               return;
+       struct pci_mmcfg_region *cfg;
 
-       for (i = 0; i < pci_mmcfg_config_num; ++i) {
-               if (pci_mmcfg_virt[i].virt) {
-                       iounmap(pci_mmcfg_virt[i].virt + (pci_mmcfg_virt[i].cfg->start_bus_number << 20));
-                       pci_mmcfg_virt[i].virt = NULL;
-                       pci_mmcfg_virt[i].cfg = NULL;
+       list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+               if (cfg->virt) {
+                       iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
+                       cfg->virt = NULL;
                }
        }
-
-       kfree(pci_mmcfg_virt);
-       pci_mmcfg_virt = NULL;
 }
index b8e45f164e2acc360bcc5c380a864a635761f134..2b26dd5930c6e82e87f0e20505ab5954e6213a83 100644 (file)
@@ -27,7 +27,9 @@
 #include <linux/page-flags.h>
 #include <linux/highmem.h>
 #include <linux/console.h>
+#include <linux/pci.h>
 
+#include <xen/xen.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/version.h>
 #include <xen/interface/physdev.h>
@@ -1175,7 +1177,11 @@ asmlinkage void __init xen_start_kernel(void)
                add_preferred_console("xenboot", 0, NULL);
                add_preferred_console("tty", 0, NULL);
                add_preferred_console("hvc", 0, NULL);
+       } else {
+               /* Make sure ACS will be enabled */
+               pci_request_acs();
        }
+               
 
        xen_raw_console_write("about to get started...\n");
 
index 05cebf8f62b195f7c86ffd601d0331cb65a29d1b..4352dbe1186ae07d571abe2c1031f94e73df24ac 100644 (file)
@@ -13,8 +13,6 @@ struct sigaction;
 asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*);
 asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*);
 asmlinkage long xtensa_pipe(int __user *);
-asmlinkage long xtensa_mmap2(unsigned long, unsigned long, unsigned long,
-                            unsigned long, unsigned long, unsigned long);
 asmlinkage long xtensa_ptrace(long, long, long, long);
 asmlinkage long xtensa_sigreturn(struct pt_regs*);
 asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);
index 4e55dc763021376d8dde31d4c333dd0ca4c495bc..fbf318b3af3e3b688515e7b4e26dd5d0097ef1ff 100644 (file)
@@ -189,7 +189,7 @@ __SYSCALL( 79, sys_fremovexattr, 2)
 /* File Map / Shared Memory Operations */
 
 #define __NR_mmap2                              80
-__SYSCALL( 80, xtensa_mmap2, 6)
+__SYSCALL( 80, sys_mmap_pgoff, 6)
 #define __NR_munmap                             81
 __SYSCALL( 81, sys_munmap, 2)
 #define __NR_mprotect                           82
index ac15ecbdf9199871f3e31ef7e013fd62e1ce3b06..1e67bab775c18fc47a79d6701c30264d20350377 100644 (file)
@@ -57,31 +57,6 @@ asmlinkage long xtensa_pipe(int __user *userfds)
        return error;
 }
 
-
-asmlinkage long xtensa_mmap2(unsigned long addr, unsigned long len,
-                            unsigned long prot, unsigned long flags,
-                            unsigned long fd, unsigned long pgoff)
-{
-       int error = -EBADF;
-       struct file * file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
 asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
 {
        unsigned long ret;
index 7702118509a0a6e848bee454a983f0ec42e9522b..c7b10b4298e991320cd45af4fcc5168118d4e4b3 100644 (file)
@@ -19,6 +19,7 @@ obj-y                         += acpi.o \
 
 # All the builtin files are in the "acpi." module_param namespace.
 acpi-y                         += osl.o utils.o reboot.o
+acpi-y                         += hest.o
 
 # sleep related files
 acpi-y                         += wakeup.o
diff --git a/drivers/acpi/hest.c b/drivers/acpi/hest.c
new file mode 100644 (file)
index 0000000..4bb18c9
--- /dev/null
@@ -0,0 +1,135 @@
+#include <linux/acpi.h>
+#include <linux/pci.h>
+
+#define PREFIX "ACPI: "
+
+static inline unsigned long parse_acpi_hest_ia_machine_check(struct acpi_hest_ia_machine_check *p)
+{
+       return sizeof(*p) +
+               (sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks);
+}
+
+static inline unsigned long parse_acpi_hest_ia_corrected(struct acpi_hest_ia_corrected *p)
+{
+       return sizeof(*p) +
+               (sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks);
+}
+
+static inline unsigned long parse_acpi_hest_ia_nmi(struct acpi_hest_ia_nmi *p)
+{
+       return sizeof(*p);
+}
+
+static inline unsigned long parse_acpi_hest_generic(struct acpi_hest_generic *p)
+{
+       return sizeof(*p);
+}
+
+static inline unsigned int hest_match_pci(struct acpi_hest_aer_common *p, struct pci_dev *pci)
+{
+       return  (0           == pci_domain_nr(pci->bus) &&
+                p->bus      == pci->bus->number &&
+                p->device   == PCI_SLOT(pci->devfn) &&
+                p->function == PCI_FUNC(pci->devfn));
+}
+
+static unsigned long parse_acpi_hest_aer(void *hdr, int type, struct pci_dev *pci, int *firmware_first)
+{
+       struct acpi_hest_aer_common *p = hdr + sizeof(struct acpi_hest_header);
+       unsigned long rc=0;
+       u8 pcie_type = 0;
+       u8 bridge = 0;
+       switch (type) {
+       case ACPI_HEST_TYPE_AER_ROOT_PORT:
+               rc = sizeof(struct acpi_hest_aer_root);
+               pcie_type = PCI_EXP_TYPE_ROOT_PORT;
+               break;
+       case ACPI_HEST_TYPE_AER_ENDPOINT:
+               rc = sizeof(struct acpi_hest_aer);
+               pcie_type = PCI_EXP_TYPE_ENDPOINT;
+               break;
+       case ACPI_HEST_TYPE_AER_BRIDGE:
+               rc = sizeof(struct acpi_hest_aer_bridge);
+               if ((pci->class >> 16) == PCI_BASE_CLASS_BRIDGE)
+                       bridge = 1;
+               break;
+       }
+
+       if (p->flags & ACPI_HEST_GLOBAL) {
+               if ((pci->is_pcie && (pci->pcie_type == pcie_type)) || bridge)
+                       *firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
+       }
+       else
+               if (hest_match_pci(p, pci))
+                       *firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
+       return rc;
+}
+
+static int acpi_hest_firmware_first(struct acpi_table_header *stdheader, struct pci_dev *pci)
+{
+       struct acpi_table_hest *hest = (struct acpi_table_hest *)stdheader;
+       void *p = (void *)hest + sizeof(*hest); /* defined by the ACPI 4.0 spec */
+       struct acpi_hest_header *hdr = p;
+
+       int i;
+       int firmware_first = 0;
+       static unsigned char printed_unused = 0;
+       static unsigned char printed_reserved = 0;
+
+       for (i=0, hdr=p; p < (((void *)hest) + hest->header.length) && i < hest->error_source_count; i++) {
+               switch (hdr->type) {
+               case ACPI_HEST_TYPE_IA32_CHECK:
+                       p += parse_acpi_hest_ia_machine_check(p);
+                       break;
+               case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK:
+                       p += parse_acpi_hest_ia_corrected(p);
+                       break;
+               case ACPI_HEST_TYPE_IA32_NMI:
+                       p += parse_acpi_hest_ia_nmi(p);
+                       break;
+               /* These three should never appear */
+               case ACPI_HEST_TYPE_NOT_USED3:
+               case ACPI_HEST_TYPE_NOT_USED4:
+               case ACPI_HEST_TYPE_NOT_USED5:
+                       if (!printed_unused) {
+                               printk(KERN_DEBUG PREFIX
+                                      "HEST Error Source list contains an obsolete type (%d).\n", hdr->type);
+                               printed_unused = 1;
+                       }
+                       break;
+               case ACPI_HEST_TYPE_AER_ROOT_PORT:
+               case ACPI_HEST_TYPE_AER_ENDPOINT:
+               case ACPI_HEST_TYPE_AER_BRIDGE:
+                       p += parse_acpi_hest_aer(p, hdr->type, pci, &firmware_first);
+                       break;
+               case ACPI_HEST_TYPE_GENERIC_ERROR:
+                       p += parse_acpi_hest_generic(p);
+                       break;
+               /* These should never appear either */
+               case ACPI_HEST_TYPE_RESERVED:
+               default:
+                       if (!printed_reserved) {
+                               printk(KERN_DEBUG PREFIX
+                                      "HEST Error Source list contains a reserved type (%d).\n", hdr->type);
+                               printed_reserved = 1;
+                       }
+                       break;
+               }
+       }
+       return firmware_first;
+}
+
+int acpi_hest_firmware_first_pci(struct pci_dev *pci)
+{
+       acpi_status status = AE_NOT_FOUND;
+       struct acpi_table_header *hest = NULL;
+       status = acpi_get_table(ACPI_SIG_HEST, 1, &hest);
+
+       if (ACPI_SUCCESS(status)) {
+               if (acpi_hest_firmware_first(hest, pci)) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_hest_firmware_first_pci);
index b8578bb3f4c9c4393c83be80ddaa36eccc073264..05a31e55d27817bed3f8157c91389c31f0adb1f8 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/module.h>
 #include <linux/scatterlist.h>
 
+#include <xen/xen.h>
 #include <xen/xenbus.h>
 #include <xen/grant_table.h>
 #include <xen/events.h>
index a6ee32b599a880c13f3595fa43aaa9717b7fb1f0..b1a71638c772b8ed5be135408c612130d7b2ec8b 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/types.h>
 
 #include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
 #include <xen/page.h>
 #include <xen/events.h>
 #include <xen/interface/io/console.h>
index 91567ac806f15b83b066d8a59f9961192f53b077..470ef6779db33d11e2bcbc60610f8671c34d10ef 100644 (file)
@@ -31,3 +31,5 @@ obj-$(CONFIG_DRM_I915)  += i915/
 obj-$(CONFIG_DRM_SIS)   += sis/
 obj-$(CONFIG_DRM_SAVAGE)+= savage/
 obj-$(CONFIG_DRM_VIA)  +=via/
+obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
+obj-y                  += i2c/
diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
new file mode 100644 (file)
index 0000000..6d2abaf
--- /dev/null
@@ -0,0 +1,4 @@
+ccflags-y := -Iinclude/drm
+
+ch7006-y := ch7006_drv.o ch7006_mode.o
+obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
new file mode 100644 (file)
index 0000000..9422a74
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2009 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "ch7006_priv.h"
+
+/* DRM encoder functions */
+
+static void ch7006_encoder_set_config(struct drm_encoder *encoder,
+                                     void *params)
+{
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+
+       priv->params = params;
+}
+
+static void ch7006_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+
+       drm_property_destroy(encoder->dev, priv->scale_property);
+
+       kfree(priv);
+       to_encoder_slave(encoder)->slave_priv = NULL;
+
+       drm_i2c_encoder_destroy(encoder);
+}
+
+static void  ch7006_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       struct ch7006_state *state = &priv->state;
+
+       ch7006_dbg(client, "\n");
+
+       if (mode == priv->last_dpms)
+               return;
+       priv->last_dpms = mode;
+
+       ch7006_setup_power_state(encoder);
+
+       ch7006_load_reg(client, state, CH7006_POWER);
+}
+
+static void ch7006_encoder_save(struct drm_encoder *encoder)
+{
+       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+
+       ch7006_dbg(client, "\n");
+
+       ch7006_state_save(client, &priv->saved_state);
+}
+
+static void ch7006_encoder_restore(struct drm_encoder *encoder)
+{
+       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+
+       ch7006_dbg(client, "\n");
+
+       ch7006_state_load(client, &priv->saved_state);
+}
+
+static bool ch7006_encoder_mode_fixup(struct drm_encoder *encoder,
+                                     struct drm_display_mode *mode,
+                                     struct drm_display_mode *adjusted_mode)
+{
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+
+       /* The ch7006 is painfully picky with the input timings so no
+        * custom modes for now... */
+
+       priv->mode = ch7006_lookup_mode(encoder, mode);
+
+       return !!priv->mode;
+}
+
+static int ch7006_encoder_mode_valid(struct drm_encoder *encoder,
+                                    struct drm_display_mode *mode)
+{
+       if (ch7006_lookup_mode(encoder, mode))
+               return MODE_OK;
+       else
+               return MODE_BAD;
+}
+
+static void ch7006_encoder_mode_set(struct drm_encoder *encoder,
+                                    struct drm_display_mode *drm_mode,
+                                    struct drm_display_mode *adjusted_mode)
+{
+       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       struct ch7006_encoder_params *params = priv->params;
+       struct ch7006_state *state = &priv->state;
+       uint8_t *regs = state->regs;
+       struct ch7006_mode *mode = priv->mode;
+       struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm];
+       int start_active;
+
+       ch7006_dbg(client, "\n");
+
+       regs[CH7006_DISPMODE] = norm->dispmode | mode->dispmode;
+       regs[CH7006_BWIDTH] = 0;
+       regs[CH7006_INPUT_FORMAT] = bitf(CH7006_INPUT_FORMAT_FORMAT,
+                                        params->input_format);
+
+       regs[CH7006_CLKMODE] = CH7006_CLKMODE_SUBC_LOCK
+               | bitf(CH7006_CLKMODE_XCM, params->xcm)
+               | bitf(CH7006_CLKMODE_PCM, params->pcm);
+       if (params->clock_mode)
+               regs[CH7006_CLKMODE] |= CH7006_CLKMODE_MASTER;
+       if (params->clock_edge)
+               regs[CH7006_CLKMODE] |= CH7006_CLKMODE_POS_EDGE;
+
+       start_active = (drm_mode->htotal & ~0x7) - (drm_mode->hsync_start & ~0x7);
+       regs[CH7006_POV] = bitf(CH7006_POV_START_ACTIVE_8, start_active);
+       regs[CH7006_START_ACTIVE] = bitf(CH7006_START_ACTIVE_0, start_active);
+
+       regs[CH7006_INPUT_SYNC] = 0;
+       if (params->sync_direction)
+               regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_OUTPUT;
+       if (params->sync_encoding)
+               regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_EMBEDDED;
+       if (drm_mode->flags & DRM_MODE_FLAG_PVSYNC)
+               regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PVSYNC;
+       if (drm_mode->flags & DRM_MODE_FLAG_PHSYNC)
+               regs[CH7006_INPUT_SYNC] |= CH7006_INPUT_SYNC_PHSYNC;
+
+       regs[CH7006_DETECT] = 0;
+       regs[CH7006_BCLKOUT] = 0;
+
+       regs[CH7006_SUBC_INC3] = 0;
+       if (params->pout_level)
+               regs[CH7006_SUBC_INC3] |= CH7006_SUBC_INC3_POUT_3_3V;
+
+       regs[CH7006_SUBC_INC4] = 0;
+       if (params->active_detect)
+               regs[CH7006_SUBC_INC4] |= CH7006_SUBC_INC4_DS_INPUT;
+
+       regs[CH7006_PLL_CONTROL] = priv->saved_state.regs[CH7006_PLL_CONTROL];
+
+       ch7006_setup_levels(encoder);
+       ch7006_setup_subcarrier(encoder);
+       ch7006_setup_pll(encoder);
+       ch7006_setup_power_state(encoder);
+       ch7006_setup_properties(encoder);
+
+       ch7006_state_load(client, state);
+}
+
+static enum drm_connector_status ch7006_encoder_detect(struct drm_encoder *encoder,
+                                                      struct drm_connector *connector)
+{
+       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       struct ch7006_state *state = &priv->state;
+       int det;
+
+       ch7006_dbg(client, "\n");
+
+       ch7006_save_reg(client, state, CH7006_DETECT);
+       ch7006_save_reg(client, state, CH7006_POWER);
+       ch7006_save_reg(client, state, CH7006_CLKMODE);
+
+       ch7006_write(client, CH7006_POWER, CH7006_POWER_RESET |
+                                          bitfs(CH7006_POWER_LEVEL, NORMAL));
+       ch7006_write(client, CH7006_CLKMODE, CH7006_CLKMODE_MASTER);
+
+       ch7006_write(client, CH7006_DETECT, CH7006_DETECT_SENSE);
+
+       ch7006_write(client, CH7006_DETECT, 0);
+
+       det = ch7006_read(client, CH7006_DETECT);
+
+       ch7006_load_reg(client, state, CH7006_CLKMODE);
+       ch7006_load_reg(client, state, CH7006_POWER);
+       ch7006_load_reg(client, state, CH7006_DETECT);
+
+       if ((det & (CH7006_DETECT_SVIDEO_Y_TEST|
+                   CH7006_DETECT_SVIDEO_C_TEST|
+                   CH7006_DETECT_CVBS_TEST)) == 0)
+               priv->subconnector = DRM_MODE_SUBCONNECTOR_SCART;
+       else if ((det & (CH7006_DETECT_SVIDEO_Y_TEST|
+                        CH7006_DETECT_SVIDEO_C_TEST)) == 0)
+               priv->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO;
+       else if ((det & CH7006_DETECT_CVBS_TEST) == 0)
+               priv->subconnector = DRM_MODE_SUBCONNECTOR_Composite;
+       else
+               priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
+
+       drm_connector_property_set_value(connector,
+                       encoder->dev->mode_config.tv_subconnector_property,
+                                                       priv->subconnector);
+
+       return priv->subconnector ? connector_status_connected :
+                                       connector_status_disconnected;
+}
+
+static int ch7006_encoder_get_modes(struct drm_encoder *encoder,
+                                   struct drm_connector *connector)
+{
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       struct ch7006_mode *mode;
+       int n = 0;
+
+       for (mode = ch7006_modes; mode->mode.clock; mode++) {
+               if (~mode->valid_scales & 1<<priv->scale ||
+                   ~mode->valid_norms & 1<<priv->norm)
+                       continue;
+
+               drm_mode_probed_add(connector,
+                               drm_mode_duplicate(encoder->dev, &mode->mode));
+
+               n++;
+       }
+
+       return n;
+}
+
+static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
+                                          struct drm_connector *connector)
+{
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       struct drm_device *dev = encoder->dev;
+       struct drm_mode_config *conf = &dev->mode_config;
+
+       drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
+
+       priv->scale_property = drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                                  "scale", 2);
+       priv->scale_property->values[0] = 0;
+       priv->scale_property->values[1] = 2;
+
+       drm_connector_attach_property(connector, conf->tv_select_subconnector_property,
+                                     priv->select_subconnector);
+       drm_connector_attach_property(connector, conf->tv_subconnector_property,
+                                     priv->subconnector);
+       drm_connector_attach_property(connector, conf->tv_left_margin_property,
+                                     priv->hmargin);
+       drm_connector_attach_property(connector, conf->tv_bottom_margin_property,
+                                     priv->vmargin);
+       drm_connector_attach_property(connector, conf->tv_mode_property,
+                                     priv->norm);
+       drm_connector_attach_property(connector, conf->tv_brightness_property,
+                                     priv->brightness);
+       drm_connector_attach_property(connector, conf->tv_contrast_property,
+                                     priv->contrast);
+       drm_connector_attach_property(connector, conf->tv_flicker_reduction_property,
+                                     priv->flicker);
+       drm_connector_attach_property(connector, priv->scale_property,
+                                     priv->scale);
+
+       return 0;
+}
+
+static int ch7006_encoder_set_property(struct drm_encoder *encoder,
+                                      struct drm_connector *connector,
+                                      struct drm_property *property,
+                                      uint64_t val)
+{
+       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       struct ch7006_state *state = &priv->state;
+       struct drm_mode_config *conf = &encoder->dev->mode_config;
+       struct drm_crtc *crtc = encoder->crtc;
+       bool modes_changed = false;
+
+       ch7006_dbg(client, "\n");
+
+       if (property == conf->tv_select_subconnector_property) {
+               priv->select_subconnector = val;
+
+               ch7006_setup_power_state(encoder);
+
+               ch7006_load_reg(client, state, CH7006_POWER);
+
+       } else if (property == conf->tv_left_margin_property) {
+               priv->hmargin = val;
+
+               ch7006_setup_properties(encoder);
+
+               ch7006_load_reg(client, state, CH7006_POV);
+               ch7006_load_reg(client, state, CH7006_HPOS);
+
+       } else if (property == conf->tv_bottom_margin_property) {
+               priv->vmargin = val;
+
+               ch7006_setup_properties(encoder);
+
+               ch7006_load_reg(client, state, CH7006_POV);
+               ch7006_load_reg(client, state, CH7006_VPOS);
+
+       } else if (property == conf->tv_mode_property) {
+               if (connector->dpms != DRM_MODE_DPMS_OFF)
+                       return -EINVAL;
+
+               priv->norm = val;
+
+               modes_changed = true;
+
+       } else if (property == conf->tv_brightness_property) {
+               priv->brightness = val;
+
+               ch7006_setup_levels(encoder);
+
+               ch7006_load_reg(client, state, CH7006_BLACK_LEVEL);
+
+       } else if (property == conf->tv_contrast_property) {
+               priv->contrast = val;
+
+               ch7006_setup_properties(encoder);
+
+               ch7006_load_reg(client, state, CH7006_CONTRAST);
+
+       } else if (property == conf->tv_flicker_reduction_property) {
+               priv->flicker = val;
+
+               ch7006_setup_properties(encoder);
+
+               ch7006_load_reg(client, state, CH7006_FFILTER);
+
+       } else if (property == priv->scale_property) {
+               if (connector->dpms != DRM_MODE_DPMS_OFF)
+                       return -EINVAL;
+
+               priv->scale = val;
+
+               modes_changed = true;
+
+       } else {
+               return -EINVAL;
+       }
+
+       if (modes_changed) {
+               drm_helper_probe_single_connector_modes(connector, 0, 0);
+
+               /* Disable the crtc to ensure a full modeset is
+                * performed whenever it's turned on again. */
+               if (crtc) {
+                       struct drm_mode_set modeset = {
+                               .crtc = crtc,
+                       };
+
+                       crtc->funcs->set_config(&modeset);
+               }
+       }
+
+       return 0;
+}
+
+static struct drm_encoder_slave_funcs ch7006_encoder_funcs = {
+       .set_config = ch7006_encoder_set_config,
+       .destroy = ch7006_encoder_destroy,
+       .dpms = ch7006_encoder_dpms,
+       .save = ch7006_encoder_save,
+       .restore = ch7006_encoder_restore,
+       .mode_fixup = ch7006_encoder_mode_fixup,
+       .mode_valid = ch7006_encoder_mode_valid,
+       .mode_set = ch7006_encoder_mode_set,
+       .detect = ch7006_encoder_detect,
+       .get_modes = ch7006_encoder_get_modes,
+       .create_resources = ch7006_encoder_create_resources,
+       .set_property = ch7006_encoder_set_property,
+};
+
+
+/* I2C driver functions */
+
+static int ch7006_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       uint8_t addr = CH7006_VERSION_ID;
+       uint8_t val;
+       int ret;
+
+       ch7006_dbg(client, "\n");
+
+       ret = i2c_master_send(client, &addr, sizeof(addr));
+       if (ret < 0)
+               goto fail;
+
+       ret = i2c_master_recv(client, &val, sizeof(val));
+       if (ret < 0)
+               goto fail;
+
+       ch7006_info(client, "Detected version ID: %x\n", val);
+
+       return 0;
+
+fail:
+       ch7006_err(client, "Error %d reading version ID\n", ret);
+
+       return -ENODEV;
+}
+
+static int ch7006_remove(struct i2c_client *client)
+{
+       ch7006_dbg(client, "\n");
+
+       return 0;
+}
+
+static int ch7006_encoder_init(struct i2c_client *client,
+                              struct drm_device *dev,
+                              struct drm_encoder_slave *encoder)
+{
+       struct ch7006_priv *priv;
+       int i;
+
+       ch7006_dbg(client, "\n");
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       encoder->slave_priv = priv;
+       encoder->slave_funcs = &ch7006_encoder_funcs;
+
+       priv->norm = TV_NORM_PAL;
+       priv->select_subconnector = DRM_MODE_SUBCONNECTOR_Automatic;
+       priv->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
+       priv->scale = 1;
+       priv->contrast = 50;
+       priv->brightness = 50;
+       priv->flicker = 50;
+       priv->hmargin = 50;
+       priv->vmargin = 50;
+       priv->last_dpms = -1;
+
+       if (ch7006_tv_norm) {
+               for (i = 0; i < NUM_TV_NORMS; i++) {
+                       if (!strcmp(ch7006_tv_norm_names[i], ch7006_tv_norm)) {
+                               priv->norm = i;
+                               break;
+                       }
+               }
+
+               if (i == NUM_TV_NORMS)
+                       ch7006_err(client, "Invalid TV norm setting \"%s\".\n",
+                                  ch7006_tv_norm);
+       }
+
+       if (ch7006_scale >= 0 && ch7006_scale <= 2)
+               priv->scale = ch7006_scale;
+       else
+               ch7006_err(client, "Invalid scale setting \"%d\".\n",
+                          ch7006_scale);
+
+       return 0;
+}
+
+static struct i2c_device_id ch7006_ids[] = {
+       { "ch7006", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ch7006_ids);
+
+static struct drm_i2c_encoder_driver ch7006_driver = {
+       .i2c_driver = {
+               .probe = ch7006_probe,
+               .remove = ch7006_remove,
+
+               .driver = {
+                       .name = "ch7006",
+               },
+
+               .id_table = ch7006_ids,
+       },
+
+       .encoder_init = ch7006_encoder_init,
+};
+
+
+/* Module initialization */
+
+static int __init ch7006_init(void)
+{
+       return drm_i2c_encoder_register(THIS_MODULE, &ch7006_driver);
+}
+
+static void __exit ch7006_exit(void)
+{
+       drm_i2c_encoder_unregister(&ch7006_driver);
+}
+
+int ch7006_debug;
+module_param_named(debug, ch7006_debug, int, 0600);
+MODULE_PARM_DESC(debug, "Enable debug output.");
+
+char *ch7006_tv_norm;
+module_param_named(tv_norm, ch7006_tv_norm, charp, 0600);
+MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
+                "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, PAL-60, NTSC-M, NTSC-J.\n"
+                "\t\tDefault: PAL");
+
+int ch7006_scale = 1;
+module_param_named(scale, ch7006_scale, int, 0600);
+MODULE_PARM_DESC(scale, "Default scale.\n"
+                "\t\tSupported: 0 -> Select video modes with a higher blanking ratio.\n"
+                "\t\t\t1 -> Select default video modes.\n"
+                "\t\t\t2 -> Select video modes with a lower blanking ratio.");
+
+MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>");
+MODULE_DESCRIPTION("Chrontel ch7006 TV encoder driver");
+MODULE_LICENSE("GPL and additional rights");
+
+module_init(ch7006_init);
+module_exit(ch7006_exit);
diff --git a/drivers/gpu/drm/i2c/ch7006_mode.c b/drivers/gpu/drm/i2c/ch7006_mode.c
new file mode 100644 (file)
index 0000000..87f5445
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Copyright (C) 2009 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "ch7006_priv.h"
+
+char *ch7006_tv_norm_names[] = {
+       [TV_NORM_PAL] = "PAL",
+       [TV_NORM_PAL_M] = "PAL-M",
+       [TV_NORM_PAL_N] = "PAL-N",
+       [TV_NORM_PAL_NC] = "PAL-Nc",
+       [TV_NORM_PAL_60] = "PAL-60",
+       [TV_NORM_NTSC_M] = "NTSC-M",
+       [TV_NORM_NTSC_J] = "NTSC-J",
+};
+
+#define NTSC_LIKE_TIMINGS .vrefresh = 60 * fixed1/1.001,               \
+               .vdisplay = 480,                                        \
+               .vtotal = 525,                                          \
+               .hvirtual = 660
+
+#define PAL_LIKE_TIMINGS .vrefresh = 50 * fixed1,              \
+               .vdisplay = 576,                                \
+               .vtotal = 625,                                  \
+               .hvirtual = 810
+
+struct ch7006_tv_norm_info ch7006_tv_norms[] = {
+       [TV_NORM_NTSC_M] = {
+               NTSC_LIKE_TIMINGS,
+               .black_level = 0.339 * fixed1,
+               .subc_freq = 3579545 * fixed1,
+               .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC),
+               .voffset = 0,
+       },
+       [TV_NORM_NTSC_J] = {
+               NTSC_LIKE_TIMINGS,
+               .black_level = 0.286 * fixed1,
+               .subc_freq = 3579545 * fixed1,
+               .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, NTSC_J),
+               .voffset = 0,
+       },
+       [TV_NORM_PAL] = {
+               PAL_LIKE_TIMINGS,
+               .black_level = 0.3 * fixed1,
+               .subc_freq = 4433618.75 * fixed1,
+               .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL),
+               .voffset = 0,
+       },
+       [TV_NORM_PAL_M] = {
+               NTSC_LIKE_TIMINGS,
+               .black_level = 0.339 * fixed1,
+               .subc_freq = 3575611.433 * fixed1,
+               .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M),
+               .voffset = 16,
+       },
+
+       /* The following modes seem to work right but they're
+        * undocumented */
+
+       [TV_NORM_PAL_N] = {
+               PAL_LIKE_TIMINGS,
+               .black_level = 0.339 * fixed1,
+               .subc_freq = 4433618.75 * fixed1,
+               .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL),
+               .voffset = 0,
+       },
+       [TV_NORM_PAL_NC] = {
+               PAL_LIKE_TIMINGS,
+               .black_level = 0.3 * fixed1,
+               .subc_freq = 3582056.25 * fixed1,
+               .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL),
+               .voffset = 0,
+       },
+       [TV_NORM_PAL_60] = {
+               NTSC_LIKE_TIMINGS,
+               .black_level = 0.3 * fixed1,
+               .subc_freq = 4433618.75 * fixed1,
+               .dispmode = bitfs(CH7006_DISPMODE_OUTPUT_STD, PAL_M),
+               .voffset = 16,
+       },
+};
+
+#define __MODE(f, hd, vd, ht, vt, hsynp, vsynp,                                \
+              subc, scale, scale_mask, norm_mask, e_hd, e_vd) {        \
+               .mode = {                                               \
+                       .name = #hd "x" #vd,                            \
+                       .status = 0,                                    \
+                       .type = DRM_MODE_TYPE_DRIVER,                   \
+                       .clock = f,                                     \
+                       .hdisplay = hd,                                 \
+                       .hsync_start = e_hd + 16,                       \
+                       .hsync_end = e_hd + 80,                         \
+                       .htotal = ht,                                   \
+                       .hskew = 0,                                     \
+                       .vdisplay = vd,                                 \
+                       .vsync_start = vd + 10,                         \
+                       .vsync_end = vd + 26,                           \
+                       .vtotal = vt,                                   \
+                       .vscan = 0,                                     \
+                       .flags = DRM_MODE_FLAG_##hsynp##HSYNC |         \
+                               DRM_MODE_FLAG_##vsynp##VSYNC,           \
+                       .vrefresh = 0,                                  \
+               },                                                      \
+               .enc_hdisp = e_hd,                                      \
+               .enc_vdisp = e_vd,                                      \
+               .subc_coeff = subc * fixed1,                            \
+               .dispmode = bitfs(CH7006_DISPMODE_SCALING_RATIO, scale) | \
+                           bitfs(CH7006_DISPMODE_INPUT_RES, e_hd##x##e_vd), \
+               .valid_scales = scale_mask,                             \
+               .valid_norms = norm_mask                                \
+        }
+
+#define MODE(f, hd, vd, ht, vt, hsynp, vsynp,                          \
+            subc, scale, scale_mask, norm_mask)                        \
+       __MODE(f, hd, vd, ht, vt, hsynp, vsynp, subc, scale,            \
+              scale_mask, norm_mask, hd, vd)
+
+#define NTSC_LIKE (1 << TV_NORM_NTSC_M | 1 << TV_NORM_NTSC_J |         \
+                  1 << TV_NORM_PAL_M | 1 << TV_NORM_PAL_60)
+
+#define PAL_LIKE (1 << TV_NORM_PAL | 1 << TV_NORM_PAL_N | 1 << TV_NORM_PAL_NC)
+
+struct ch7006_mode ch7006_modes[] = {
+       MODE(21000, 512, 384, 840, 500, N, N, 181.797557582, 5_4, 0x6, PAL_LIKE),
+       MODE(26250, 512, 384, 840, 625, N, N, 145.438046066, 1_1, 0x1, PAL_LIKE),
+       MODE(20140, 512, 384, 800, 420, N, N, 213.257083791, 5_4, 0x4, NTSC_LIKE),
+       MODE(24671, 512, 384, 784, 525, N, N, 174.0874153, 1_1, 0x3, NTSC_LIKE),
+       MODE(28125, 720, 400, 1125, 500, N, N, 135.742176298, 5_4, 0x6, PAL_LIKE),
+       MODE(34875, 720, 400, 1116, 625, N, N, 109.469496898, 1_1, 0x1, PAL_LIKE),
+       MODE(23790, 720, 400, 945, 420, N, N, 160.475642016, 5_4, 0x4, NTSC_LIKE),
+       MODE(29455, 720, 400, 936, 525, N, N, 129.614941843, 1_1, 0x3, NTSC_LIKE),
+       MODE(25000, 640, 400, 1000, 500, N, N, 152.709948279, 5_4, 0x6, PAL_LIKE),
+       MODE(31500, 640, 400, 1008, 625, N, N, 121.198371646, 1_1, 0x1, PAL_LIKE),
+       MODE(21147, 640, 400, 840, 420, N, N, 180.535097338, 5_4, 0x4, NTSC_LIKE),
+       MODE(26434, 640, 400, 840, 525, N, N, 144.42807787, 1_1, 0x2, NTSC_LIKE),
+       MODE(30210, 640, 400, 840, 600, N, N, 126.374568276, 7_8, 0x1, NTSC_LIKE),
+       MODE(21000, 640, 480, 840, 500, N, N, 181.797557582, 5_4, 0x4, PAL_LIKE),
+       MODE(26250, 640, 480, 840, 625, N, N, 145.438046066, 1_1, 0x2, PAL_LIKE),
+       MODE(31500, 640, 480, 840, 750, N, N, 121.198371646, 5_6, 0x1, PAL_LIKE),
+       MODE(24671, 640, 480, 784, 525, N, N, 174.0874153, 1_1, 0x4, NTSC_LIKE),
+       MODE(28196, 640, 480, 784, 600, N, N, 152.326488422, 7_8, 0x2, NTSC_LIKE),
+       MODE(30210, 640, 480, 800, 630, N, N, 142.171389101, 5_6, 0x1, NTSC_LIKE),
+       __MODE(29500, 720, 576, 944, 625, P, P, 145.592111636, 1_1, 0x7, PAL_LIKE, 800, 600),
+       MODE(36000, 800, 600, 960, 750, P, P, 119.304647022, 5_6, 0x6, PAL_LIKE),
+       MODE(39000, 800, 600, 936, 836, P, P, 110.127366499, 3_4, 0x1, PAL_LIKE),
+       MODE(39273, 800, 600, 1040, 630, P, P, 145.816809399, 5_6, 0x4, NTSC_LIKE),
+       MODE(43636, 800, 600, 1040, 700, P, P, 131.235128487, 3_4, 0x2, NTSC_LIKE),
+       MODE(47832, 800, 600, 1064, 750, P, P, 119.723275165, 7_10, 0x1, NTSC_LIKE),
+       {}
+};
+
+struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder,
+                                      struct drm_display_mode *drm_mode)
+{
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       struct ch7006_mode *mode;
+
+       for (mode = ch7006_modes; mode->mode.clock; mode++) {
+
+               if (~mode->valid_norms & 1<<priv->norm)
+                       continue;
+
+               if (mode->mode.hdisplay != drm_mode->hdisplay ||
+                   mode->mode.vdisplay != drm_mode->vdisplay ||
+                   mode->mode.vtotal != drm_mode->vtotal ||
+                   mode->mode.htotal != drm_mode->htotal ||
+                   mode->mode.clock != drm_mode->clock)
+                       continue;
+
+               return mode;
+       }
+
+       return NULL;
+}
+
+/* Some common HW state calculation code */
+
+void ch7006_setup_levels(struct drm_encoder *encoder)
+{
+       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       uint8_t *regs = priv->state.regs;
+       struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm];
+       int gain;
+       int black_level;
+
+       /* Set DAC_GAIN if the voltage drop between white and black is
+        * high enough. */
+       if (norm->black_level < 339*fixed1/1000) {
+               gain = 76;
+
+               regs[CH7006_INPUT_FORMAT] |= CH7006_INPUT_FORMAT_DAC_GAIN;
+       } else {
+               gain = 71;
+
+               regs[CH7006_INPUT_FORMAT] &= ~CH7006_INPUT_FORMAT_DAC_GAIN;
+       }
+
+       black_level = round_fixed(norm->black_level*26625)/gain;
+
+       /* Correct it with the specified brightness. */
+       black_level = interpolate(90, black_level, 208, priv->brightness);
+
+       regs[CH7006_BLACK_LEVEL] = bitf(CH7006_BLACK_LEVEL_0, black_level);
+
+       ch7006_dbg(client, "black level: %d\n", black_level);
+}
+
+void ch7006_setup_subcarrier(struct drm_encoder *encoder)
+{
+       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       struct ch7006_state *state = &priv->state;
+       struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm];
+       struct ch7006_mode *mode = priv->mode;
+       uint32_t subc_inc;
+
+       subc_inc = round_fixed((mode->subc_coeff >> 8)
+                              * (norm->subc_freq >> 24));
+
+       setbitf(state, CH7006_SUBC_INC0, 28, subc_inc);
+       setbitf(state, CH7006_SUBC_INC1, 24, subc_inc);
+       setbitf(state, CH7006_SUBC_INC2, 20, subc_inc);
+       setbitf(state, CH7006_SUBC_INC3, 16, subc_inc);
+       setbitf(state, CH7006_SUBC_INC4, 12, subc_inc);
+       setbitf(state, CH7006_SUBC_INC5, 8, subc_inc);
+       setbitf(state, CH7006_SUBC_INC6, 4, subc_inc);
+       setbitf(state, CH7006_SUBC_INC7, 0, subc_inc);
+
+       ch7006_dbg(client, "subcarrier inc: %u\n", subc_inc);
+}
+
+void ch7006_setup_pll(struct drm_encoder *encoder)
+{
+       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       uint8_t *regs = priv->state.regs;
+       struct ch7006_mode *mode = priv->mode;
+       int n, best_n = 0;
+       int m, best_m = 0;
+       int freq, best_freq = 0;
+
+       for (n = 0; n < CH7006_MAXN; n++) {
+               for (m = 0; m < CH7006_MAXM; m++) {
+                       freq = CH7006_FREQ0*(n+2)/(m+2);
+
+                       if (abs(freq - mode->mode.clock) <
+                           abs(best_freq - mode->mode.clock)) {
+                               best_freq = freq;
+                               best_n = n;
+                               best_m = m;
+                       }
+               }
+       }
+
+       regs[CH7006_PLLOV] = bitf(CH7006_PLLOV_N_8, best_n) |
+               bitf(CH7006_PLLOV_M_8, best_m);
+
+       regs[CH7006_PLLM] = bitf(CH7006_PLLM_0, best_m);
+       regs[CH7006_PLLN] = bitf(CH7006_PLLN_0, best_n);
+
+       if (best_n < 108)
+               regs[CH7006_PLL_CONTROL] |= CH7006_PLL_CONTROL_CAPACITOR;
+       else
+               regs[CH7006_PLL_CONTROL] &= ~CH7006_PLL_CONTROL_CAPACITOR;
+
+       ch7006_dbg(client, "n=%d m=%d f=%d c=%d\n",
+                  best_n, best_m, best_freq, best_n < 108);
+}
+
+void ch7006_setup_power_state(struct drm_encoder *encoder)
+{
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       uint8_t *power = &priv->state.regs[CH7006_POWER];
+       int subconnector;
+
+       subconnector = priv->select_subconnector ? priv->select_subconnector :
+                                                       priv->subconnector;
+
+       *power = CH7006_POWER_RESET;
+
+       if (priv->last_dpms == DRM_MODE_DPMS_ON) {
+               switch (subconnector) {
+               case DRM_MODE_SUBCONNECTOR_SVIDEO:
+                       *power |= bitfs(CH7006_POWER_LEVEL, CVBS_OFF);
+                       break;
+               case DRM_MODE_SUBCONNECTOR_Composite:
+                       *power |= bitfs(CH7006_POWER_LEVEL, SVIDEO_OFF);
+                       break;
+               case DRM_MODE_SUBCONNECTOR_SCART:
+                       *power |= bitfs(CH7006_POWER_LEVEL, NORMAL) |
+                               CH7006_POWER_SCART;
+                       break;
+               }
+
+       } else {
+               *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF);
+       }
+}
+
+void ch7006_setup_properties(struct drm_encoder *encoder)
+{
+       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct ch7006_priv *priv = to_ch7006_priv(encoder);
+       struct ch7006_state *state = &priv->state;
+       struct ch7006_tv_norm_info *norm = &ch7006_tv_norms[priv->norm];
+       struct ch7006_mode *ch_mode = priv->mode;
+       struct drm_display_mode *mode = &ch_mode->mode;
+       uint8_t *regs = state->regs;
+       int flicker, contrast, hpos, vpos;
+       uint64_t scale, aspect;
+
+       flicker = interpolate(0, 2, 3, priv->flicker);
+       regs[CH7006_FFILTER] = bitf(CH7006_FFILTER_TEXT, flicker) |
+               bitf(CH7006_FFILTER_LUMA, flicker) |
+               bitf(CH7006_FFILTER_CHROMA, 1);
+
+       contrast = interpolate(0, 5, 7, priv->contrast);
+       regs[CH7006_CONTRAST] = bitf(CH7006_CONTRAST_0, contrast);
+
+       scale = norm->vtotal*fixed1;
+       do_div(scale, mode->vtotal);
+
+       aspect = ch_mode->enc_hdisp*fixed1;
+       do_div(aspect, ch_mode->enc_vdisp);
+
+       hpos = round_fixed((norm->hvirtual * aspect - mode->hdisplay * scale)
+                          * priv->hmargin * mode->vtotal) / norm->vtotal / 100 / 4;
+
+       setbitf(state, CH7006_POV, HPOS_8, hpos);
+       setbitf(state, CH7006_HPOS, 0, hpos);
+
+       vpos = max(0, norm->vdisplay - round_fixed(mode->vdisplay*scale)
+                  + norm->voffset) * priv->vmargin / 100 / 2;
+
+       setbitf(state, CH7006_POV, VPOS_8, vpos);
+       setbitf(state, CH7006_VPOS, 0, vpos);
+
+       ch7006_dbg(client, "hpos: %d, vpos: %d\n", hpos, vpos);
+}
+
+/* HW access functions */
+
+void ch7006_write(struct i2c_client *client, uint8_t addr, uint8_t val)
+{
+       uint8_t buf[] = {addr, val};
+       int ret;
+
+       ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
+       if (ret < 0)
+               ch7006_err(client, "Error %d writing to subaddress 0x%x\n",
+                          ret, addr);
+}
+
+uint8_t ch7006_read(struct i2c_client *client, uint8_t addr)
+{
+       uint8_t val;
+       int ret;
+
+       ret = i2c_master_send(client, &addr, sizeof(addr));
+       if (ret < 0)
+               goto fail;
+
+       ret = i2c_master_recv(client, &val, sizeof(val));
+       if (ret < 0)
+               goto fail;
+
+       return val;
+
+fail:
+       ch7006_err(client, "Error %d reading from subaddress 0x%x\n",
+                  ret, addr);
+       return 0;
+}
+
+void ch7006_state_load(struct i2c_client *client,
+                      struct ch7006_state *state)
+{
+       ch7006_load_reg(client, state, CH7006_POWER);
+
+       ch7006_load_reg(client, state, CH7006_DISPMODE);
+       ch7006_load_reg(client, state, CH7006_FFILTER);
+       ch7006_load_reg(client, state, CH7006_BWIDTH);
+       ch7006_load_reg(client, state, CH7006_INPUT_FORMAT);
+       ch7006_load_reg(client, state, CH7006_CLKMODE);
+       ch7006_load_reg(client, state, CH7006_START_ACTIVE);
+       ch7006_load_reg(client, state, CH7006_POV);
+       ch7006_load_reg(client, state, CH7006_BLACK_LEVEL);
+       ch7006_load_reg(client, state, CH7006_HPOS);
+       ch7006_load_reg(client, state, CH7006_VPOS);
+       ch7006_load_reg(client, state, CH7006_INPUT_SYNC);
+       ch7006_load_reg(client, state, CH7006_DETECT);
+       ch7006_load_reg(client, state, CH7006_CONTRAST);
+       ch7006_load_reg(client, state, CH7006_PLLOV);
+       ch7006_load_reg(client, state, CH7006_PLLM);
+       ch7006_load_reg(client, state, CH7006_PLLN);
+       ch7006_load_reg(client, state, CH7006_BCLKOUT);
+       ch7006_load_reg(client, state, CH7006_SUBC_INC0);
+       ch7006_load_reg(client, state, CH7006_SUBC_INC1);
+       ch7006_load_reg(client, state, CH7006_SUBC_INC2);
+       ch7006_load_reg(client, state, CH7006_SUBC_INC3);
+       ch7006_load_reg(client, state, CH7006_SUBC_INC4);
+       ch7006_load_reg(client, state, CH7006_SUBC_INC5);
+       ch7006_load_reg(client, state, CH7006_SUBC_INC6);
+       ch7006_load_reg(client, state, CH7006_SUBC_INC7);
+       ch7006_load_reg(client, state, CH7006_PLL_CONTROL);
+       ch7006_load_reg(client, state, CH7006_CALC_SUBC_INC0);
+
+       /* I don't know what this is for, but otherwise I get no
+        * signal.
+        */
+       ch7006_write(client, 0x3d, 0x0);
+}
+
+void ch7006_state_save(struct i2c_client *client,
+                      struct ch7006_state *state)
+{
+       ch7006_save_reg(client, state, CH7006_POWER);
+
+       ch7006_save_reg(client, state, CH7006_DISPMODE);
+       ch7006_save_reg(client, state, CH7006_FFILTER);
+       ch7006_save_reg(client, state, CH7006_BWIDTH);
+       ch7006_save_reg(client, state, CH7006_INPUT_FORMAT);
+       ch7006_save_reg(client, state, CH7006_CLKMODE);
+       ch7006_save_reg(client, state, CH7006_START_ACTIVE);
+       ch7006_save_reg(client, state, CH7006_POV);
+       ch7006_save_reg(client, state, CH7006_BLACK_LEVEL);
+       ch7006_save_reg(client, state, CH7006_HPOS);
+       ch7006_save_reg(client, state, CH7006_VPOS);
+       ch7006_save_reg(client, state, CH7006_INPUT_SYNC);
+       ch7006_save_reg(client, state, CH7006_DETECT);
+       ch7006_save_reg(client, state, CH7006_CONTRAST);
+       ch7006_save_reg(client, state, CH7006_PLLOV);
+       ch7006_save_reg(client, state, CH7006_PLLM);
+       ch7006_save_reg(client, state, CH7006_PLLN);
+       ch7006_save_reg(client, state, CH7006_BCLKOUT);
+       ch7006_save_reg(client, state, CH7006_SUBC_INC0);
+       ch7006_save_reg(client, state, CH7006_SUBC_INC1);
+       ch7006_save_reg(client, state, CH7006_SUBC_INC2);
+       ch7006_save_reg(client, state, CH7006_SUBC_INC3);
+       ch7006_save_reg(client, state, CH7006_SUBC_INC4);
+       ch7006_save_reg(client, state, CH7006_SUBC_INC5);
+       ch7006_save_reg(client, state, CH7006_SUBC_INC6);
+       ch7006_save_reg(client, state, CH7006_SUBC_INC7);
+       ch7006_save_reg(client, state, CH7006_PLL_CONTROL);
+       ch7006_save_reg(client, state, CH7006_CALC_SUBC_INC0);
+
+       state->regs[CH7006_FFILTER] = (state->regs[CH7006_FFILTER] & 0xf0) |
+               (state->regs[CH7006_FFILTER] & 0x0c) >> 2 |
+               (state->regs[CH7006_FFILTER] & 0x03) << 2;
+}
diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h
new file mode 100644 (file)
index 0000000..b06d3d9
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2009 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __DRM_I2C_CH7006_PRIV_H__
+#define __DRM_I2C_CH7006_PRIV_H__
+
+#include "drmP.h"
+#include "drm_crtc_helper.h"
+#include "drm_encoder_slave.h"
+#include "i2c/ch7006.h"
+
+typedef int64_t fixed;
+#define fixed1 (1LL << 32)
+
+enum ch7006_tv_norm {
+       TV_NORM_PAL,
+       TV_NORM_PAL_M,
+       TV_NORM_PAL_N,
+       TV_NORM_PAL_NC,
+       TV_NORM_PAL_60,
+       TV_NORM_NTSC_M,
+       TV_NORM_NTSC_J,
+       NUM_TV_NORMS
+};
+
+struct ch7006_tv_norm_info {
+       fixed vrefresh;
+       int vdisplay;
+       int vtotal;
+       int hvirtual;
+
+       fixed subc_freq;
+       fixed black_level;
+
+       uint32_t dispmode;
+       int voffset;
+};
+
+struct ch7006_mode {
+       struct drm_display_mode mode;
+
+       int enc_hdisp;
+       int enc_vdisp;
+
+       fixed subc_coeff;
+       uint32_t dispmode;
+
+       uint32_t valid_scales;
+       uint32_t valid_norms;
+};
+
+struct ch7006_state {
+       uint8_t regs[0x26];
+};
+
+struct ch7006_priv {
+       struct ch7006_encoder_params *params;
+       struct ch7006_mode *mode;
+
+       struct ch7006_state state;
+       struct ch7006_state saved_state;
+
+       struct drm_property *scale_property;
+
+       int select_subconnector;
+       int subconnector;
+       int hmargin;
+       int vmargin;
+       enum ch7006_tv_norm norm;
+       int brightness;
+       int contrast;
+       int flicker;
+       int scale;
+
+       int last_dpms;
+};
+
+#define to_ch7006_priv(x) \
+       ((struct ch7006_priv *)to_encoder_slave(x)->slave_priv)
+
+extern int ch7006_debug;
+extern char *ch7006_tv_norm;
+extern int ch7006_scale;
+
+extern char *ch7006_tv_norm_names[];
+extern struct ch7006_tv_norm_info ch7006_tv_norms[];
+extern struct ch7006_mode ch7006_modes[];
+
+struct ch7006_mode *ch7006_lookup_mode(struct drm_encoder *encoder,
+                                      struct drm_display_mode *drm_mode);
+
+void ch7006_setup_levels(struct drm_encoder *encoder);
+void ch7006_setup_subcarrier(struct drm_encoder *encoder);
+void ch7006_setup_pll(struct drm_encoder *encoder);
+void ch7006_setup_power_state(struct drm_encoder *encoder);
+void ch7006_setup_properties(struct drm_encoder *encoder);
+
+void ch7006_write(struct i2c_client *client, uint8_t addr, uint8_t val);
+uint8_t ch7006_read(struct i2c_client *client, uint8_t addr);
+
+void ch7006_state_load(struct i2c_client *client,
+                      struct ch7006_state *state);
+void ch7006_state_save(struct i2c_client *client,
+                      struct ch7006_state *state);
+
+/* Some helper macros */
+
+#define ch7006_dbg(client, format, ...) do {                           \
+               if (ch7006_debug)                                       \
+                       dev_printk(KERN_DEBUG, &client->dev,            \
+                                  "%s: " format, __func__, ## __VA_ARGS__); \
+       } while (0)
+#define ch7006_info(client, format, ...) \
+                               dev_info(&client->dev, format, __VA_ARGS__)
+#define ch7006_err(client, format, ...) \
+                               dev_err(&client->dev, format, __VA_ARGS__)
+
+#define __mask(src, bitfield) \
+               (((2 << (1 ? bitfield)) - 1) & ~((1 << (0 ? bitfield)) - 1))
+#define mask(bitfield) __mask(bitfield)
+
+#define __bitf(src, bitfield, x) \
+               (((x) >> (src) << (0 ? bitfield)) &  __mask(src, bitfield))
+#define bitf(bitfield, x) __bitf(bitfield, x)
+#define bitfs(bitfield, s) __bitf(bitfield, bitfield##_##s)
+#define setbitf(state, reg, bitfield, x)                               \
+       state->regs[reg] = (state->regs[reg] & ~mask(reg##_##bitfield)) \
+               | bitf(reg##_##bitfield, x)
+
+#define __unbitf(src, bitfield, x) \
+               ((x & __mask(src, bitfield)) >> (0 ? bitfield) << (src))
+#define unbitf(bitfield, x) __unbitf(bitfield, x)
+
+static inline int interpolate(int y0, int y1, int y2, int x)
+{
+       return y1 + (x < 50 ? y1 - y0 : y2 - y1) * (x - 50) / 50;
+}
+
+static inline int32_t round_fixed(fixed x)
+{
+       return (x + fixed1/2) >> 32;
+}
+
+#define ch7006_load_reg(client, state, reg) ch7006_write(client, reg, state->regs[reg])
+#define ch7006_save_reg(client, state, reg) state->regs[reg] = ch7006_read(client, reg)
+
+/* Fixed hardware specs */
+
+#define CH7006_FREQ0                           14318
+#define CH7006_MAXN                            650
+#define CH7006_MAXM                            315
+
+/* Register definitions */
+
+#define CH7006_DISPMODE                                0x00
+#define CH7006_DISPMODE_INPUT_RES              0, 7:5
+#define CH7006_DISPMODE_INPUT_RES_512x384      0x0
+#define CH7006_DISPMODE_INPUT_RES_720x400      0x1
+#define CH7006_DISPMODE_INPUT_RES_640x400      0x2
+#define CH7006_DISPMODE_INPUT_RES_640x480      0x3
+#define CH7006_DISPMODE_INPUT_RES_800x600      0x4
+#define CH7006_DISPMODE_INPUT_RES_NATIVE       0x5
+#define CH7006_DISPMODE_OUTPUT_STD             0, 4:3
+#define CH7006_DISPMODE_OUTPUT_STD_PAL         0x0
+#define CH7006_DISPMODE_OUTPUT_STD_NTSC                0x1
+#define CH7006_DISPMODE_OUTPUT_STD_PAL_M       0x2
+#define CH7006_DISPMODE_OUTPUT_STD_NTSC_J      0x3
+#define CH7006_DISPMODE_SCALING_RATIO          0, 2:0
+#define CH7006_DISPMODE_SCALING_RATIO_5_4      0x0
+#define CH7006_DISPMODE_SCALING_RATIO_1_1      0x1
+#define CH7006_DISPMODE_SCALING_RATIO_7_8      0x2
+#define CH7006_DISPMODE_SCALING_RATIO_5_6      0x3
+#define CH7006_DISPMODE_SCALING_RATIO_3_4      0x4
+#define CH7006_DISPMODE_SCALING_RATIO_7_10     0x5
+
+#define CH7006_FFILTER                         0x01
+#define CH7006_FFILTER_TEXT                    0, 5:4
+#define CH7006_FFILTER_LUMA                    0, 3:2
+#define CH7006_FFILTER_CHROMA                  0, 1:0
+#define CH7006_FFILTER_CHROMA_NO_DCRAWL                0x3
+
+#define CH7006_BWIDTH                          0x03
+#define CH7006_BWIDTH_5L_FFILER                        (1 << 7)
+#define CH7006_BWIDTH_CVBS_NO_CHROMA           (1 << 6)
+#define CH7006_BWIDTH_CHROMA                   0, 5:4
+#define CH7006_BWIDTH_SVIDEO_YPEAK             (1 << 3)
+#define CH7006_BWIDTH_SVIDEO_LUMA              0, 2:1
+#define CH7006_BWIDTH_CVBS_LUMA                        0, 0:0
+
+#define CH7006_INPUT_FORMAT                    0x04
+#define CH7006_INPUT_FORMAT_DAC_GAIN           (1 << 6)
+#define CH7006_INPUT_FORMAT_RGB_PASS_THROUGH   (1 << 5)
+#define CH7006_INPUT_FORMAT_FORMAT             0, 3:0
+#define CH7006_INPUT_FORMAT_FORMAT_RGB16       0x0
+#define CH7006_INPUT_FORMAT_FORMAT_YCrCb24m16  0x1
+#define CH7006_INPUT_FORMAT_FORMAT_RGB24m16    0x2
+#define CH7006_INPUT_FORMAT_FORMAT_RGB15       0x3
+#define CH7006_INPUT_FORMAT_FORMAT_RGB24m12C   0x4
+#define CH7006_INPUT_FORMAT_FORMAT_RGB24m12I   0x5
+#define CH7006_INPUT_FORMAT_FORMAT_RGB24m8     0x6
+#define CH7006_INPUT_FORMAT_FORMAT_RGB16m8     0x7
+#define CH7006_INPUT_FORMAT_FORMAT_RGB15m8     0x8
+#define CH7006_INPUT_FORMAT_FORMAT_YCrCb24m8   0x9
+
+#define CH7006_CLKMODE                         0x06
+#define CH7006_CLKMODE_SUBC_LOCK               (1 << 7)
+#define CH7006_CLKMODE_MASTER                  (1 << 6)
+#define CH7006_CLKMODE_POS_EDGE                        (1 << 4)
+#define CH7006_CLKMODE_XCM                     0, 3:2
+#define CH7006_CLKMODE_PCM                     0, 1:0
+
+#define CH7006_START_ACTIVE                    0x07
+#define CH7006_START_ACTIVE_0                  0, 7:0
+
+#define CH7006_POV                             0x08
+#define CH7006_POV_START_ACTIVE_8              8, 2:2
+#define CH7006_POV_HPOS_8                      8, 1:1
+#define CH7006_POV_VPOS_8                      8, 0:0
+
+#define CH7006_BLACK_LEVEL                     0x09
+#define CH7006_BLACK_LEVEL_0                   0, 7:0
+
+#define CH7006_HPOS                            0x0a
+#define CH7006_HPOS_0                          0, 7:0
+
+#define CH7006_VPOS                            0x0b
+#define CH7006_VPOS_0                          0, 7:0
+
+#define CH7006_INPUT_SYNC                      0x0d
+#define CH7006_INPUT_SYNC_EMBEDDED             (1 << 3)
+#define CH7006_INPUT_SYNC_OUTPUT               (1 << 2)
+#define CH7006_INPUT_SYNC_PVSYNC               (1 << 1)
+#define CH7006_INPUT_SYNC_PHSYNC               (1 << 0)
+
+#define CH7006_POWER                           0x0e
+#define CH7006_POWER_SCART                     (1 << 4)
+#define CH7006_POWER_RESET                     (1 << 3)
+#define CH7006_POWER_LEVEL                     0, 2:0
+#define CH7006_POWER_LEVEL_CVBS_OFF            0x0
+#define CH7006_POWER_LEVEL_POWER_OFF           0x1
+#define CH7006_POWER_LEVEL_SVIDEO_OFF          0x2
+#define CH7006_POWER_LEVEL_NORMAL              0x3
+#define CH7006_POWER_LEVEL_FULL_POWER_OFF      0x4
+
+#define CH7006_DETECT                          0x10
+#define CH7006_DETECT_SVIDEO_Y_TEST            (1 << 3)
+#define CH7006_DETECT_SVIDEO_C_TEST            (1 << 2)
+#define CH7006_DETECT_CVBS_TEST                        (1 << 1)
+#define CH7006_DETECT_SENSE                    (1 << 0)
+
+#define CH7006_CONTRAST                                0x11
+#define CH7006_CONTRAST_0                      0, 2:0
+
+#define CH7006_PLLOV                           0x13
+#define CH7006_PLLOV_N_8                       8, 2:1
+#define CH7006_PLLOV_M_8                       8, 0:0
+
+#define CH7006_PLLM                            0x14
+#define CH7006_PLLM_0                          0, 7:0
+
+#define CH7006_PLLN                            0x15
+#define CH7006_PLLN_0                          0, 7:0
+
+#define CH7006_BCLKOUT                         0x17
+
+#define CH7006_SUBC_INC0                       0x18
+#define CH7006_SUBC_INC0_28                    28, 3:0
+
+#define CH7006_SUBC_INC1                       0x19
+#define CH7006_SUBC_INC1_24                    24, 3:0
+
+#define CH7006_SUBC_INC2                       0x1a
+#define CH7006_SUBC_INC2_20                    20, 3:0
+
+#define CH7006_SUBC_INC3                       0x1b
+#define CH7006_SUBC_INC3_GPIO1_VAL             (1 << 7)
+#define CH7006_SUBC_INC3_GPIO0_VAL             (1 << 6)
+#define CH7006_SUBC_INC3_POUT_3_3V             (1 << 5)
+#define CH7006_SUBC_INC3_POUT_INV              (1 << 4)
+#define CH7006_SUBC_INC3_16                    16, 3:0
+
+#define CH7006_SUBC_INC4                       0x1c
+#define CH7006_SUBC_INC4_GPIO1_IN              (1 << 7)
+#define CH7006_SUBC_INC4_GPIO0_IN              (1 << 6)
+#define CH7006_SUBC_INC4_DS_INPUT              (1 << 4)
+#define CH7006_SUBC_INC4_12                    12, 3:0
+
+#define CH7006_SUBC_INC5                       0x1d
+#define CH7006_SUBC_INC5_8                     8, 3:0
+
+#define CH7006_SUBC_INC6                       0x1e
+#define CH7006_SUBC_INC6_4                     4, 3:0
+
+#define CH7006_SUBC_INC7                       0x1f
+#define CH7006_SUBC_INC7_0                     0, 3:0
+
+#define CH7006_PLL_CONTROL                     0x20
+#define CH7006_PLL_CONTROL_CPI                 (1 << 5)
+#define CH7006_PLL_CONTROL_CAPACITOR           (1 << 4)
+#define CH7006_PLL_CONTROL_7STAGES             (1 << 3)
+#define CH7006_PLL_CONTROL_DIGITAL_5V          (1 << 2)
+#define CH7006_PLL_CONTROL_ANALOG_5V           (1 << 1)
+#define CH7006_PLL_CONTROL_MEMORY_5V           (1 << 0)
+
+#define CH7006_CALC_SUBC_INC0                  0x21
+#define CH7006_CALC_SUBC_INC0_24               24, 4:3
+#define CH7006_CALC_SUBC_INC0_HYST             0, 2:1
+#define CH7006_CALC_SUBC_INC0_AUTO             (1 << 0)
+
+#define CH7006_CALC_SUBC_INC1                  0x22
+#define CH7006_CALC_SUBC_INC1_16               16, 7:0
+
+#define CH7006_CALC_SUBC_INC2                  0x23
+#define CH7006_CALC_SUBC_INC2_8                        8, 7:0
+
+#define CH7006_CALC_SUBC_INC3                  0x24
+#define CH7006_CALC_SUBC_INC3_0                        0, 7:0
+
+#define CH7006_VERSION_ID                      0x25
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
new file mode 100644 (file)
index 0000000..d823e63
--- /dev/null
@@ -0,0 +1,44 @@
+config DRM_NOUVEAU
+       tristate "Nouveau (nVidia) cards"
+       depends on DRM
+        select FW_LOADER
+       select DRM_KMS_HELPER
+       select DRM_TTM
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       select FB
+       select FRAMEBUFFER_CONSOLE if !EMBEDDED
+       select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
+       help
+         Choose this option for open-source nVidia support.
+
+config DRM_NOUVEAU_BACKLIGHT
+       bool "Support for backlight control"
+       depends on DRM_NOUVEAU
+       default y
+       help
+         Say Y here if you want to control the backlight of your display
+         (e.g. a laptop panel).
+
+config DRM_NOUVEAU_DEBUG
+       bool "Build in Nouveau's debugfs support"
+       depends on DRM_NOUVEAU && DEBUG_FS
+       default y
+       help
+         Say Y here if you want Nouveau to output debugging information
+         via debugfs.
+
+menu "I2C encoder or helper chips"
+     depends on DRM
+
+config DRM_I2C_CH7006
+       tristate "Chrontel ch7006 TV encoder"
+       default m if DRM_NOUVEAU
+       help
+         Support for Chrontel ch7006 and similar TV encoders, found
+         on some nVidia video cards.
+
+         This driver is currently only useful if you're also using
+         the nouveau driver.
+endmenu
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
new file mode 100644 (file)
index 0000000..1d90d4d
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
+             nouveau_object.o nouveau_irq.o nouveau_notifier.o \
+             nouveau_sgdma.o nouveau_dma.o \
+             nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
+             nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
+            nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
+            nouveau_dp.o \
+             nv04_timer.o \
+             nv04_mc.o nv40_mc.o nv50_mc.o \
+             nv04_fb.o nv10_fb.o nv40_fb.o \
+             nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
+             nv04_graph.o nv10_graph.o nv20_graph.o \
+             nv40_graph.o nv50_graph.o \
+             nv04_instmem.o nv50_instmem.o \
+             nv50_crtc.o nv50_dac.o nv50_sor.o \
+             nv50_cursor.o nv50_display.o nv50_fbcon.o \
+             nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
+             nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
+             nv17_gpio.o
+
+nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
+nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
+nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
+nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
+
+obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
new file mode 100644 (file)
index 0000000..1cf4882
--- /dev/null
@@ -0,0 +1,125 @@
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_sarea.h"
+#include "drm_crtc_helper.h"
+#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+#include "nv50_display.h"
+
+#define NOUVEAU_DSM_SUPPORTED 0x00
+#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00
+
+#define NOUVEAU_DSM_ACTIVE 0x01
+#define NOUVEAU_DSM_ACTIVE_QUERY 0x00
+
+#define NOUVEAU_DSM_LED 0x02
+#define NOUVEAU_DSM_LED_STATE 0x00
+#define NOUVEAU_DSM_LED_OFF 0x10
+#define NOUVEAU_DSM_LED_STAMINA 0x11
+#define NOUVEAU_DSM_LED_SPEED 0x12
+
+#define NOUVEAU_DSM_POWER 0x03
+#define NOUVEAU_DSM_POWER_STATE 0x00
+#define NOUVEAU_DSM_POWER_SPEED 0x01
+#define NOUVEAU_DSM_POWER_STAMINA 0x02
+
+static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
+{
+       static char muid[] = {
+               0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
+               0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
+       };
+
+       struct pci_dev *pdev = dev->pdev;
+       struct acpi_handle *handle;
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_object_list input;
+       union acpi_object params[4];
+       union acpi_object *obj;
+       int err;
+
+       handle = DEVICE_ACPI_HANDLE(&pdev->dev);
+
+       if (!handle)
+               return -ENODEV;
+
+       input.count = 4;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_BUFFER;
+       params[0].buffer.length = sizeof(muid);
+       params[0].buffer.pointer = (char *)muid;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = 0x00000102;
+       params[2].type = ACPI_TYPE_INTEGER;
+       params[2].integer.value = func;
+       params[3].type = ACPI_TYPE_INTEGER;
+       params[3].integer.value = arg;
+
+       err = acpi_evaluate_object(handle, "_DSM", &input, &output);
+       if (err) {
+               NV_INFO(dev, "failed to evaluate _DSM: %d\n", err);
+               return err;
+       }
+
+       obj = (union acpi_object *)output.pointer;
+
+       if (obj->type == ACPI_TYPE_INTEGER)
+               if (obj->integer.value == 0x80000002)
+                       return -ENODEV;
+
+       if (obj->type == ACPI_TYPE_BUFFER) {
+               if (obj->buffer.length == 4 && result) {
+                       *result = 0;
+                       *result |= obj->buffer.pointer[0];
+                       *result |= (obj->buffer.pointer[1] << 8);
+                       *result |= (obj->buffer.pointer[2] << 16);
+                       *result |= (obj->buffer.pointer[3] << 24);
+               }
+       }
+
+       kfree(output.pointer);
+       return 0;
+}
+
+int nouveau_hybrid_setup(struct drm_device *dev)
+{
+       int result;
+
+       if (nouveau_dsm(dev, NOUVEAU_DSM_ACTIVE, NOUVEAU_DSM_ACTIVE_QUERY,
+                                                               &result))
+               return -ENODEV;
+
+       NV_INFO(dev, "_DSM hardware status gave 0x%x\n", result);
+
+       if (result & 0x1) {     /* Stamina mode - disable the external GPU */
+               nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_STAMINA,
+                                                                       NULL);
+               nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STAMINA,
+                                                                       NULL);
+       } else {                /* Ensure that the external GPU is enabled */
+               nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL);
+               nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED,
+                                                                       NULL);
+       }
+
+       return 0;
+}
+
+bool nouveau_dsm_probe(struct drm_device *dev)
+{
+       int support = 0;
+
+       if (nouveau_dsm(dev, NOUVEAU_DSM_SUPPORTED,
+                               NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &support))
+               return false;
+
+       if (!support)
+               return false;
+
+       return true;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
new file mode 100644 (file)
index 0000000..20564f8
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2009 Red Hat <mjg@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Authors:
+ *  Matthew Garrett <mjg@redhat.com>
+ *
+ * Register locations derived from NVClock by Roderick Colenbrander
+ */
+
+#include <linux/backlight.h>
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+#include "nouveau_reg.h"
+
+static int nv40_get_intensity(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+       int val = (nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)
+                                                                       >> 16;
+
+       return val;
+}
+
+static int nv40_set_intensity(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+       int val = bd->props.brightness;
+       int reg = nv_rd32(dev, NV40_PMC_BACKLIGHT);
+
+       nv_wr32(dev, NV40_PMC_BACKLIGHT,
+                (val << 16) | (reg & ~NV40_PMC_BACKLIGHT_MASK));
+
+       return 0;
+}
+
+static struct backlight_ops nv40_bl_ops = {
+       .options = BL_CORE_SUSPENDRESUME,
+       .get_brightness = nv40_get_intensity,
+       .update_status = nv40_set_intensity,
+};
+
+static int nv50_get_intensity(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+
+       return nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT);
+}
+
+static int nv50_set_intensity(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+       int val = bd->props.brightness;
+
+       nv_wr32(dev, NV50_PDISPLAY_SOR_BACKLIGHT,
+               val | NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE);
+       return 0;
+}
+
+static struct backlight_ops nv50_bl_ops = {
+       .options = BL_CORE_SUSPENDRESUME,
+       .get_brightness = nv50_get_intensity,
+       .update_status = nv50_set_intensity,
+};
+
+static int nouveau_nv40_backlight_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct backlight_device *bd;
+
+       if (!(nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK))
+               return 0;
+
+       bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
+                                      &nv40_bl_ops);
+       if (IS_ERR(bd))
+               return PTR_ERR(bd);
+
+       dev_priv->backlight = bd;
+       bd->props.max_brightness = 31;
+       bd->props.brightness = nv40_get_intensity(bd);
+       backlight_update_status(bd);
+
+       return 0;
+}
+
+static int nouveau_nv50_backlight_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct backlight_device *bd;
+
+       if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT))
+               return 0;
+
+       bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
+                                      &nv50_bl_ops);
+       if (IS_ERR(bd))
+               return PTR_ERR(bd);
+
+       dev_priv->backlight = bd;
+       bd->props.max_brightness = 1025;
+       bd->props.brightness = nv50_get_intensity(bd);
+       backlight_update_status(bd);
+       return 0;
+}
+
+int nouveau_backlight_init(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       switch (dev_priv->card_type) {
+       case NV_40:
+               return nouveau_nv40_backlight_init(dev);
+       case NV_50:
+               return nouveau_nv50_backlight_init(dev);
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+void nouveau_backlight_exit(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->backlight) {
+               backlight_device_unregister(dev_priv->backlight);
+               dev_priv->backlight = NULL;
+       }
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
new file mode 100644 (file)
index 0000000..5eec5ed
--- /dev/null
@@ -0,0 +1,6095 @@
+/*
+ * Copyright 2005-2006 Erik Waling
+ * Copyright 2006 Stephane Marchesin
+ * Copyright 2007-2009 Stuart Bennett
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "drmP.h"
+#define NV_DEBUG_NOTRACE
+#include "nouveau_drv.h"
+#include "nouveau_hw.h"
+
+/* these defines are made up */
+#define NV_CIO_CRE_44_HEADA 0x0
+#define NV_CIO_CRE_44_HEADB 0x3
+#define FEATURE_MOBILE 0x10    /* also FEATURE_QUADRO for BMP */
+#define LEGACY_I2C_CRT 0x80
+#define LEGACY_I2C_PANEL 0x81
+#define LEGACY_I2C_TV 0x82
+
+#define EDID1_LEN 128
+
+#define BIOSLOG(sip, fmt, arg...) NV_DEBUG(sip->dev, fmt, ##arg)
+#define LOG_OLD_VALUE(x)
+
+#define ROM16(x) le16_to_cpu(*(uint16_t *)&(x))
+#define ROM32(x) le32_to_cpu(*(uint32_t *)&(x))
+
+struct init_exec {
+       bool execute;
+       bool repeat;
+};
+
+static bool nv_cksum(const uint8_t *data, unsigned int length)
+{
+       /*
+        * There's a few checksums in the BIOS, so here's a generic checking
+        * function.
+        */
+       int i;
+       uint8_t sum = 0;
+
+       for (i = 0; i < length; i++)
+               sum += data[i];
+
+       if (sum)
+               return true;
+
+       return false;
+}
+
+static int
+score_vbios(struct drm_device *dev, const uint8_t *data, const bool writeable)
+{
+       if (!(data[0] == 0x55 && data[1] == 0xAA)) {
+               NV_TRACEWARN(dev, "... BIOS signature not found\n");
+               return 0;
+       }
+
+       if (nv_cksum(data, data[2] * 512)) {
+               NV_TRACEWARN(dev, "... BIOS checksum invalid\n");
+               /* if a ro image is somewhat bad, it's probably all rubbish */
+               return writeable ? 2 : 1;
+       } else
+               NV_TRACE(dev, "... appears to be valid\n");
+
+       return 3;
+}
+
+static void load_vbios_prom(struct drm_device *dev, uint8_t *data)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t pci_nv_20, save_pci_nv_20;
+       int pcir_ptr;
+       int i;
+
+       if (dev_priv->card_type >= NV_50)
+               pci_nv_20 = 0x88050;
+       else
+               pci_nv_20 = NV_PBUS_PCI_NV_20;
+
+       /* enable ROM access */
+       save_pci_nv_20 = nvReadMC(dev, pci_nv_20);
+       nvWriteMC(dev, pci_nv_20,
+                 save_pci_nv_20 & ~NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
+
+       /* bail if no rom signature */
+       if (nv_rd08(dev, NV_PROM_OFFSET) != 0x55 ||
+           nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa)
+               goto out;
+
+       /* additional check (see note below) - read PCI record header */
+       pcir_ptr = nv_rd08(dev, NV_PROM_OFFSET + 0x18) |
+                  nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8;
+       if (nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr) != 'P' ||
+           nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 1) != 'C' ||
+           nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 2) != 'I' ||
+           nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 3) != 'R')
+               goto out;
+
+       /* on some 6600GT/6800LE prom reads are messed up.  nvclock alleges a
+        * a good read may be obtained by waiting or re-reading (cargocult: 5x)
+        * each byte.  we'll hope pramin has something usable instead
+        */
+       for (i = 0; i < NV_PROM_SIZE; i++)
+               data[i] = nv_rd08(dev, NV_PROM_OFFSET + i);
+
+out:
+       /* disable ROM access */
+       nvWriteMC(dev, pci_nv_20,
+                 save_pci_nv_20 | NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
+}
+
+static void load_vbios_pramin(struct drm_device *dev, uint8_t *data)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t old_bar0_pramin = 0;
+       int i;
+
+       if (dev_priv->card_type >= NV_50) {
+               uint32_t vbios_vram = (nv_rd32(dev, 0x619f04) & ~0xff) << 8;
+
+               if (!vbios_vram)
+                       vbios_vram = (nv_rd32(dev, 0x1700) << 16) + 0xf0000;
+
+               old_bar0_pramin = nv_rd32(dev, 0x1700);
+               nv_wr32(dev, 0x1700, vbios_vram >> 16);
+       }
+
+       /* bail if no rom signature */
+       if (nv_rd08(dev, NV_PRAMIN_OFFSET) != 0x55 ||
+           nv_rd08(dev, NV_PRAMIN_OFFSET + 1) != 0xaa)
+               goto out;
+
+       for (i = 0; i < NV_PROM_SIZE; i++)
+               data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i);
+
+out:
+       if (dev_priv->card_type >= NV_50)
+               nv_wr32(dev, 0x1700, old_bar0_pramin);
+}
+
+static void load_vbios_pci(struct drm_device *dev, uint8_t *data)
+{
+       void __iomem *rom = NULL;
+       size_t rom_len;
+       int ret;
+
+       ret = pci_enable_rom(dev->pdev);
+       if (ret)
+               return;
+
+       rom = pci_map_rom(dev->pdev, &rom_len);
+       if (!rom)
+               goto out;
+       memcpy_fromio(data, rom, rom_len);
+       pci_unmap_rom(dev->pdev, rom);
+
+out:
+       pci_disable_rom(dev->pdev);
+}
+
+struct methods {
+       const char desc[8];
+       void (*loadbios)(struct drm_device *, uint8_t *);
+       const bool rw;
+       int score;
+};
+
+static struct methods nv04_methods[] = {
+       { "PROM", load_vbios_prom, false },
+       { "PRAMIN", load_vbios_pramin, true },
+       { "PCIROM", load_vbios_pci, true },
+       { }
+};
+
+static struct methods nv50_methods[] = {
+       { "PRAMIN", load_vbios_pramin, true },
+       { "PROM", load_vbios_prom, false },
+       { "PCIROM", load_vbios_pci, true },
+       { }
+};
+
+static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct methods *methods, *method;
+       int testscore = 3;
+
+       if (nouveau_vbios) {
+               method = nv04_methods;
+               while (method->loadbios) {
+                       if (!strcasecmp(nouveau_vbios, method->desc))
+                               break;
+                       method++;
+               }
+
+               if (method->loadbios) {
+                       NV_INFO(dev, "Attempting to use BIOS image from %s\n",
+                               method->desc);
+
+                       method->loadbios(dev, data);
+                       if (score_vbios(dev, data, method->rw))
+                               return true;
+               }
+
+               NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
+       }
+
+       if (dev_priv->card_type < NV_50)
+               methods = nv04_methods;
+       else
+               methods = nv50_methods;
+
+       method = methods;
+       while (method->loadbios) {
+               NV_TRACE(dev, "Attempting to load BIOS image from %s\n",
+                        method->desc);
+               data[0] = data[1] = 0;  /* avoid reuse of previous image */
+               method->loadbios(dev, data);
+               method->score = score_vbios(dev, data, method->rw);
+               if (method->score == testscore)
+                       return true;
+               method++;
+       }
+
+       while (--testscore > 0) {
+               method = methods;
+               while (method->loadbios) {
+                       if (method->score == testscore) {
+                               NV_TRACE(dev, "Using BIOS image from %s\n",
+                                        method->desc);
+                               method->loadbios(dev, data);
+                               return true;
+                       }
+                       method++;
+               }
+       }
+
+       NV_ERROR(dev, "No valid BIOS image found\n");
+       return false;
+}
+
+struct init_tbl_entry {
+       char *name;
+       uint8_t id;
+       int length;
+       int length_offset;
+       int length_multiplier;
+       bool (*handler)(struct nvbios *, uint16_t, struct init_exec *);
+};
+
+struct bit_entry {
+       uint8_t id[2];
+       uint16_t length;
+       uint16_t offset;
+};
+
+static int parse_init_table(struct nvbios *, unsigned int, struct init_exec *);
+
+#define MACRO_INDEX_SIZE       2
+#define MACRO_SIZE             8
+#define CONDITION_SIZE         12
+#define IO_FLAG_CONDITION_SIZE 9
+#define IO_CONDITION_SIZE      5
+#define MEM_INIT_SIZE          66
+
+static void still_alive(void)
+{
+#if 0
+       sync();
+       msleep(2);
+#endif
+}
+
+static uint32_t
+munge_reg(struct nvbios *bios, uint32_t reg)
+{
+       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
+       struct dcb_entry *dcbent = bios->display.output;
+
+       if (dev_priv->card_type < NV_50)
+               return reg;
+
+       if (reg & 0x40000000) {
+               BUG_ON(!dcbent);
+
+               reg += (ffs(dcbent->or) - 1) * 0x800;
+               if ((reg & 0x20000000) && !(dcbent->sorconf.link & 1))
+                       reg += 0x00000080;
+       }
+
+       reg &= ~0x60000000;
+       return reg;
+}
+
+static int
+valid_reg(struct nvbios *bios, uint32_t reg)
+{
+       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
+       struct drm_device *dev = bios->dev;
+
+       /* C51 has misaligned regs on purpose. Marvellous */
+       if (reg & 0x2 || (reg & 0x1 && dev_priv->VBIOS.pub.chip_version != 0x51)) {
+               NV_ERROR(dev, "========== misaligned reg 0x%08X ==========\n",
+                        reg);
+               return 0;
+       }
+       /*
+        * Warn on C51 regs that have not been verified accessible in
+        * mmiotracing
+        */
+       if (reg & 0x1 && dev_priv->VBIOS.pub.chip_version == 0x51 &&
+           reg != 0x130d && reg != 0x1311 && reg != 0x60081d)
+               NV_WARN(dev, "=== C51 misaligned reg 0x%08X not verified ===\n",
+                       reg);
+
+       /* Trust the init scripts on G80 */
+       if (dev_priv->card_type >= NV_50)
+               return 1;
+
+       #define WITHIN(x, y, z) ((x >= y) && (x < y + z))
+       if (WITHIN(reg, NV_PMC_OFFSET, NV_PMC_SIZE))
+               return 1;
+       if (WITHIN(reg, NV_PBUS_OFFSET, NV_PBUS_SIZE))
+               return 1;
+       if (WITHIN(reg, NV_PFIFO_OFFSET, NV_PFIFO_SIZE))
+               return 1;
+       if (dev_priv->VBIOS.pub.chip_version >= 0x30 &&
+           (WITHIN(reg, 0x4000, 0x600) || reg == 0x00004600))
+               return 1;
+       if (dev_priv->VBI